supersnake

c#.net

导航

Supersnake.Tools.PasswordManager

Posted on 2005-04-12 09:45  supersnake  阅读(558)  评论(0编辑  收藏  举报
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;
        }


    }

}