|
现在加密技术很多,比如SHA,MD5(已经被破解了),小可想和大家讨论一下在.NET框架中简单应用SHA算法加密用户登录密码的方法。 这里我采用的是SHA1(安全散列算法),是将不定长的字符串转换成160位(20字节)字节流散列算法。 这里讲的加密一般分以下几个步骤:
密码的建立: 1)对用户的原始密码进行第一次哈希,得到UnsaltedPassword: User password ====hash====> UnsaltedPassword (20B) 2)随机产生一个N字节的密钥值(salt value),拼接到上面哈希后的字节流后面即 UnsaltedPassword(20B) | Salt value(NB) 3)将以上(20 + N)Byte的字节流再经过一次哈希,得到SaltedPassword UnsaltedPassword(20B) | Salt value(NB) ====hash====> SaltedPassword 4)将SaltedPassword(20B) | Salt value(NB)存入数据库
密码的验证: 1)从数据库中获得加密后用户密码 dbPassword,取其最后N字节作为Salt value 2)重复上面1) 3) 4)将用户输入的密码结合Salt value进行哈希加密,和dbPassword进行比较以确定用户输入密码是否正确
private void btnLogon_Click(object sender, EventArgs e)
  {
//创建SHA1类的实例,SHA1是抽象类(abstract)所以不能直接实例化
SHA1 sha1 = SHA1.Create();
//Unicode.GetBytes获得string的Unicode(双字节字符)字节流
byte[] hashedPassword = sha1.ComputeHash(Encoding.Unicode.GetBytes(txtPassword.Text));
//UserDate 可以理解为用户信息的抽象
UserData user = userSystem.GetByName(txtUsername.Text, hashedPassword);
if (user == null)
 {
//登录失败处理
}
}

public UserData GetByName(string userName, byte[] password)
  {
UserData userData;
using (Users usersDataAccess = new Users())
 {
userData = usersDataAccess.LoadUserByUserName(userName);
}
byte[] dbPassword = UserData.UserPassword;

if (ComparePasswords(dbPassword, password))
return userData;
else
return null;
}


// 比较密码
private bool ComparePasswords(byte[] storedPassword, byte[] hashedPassword)
  {
if (storedPassword == null || hashedPassword == null || hashedPassword.Length != storedPassword.Length - saltLength)
return false;
// 获得存储的密钥值
byte[] saltValue = new byte[saltLength];
int saltOffset = storedPassword.Length - saltLength;
for (int i = 0; i < saltLength; i++)
saltValue[i] = storedPassword[saltOffset + i];
byte[] saltedPassword = CreateSaltedPassword(saltValue, hashedPassword);

// 比较存贮的密码序列和计算后的密码序列
return CompareByteArray(storedPassword, saltedPassword);
}

private byte[] CreateSaltedPassword(byte[] saltValue, byte[] unsaltedPassword)
  {
// 在哈希值末尾添加密钥
byte[] rawSalted = new byte[unsaltedPassword.Length + saltValue.Length];
unsaltedPassword.CopyTo(rawSalted, 0);
saltValue.CopyTo(rawSalted, unsaltedPassword.Length);

// 计算哈希值
SHA1 sha1 = SHA1.Create();
byte[] saltedPassword = sha1.ComputeHash(rawSalted);

// 在哈希值末尾添加密钥
byte[] dbPassword = new byte[saltedPassword.Length + saltValue.Length];
saltedPassword.CopyTo(dbPassword, 0);
saltValue.CopyTo(dbPassword, saltedPassword.Length);

return dbPassword;
}

// 比较两个 byte 数组的内容
private 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;
}


