using System;
using System.Text;
using System.Security.Cryptography;
/** 密码管理器
* [功能]
* 加密用户密码
* 检测用户密码
* [原理]
* 对密码执行散列运算
* 若要避免以明文形式存储密码,
* 一种常见的安全做法是对密码执行散列运算,
* 对散列执行 Salt 运算
* 增加免受潜在攻击的安全性,
* 则可以对密码散列执行 Salt 运算
* Salt 就是在已执行散列运算的密码中插入的一个随机数字
* 这一策略有助于阻止潜在的攻击者利用预先计算的字典攻击
* 字典攻击是攻击者使用密钥的所有可能组合来破解密码的攻击
* 当您使用 Salt 值使散列运算进一步随机化后
* 攻击者将需要为每个 Salt 值创建一个字典
* 这将使攻击变得非常复杂且成本极高
*/
namespace Supersnake.Tools
{
/// <summary>
/// PasswordChecker 的摘要说明。
/// 加密和检测用户密码
/// </summary>
public class PasswordManager
{
public PasswordManager()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
/// <summary>
/// 对密码进行 hash 和 salt 运算
/// </summary>
/// <param name="originalPassword">
/// 原始密码
/// </param>
/// <returns>
/// hash 和 salt 后的密码
/// </returns>
public static byte[] CreatePassword(string originalPassword)
{
// 生成 salt 值
byte[] saltvalue = new byte[_saltlen];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(saltvalue);
return createSaltedPassword(createHashedPassword(originalPassword),saltvalue);
}
/// <summary>
/// 比较用户密码和 加密密码是否相同
/// </summary>
/// <param name="originalPassword">原始密码</param>
/// <param name="cryptogramPassword">hash和salt后的密码</param>
/// <returns>真: 相同, 假: 不相同</returns>
public static bool Compare(string originalPassword, byte[] cryptogramPassword)
{
if(originalPassword==null || cryptogramPassword==null)
return false;
// 获利 salt 值
byte[] saltvalue = new byte[_saltlen];
int offset = cryptogramPassword.Length - _saltlen;
for(int i = 0; i<_saltlen; i++)
{
saltvalue[i] = cryptogramPassword[offset+i];
}
byte[] pwd = createSaltedPassword(createHashedPassword(originalPassword),saltvalue);
return compareByteArray(pwd,cryptogramPassword);
}
// 生成hash后的密码
private static string _hashkey = "$<supersnake>$";
private static byte[] createHashedPassword(string originalPassword)
{
SHA1 sha1 = SHA1.Create();
return sha1.ComputeHash(Encoding.Unicode.GetBytes(originalPassword + _hashkey));
}
// 生成salt后的密码
private const int _saltlen = 4;
private static byte[] createSaltedPassword(byte[] unsaltedPassword, byte[] saltvalue)
{
// 拼接两个字节数组
byte[] arr = new byte[unsaltedPassword.Length+saltvalue.Length];
unsaltedPassword.CopyTo(arr,0);
saltvalue.CopyTo(arr,unsaltedPassword.Length);
// 再 hash (20 bytes)
SHA1 sha1 = SHA1.Create();
byte[] arrhash = sha1.ComputeHash(arr);
// 再接上 saltvalue (24 bytes)
byte[] saltedPassword = new byte[arrhash.Length + saltvalue.Length];
arrhash.CopyTo(saltedPassword,0);
saltvalue.CopyTo(saltedPassword,arrhash.Length);
return saltedPassword;
}
// 比较两上 byte array 是否相等
private static bool compareByteArray(byte[] arr1, byte[] arr2)
{
if(arr1.Length != arr2.Length)return false;
for(int i = 0; i < arr1.Length; i++)
{
if(arr1[i] != arr2[i])return false;
}
return true;
}
}
}
using System.Text;
using System.Security.Cryptography;
/** 密码管理器
* [功能]
* 加密用户密码
* 检测用户密码
* [原理]
* 对密码执行散列运算
* 若要避免以明文形式存储密码,
* 一种常见的安全做法是对密码执行散列运算,
* 对散列执行 Salt 运算
* 增加免受潜在攻击的安全性,
* 则可以对密码散列执行 Salt 运算
* Salt 就是在已执行散列运算的密码中插入的一个随机数字
* 这一策略有助于阻止潜在的攻击者利用预先计算的字典攻击
* 字典攻击是攻击者使用密钥的所有可能组合来破解密码的攻击
* 当您使用 Salt 值使散列运算进一步随机化后
* 攻击者将需要为每个 Salt 值创建一个字典
* 这将使攻击变得非常复杂且成本极高
*/
namespace Supersnake.Tools
{
/// <summary>
/// PasswordChecker 的摘要说明。
/// 加密和检测用户密码
/// </summary>
public class PasswordManager
{
public PasswordManager()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
/// <summary>
/// 对密码进行 hash 和 salt 运算
/// </summary>
/// <param name="originalPassword">
/// 原始密码
/// </param>
/// <returns>
/// hash 和 salt 后的密码
/// </returns>
public static byte[] CreatePassword(string originalPassword)
{
// 生成 salt 值
byte[] saltvalue = new byte[_saltlen];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(saltvalue);
return createSaltedPassword(createHashedPassword(originalPassword),saltvalue);
}
/// <summary>
/// 比较用户密码和 加密密码是否相同
/// </summary>
/// <param name="originalPassword">原始密码</param>
/// <param name="cryptogramPassword">hash和salt后的密码</param>
/// <returns>真: 相同, 假: 不相同</returns>
public static bool Compare(string originalPassword, byte[] cryptogramPassword)
{
if(originalPassword==null || cryptogramPassword==null)
return false;
// 获利 salt 值
byte[] saltvalue = new byte[_saltlen];
int offset = cryptogramPassword.Length - _saltlen;
for(int i = 0; i<_saltlen; i++)
{
saltvalue[i] = cryptogramPassword[offset+i];
}
byte[] pwd = createSaltedPassword(createHashedPassword(originalPassword),saltvalue);
return compareByteArray(pwd,cryptogramPassword);
}
// 生成hash后的密码
private static string _hashkey = "$<supersnake>$";
private static byte[] createHashedPassword(string originalPassword)
{
SHA1 sha1 = SHA1.Create();
return sha1.ComputeHash(Encoding.Unicode.GetBytes(originalPassword + _hashkey));
}
// 生成salt后的密码
private const int _saltlen = 4;
private static byte[] createSaltedPassword(byte[] unsaltedPassword, byte[] saltvalue)
{
// 拼接两个字节数组
byte[] arr = new byte[unsaltedPassword.Length+saltvalue.Length];
unsaltedPassword.CopyTo(arr,0);
saltvalue.CopyTo(arr,unsaltedPassword.Length);
// 再 hash (20 bytes)
SHA1 sha1 = SHA1.Create();
byte[] arrhash = sha1.ComputeHash(arr);
// 再接上 saltvalue (24 bytes)
byte[] saltedPassword = new byte[arrhash.Length + saltvalue.Length];
arrhash.CopyTo(saltedPassword,0);
saltvalue.CopyTo(saltedPassword,arrhash.Length);
return saltedPassword;
}
// 比较两上 byte array 是否相等
private static bool compareByteArray(byte[] arr1, byte[] arr2)
{
if(arr1.Length != arr2.Length)return false;
for(int i = 0; i < arr1.Length; i++)
{
if(arr1[i] != arr2[i])return false;
}
return true;
}
}
}