分享
 
 
 

详解对密码执行散列和 salt 运算方法

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

大家对密码执行散列和Salt运算一定不陌生。两个Visual Studio企业版示例都是用的这个方法来加密这个方法的。结合示例代码,我总结了一个包含对密码进行加密,比较等静态方法的类。

使用说明:先用HashAndSalt方法对密码进行加密,然后存储到数据库中。 在用户登录时用ComparePasswords方法在对用户输入的密码和用户注册时存储在数据库中的密码进行比较,判断用户输入的密码是否正确。

Credentials.cs

using System;

using System.IO;

using System.Text;

using System.Security.Cryptography;

namespace BookStore.Common

{

/// <summary>

/// Credentials 的摘要说明。

/// 原理:

/// 对密码执行散列运算

/// 若要避免以明文形式存储密码,一种常见的安全做法是对密码执行散列运算。如以下代码所示,使用 System.Security.Cryptography 命名空间(它实现 160 位 SHA-1 标准)对密码进行散列运算。有关更多信息,请参见 SHA1 成员。

/// 对散列执行 Salt 运算

/// 虽然对密码执行散列运算的一个好的开端,但若要增加免受潜在攻击的安全性,则可以对密码散列执行 Salt 运算。Salt 就是在已执行散列运算的密码中插入的一个随机数字。这一策略有助于阻止潜在的攻击者利用预先计算的字典攻击。字典攻击是攻击者使用密钥的所有可能组合来破解密码的攻击。当您使用 Salt 值使散列运算进一步随机化后,攻击者将需要为每个 Salt 值创建一个字典,这将使攻击变得非常复杂且成本极高。

/// Salt 值随散列存储在一起,并且未经过加密。所存储的 Salt 值可以在随后用于密码验证。

/// </summary>

public class Credentials

{

private static string key = "!48%0d-F=cj>,s&2"; //密钥(增加密码复杂度,好像比较多余)

private const int saltLength = 4; //定义salt值的长度

/// <summary>

/// 对密码进行Hash 和 Salt

/// </summary>

/// <param name="Password">用户输入的密码</param>

/// <returns></returns>

public static byte[] HashAndSalt(string Password)

{

return CreateDbPassword(HashPassword(Password));

}

/// <summary>

/// 对用户输入的密码加上密钥key后进行SHA1散列

/// </summary>

/// <param name="Password">用户输入的密码</param>

/// <returns>返回 160 位 SHA-1 散列后的的byte[](160位对应20个字节)</returns>

private static byte[] HashPassword( string Password )

{

//创建SHA1的对象实例sha1

SHA1 sha1 = SHA1.Create();

//计算输入数据的哈希值

return sha1.ComputeHash( Encoding.Unicode.GetBytes( Password + key ) );

}

/// <summary>

/// 比较数据库中的密码和所输入的密码是否相同

/// </summary>

/// <param name="storedPassword">数据库中的密码</param>

/// <param name="Password">用户输入的密码</param>

/// <returns>true:相等/false:不等</returns>

public static bool ComparePasswords(byte[] storedPassword, string Password)

{

//首先将用户输入的密码进行Hash散列

byte[] hashedPassword = HashPassword(Password);

if (storedPassword == null || hashedPassword == null || hashedPassword.Length != storedPassword.Length - saltLength)

{

return false;

}

//获取数据库中的密码的salt 值,数据库中的密码的后4个字节为salt 值

byte[] saltValue = new byte[saltLength];

int saltOffset = storedPassword.Length - saltLength;

for (int i = 0; i < saltLength; i++){

saltValue[i] = storedPassword[saltOffset + i];

}

//用户输入的密码用户输入的密码加上salt 值,进行salt

byte[] saltedPassword = CreateSaltedPassword(saltValue, hashedPassword);

//比较数据库中的密码和经过salt的用户输入密码是否相等

return CompareByteArray(storedPassword, saltedPassword);

}

/// <summary>

/// 比较两个ByteArray,看是否相等

/// </summary>

/// <param name="array1"></param>

/// <param name="array2"></param>

/// <returns>true:相等/false:不等</returns>

private static bool CompareByteArray(byte[] array1, byte[] array2)

{

if (array1.Length != array2.Length)

{

return false;

}

for (int i = 0; i < array1.Length; i++)

{

if (array1[i] != array2[i])

{

return false;

}

}

return true;

}

/// <summary>

/// 对要存储的密码进行salt运算

/// </summary>

/// <param name="unsaltedPassword">没有进行过salt运算的hash散列密码</param>

/// <returns>经过salt的密码(经过salt的密码长度为:20+4=24,存储密码的字段为Binary(24))</returns>

private static byte[] CreateDbPassword(byte[] unsaltedPassword)

{

//获得 salt 值

byte[] saltValue = new byte[saltLength];

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

rng.GetBytes(saltValue);

return CreateSaltedPassword(saltValue, unsaltedPassword);

}

/// <summary>

/// 创建一个经过salt的密码

/// </summary>

/// <param name="saltValue">salt 值</param>

/// <param name="unsaltedPassword">没有进行过salt运算的hash散列密码</param>

/// <returns>经过salt的密码</returns>

private static byte[] CreateSaltedPassword(byte[] saltValue, byte[] unsaltedPassword)

{

//将salt值数组添加到hash散列数组后拼接成rawSalted数组中

byte[] rawSalted = new byte[unsaltedPassword.Length + saltValue.Length];

unsaltedPassword.CopyTo(rawSalted,0);

saltValue.CopyTo(rawSalted,unsaltedPassword.Length);

//将合并后的rawSalted数组再进行SHA1散列的到saltedPassword数组(长度为20字节)

SHA1 sha1 = SHA1.Create();

byte[] saltedPassword = sha1.ComputeHash(rawSalted);

//将salt值数组在添加到saltedPassword数组后拼接成dbPassword数组(长度为24字节)

byte[] dbPassword = new byte[saltedPassword.Length + saltValue.Length];

saltedPassword.CopyTo(dbPassword,0);

saltValue.CopyTo(dbPassword,saltedPassword.Length);

return dbPassword;

}

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有