// 创建在数据库中存储的的哈希值(转入参数为经过一次哈希的用户输入密码的字节流)
public byte[] CreateDbPassword(byte[] unsaltedPassword)
  {
//Create a salt value
byte[] saltValue = new byte[saltLength];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(saltValue);

return CreateSaltedPassword(saltValue, unsaltedPassword);
}
不知道为什么弄的这么复杂
c#程序中对密码进行加密的方法
在ADO.NET中,向数据库添加数据时,怎样对数据中的密码进行加密?(也就是说在数据表中也看不到用户的密
码,只是一些经过编译后的字符串,以防止数据库管理员利用用户的密码进行非法操作。) 首先,在c#WinForm程序中引入命名空间,"using System.Web.Security;",此命名空间是专门用来对程序进
行安全设置的; 其次,定义一个string类型的变量,用来接收用输入的密码; string passWord = this.textBox1.Text.Trim(); 取到密码之后,接下来便是对密码进行加密处理: string pwd = FormsAuthentication.HashPasswordForStoringInConfigFile(pwd, "md5"); 最后,将加密后的密码pwd添加到数据库中去。 insert into userInfo(uName,pwd) values('{0}','{1}');select @@identity", this.txtUID.Text.Trim
(),passwrod); 示例代码: using System.Web.Security;
//取得文本框中的密码 string pwd = this.txtPwd1.Text.Trim(); //对密码加密 string passwrod = FormsAuthentication.HashPasswordForStoringInConfigFile(pwd, "md5");
这个在winform里面不好用 //创建SQL语句,将加密后的密码保存到数据库中 string insCmd = string.Format("insert into userInfo(uName,pwd) values('{0}','{1}');select @@identity",
this.txtUID.Text.Trim(),passwrod); using (SqlCommand cmd = new SqlCommand(insCmd, Form1.Connection)) { int uid = Convert.ToInt32(cmd.ExecuteScalar()); //int uid = int.Parse(cmd.ExecuteScalar());//error if (uid > 0) { string mess = string.Format("恭喜,注册成功!您的号码是{0}",uid); MessageBox.Show(mess); } else { MessageBox.Show("对不起,注册失败了!"); } }
这样加密之后保证了用户密码的安全,但是又出现了一个问题,即用户登录时怎样对密码进行验证,该不会让
用户去记住加密后的那一长串字符串吧? 答案当然是否定的,那怎样解决呢? 应该这样解决: 在用户登录时,得到用户输入的密码; 然后,将取到的密码再次进行加密; 之后,根据用户名取出该用户在数据库中的真实密码; 最后,将刚刚进行加密的密码与数据库密码进行比对,即可完成用户登录操作。 示例代码: string pwd = this.txtPwd1.Text.Trim(); string pwd1 = FormsAuthentication.HashPasswordForStoringInConfigFile(pwd, "md5"); string uid = this.txtUID.Text.Trim(); string selCmd = string.Format("select pwd from userINfo where uName='{0}'", uid); string password = ""; using (SqlCommand cmd = new SqlCommand(selCmd, Form1.Connection)) { password= cmd.ExecuteScalar().ToString(); } if (password == pwd1) { MessageBox.Show("登录成功"); } else { MessageBox.Show("密码错误!"); }
1)使用 SHA1 生成散列
通过如下的示例代码,来演示如何通过SHA1生成散列:
byte [] bytePassword = null;
string tmpPassword = txtPassword.Text.Trim();
// 创建新的加密服务提供程序对象
SHA1 sha1 = SHA1.Create();
// 将原始字符串转换成字节数组,然后计算散列,并返回一个字节数组
bytePassword = sha1.ComputeHash(Encoding.Unicode.GetBytes(tmpPassword));
// Releases all resources used by the System.Security.Cryptography.HashAlgorithm.
sha1.Clear();
// 返回散列值的 Base64 编码字符串
txtResults.Text = Convert.ToBase64String(bytePassword);
传递不同的字符串值来调用该例程,查看散列值的变化。例如,如果将字符串Rickie传递给该例程,输出结果:
v8ocXHBvlh4EqY/2HsJNH5XBVG0=
现在,将此过程中的输入值更改为Ricky。你将看到以下输出结果:
luQsSa61sB/7PT9piDx+OAGqCnI=
如此可见,输入字符串的一个小小变化就会产生完全不同的字符组合。这正是散列算法之所以有效的原因,它使我们很难找到输入字符串的规律,也很难根据加密后的字符弄清楚字符串原来的模样。
2)使用MD5也可以生成散列
通过如下的示例代码,来演示如何通过MD5生成散列:
byte [] bytePassword = null;
string tmpPassword = txtPassword.Text.Trim();
MD5 md5 = MD5.Create();
bytePassword = md5.ComputeHash(Encoding.Unicode.GetBytes(tmpPassword));
// Releases all resources used by the System.Security.Cryptography.HashAlgorithm.
md5.Clear();
txtResults.Text = Convert.ToBase64String(bytePassword);
输入Rickie,MD5散列算法的输出结果:
YUqR1JfNxrciyG0ixNj58A==
同样,加密后的字符串看起来也与原始输入相去甚远。这些散列算法对于创建没有任何意义的密码来说非常有用,也使黑客很难猜出这些密码。之所以使用散列算法,是因为可以用这种算法对密码进行加密并将其存储在数据库中。然后,当用户输入真实密码时,需要先对用户输入的密码进行同样的散列,然后通过网络发送到数据库中,比较它与数据库中的密码是否匹配。
请记住,散列是单向操作。使用散列算法对原始密码加密后将无法再恢复。
上述两种散列算法都执行同一种操作。不同之处只在于生成散列的密钥大小以及使用的算法。使用的密钥越大,加密就越安全。例如,MD5 使用的加密密钥比 SHA1 使用的密钥大,因此 MD5 散列较难破解。
对于散列算法要考虑的另外一点是,从实践或理论的角度上看是否存在冲突的可能性。冲突是我们所不希望的,因为两个不同的单词可能会生成相同的散列。例如,SHA1 从实践或理论上来讲没有发生冲突的可能性。MD5 从理论上讲有发生冲突的可能性,但从实践上讲没有发生冲突的可能性。因此,选择哪种算法归根结底取决于所需要的安全级别 [C语言系列]C# 过滤html,js,css代码 正则表达式 [C语言系列]C# DataGridView显示行号的两种方法 [C语言系列]C# WinForm 中Label自动换行 解决方法 [C语言系列]C# 线程调用主线程中的控件 [电脑应用]c# winform 打包部署 自定义界面 或设置开机启动 [C语言系列]C# 和 Linux 时间戳转换 [C语言系列]C#实现 WebBrowser中新窗口打开链接用默认或者指定… [C语言系列]C#全角和半角转换 [C语言系列]c#WebBrowser查找并选择文本 [C语言系列]C#中实现WebBrowser控件的HTML源代码读写
|