本文转自:http://www.cnblogs.com/CnBlogFounder/archive/2008/07/04/1235690.html

大家对密码执行散列和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 命名空间(它实现 60 位 SHA- 标准)对密码进行散列运算。有关更多信息,请参见 SHA 成员。
/// 对散列执行 Salt 运算
/// 虽然对密码执行散列运算的一个好的开端,但若要增加免受潜在攻击的安全性,则可以对密码散列执行 Salt 运算。Salt 就是在已执行散列运算的密码中插入的一个随机数字。这一策略有助于阻止潜在的攻击者利用预先计算的字典攻击。字典攻击是攻击者使用密钥的所有可能组合来破解密码的攻击。当您使用 Salt 值使散列运算进一步随机化后,攻击者将需要为每个 Salt 值创建一个字典,这将使攻击变得非常复杂巧本极高。
/// Salt 值随散列存储在一起,并且未经过加密。所存储的 Salt 值可以在随后用于密码验证。
/// </summary>
public class Credentials
{
private static string key = "!8%0d-F=cj>,s&"; //密钥(增加密码复杂度,好像比较多余)
private const int saltLength = ; //定义salt值的长度 /// <summary>
/// 对密码进行Hash 和 Salt
/// </summary>
/// <param name="Password">用户输入的密码</param>
/// <returns></returns>
public static byte[] HashAndSalt(string Password)
{
return CreateDbPassword(HashPassword(Password));
} /// <summary>
/// 对用户输入的密码加上密钥key后进行SHA散列
/// </summary>
/// <param name="Password">用户输入的密码</param>
/// <returns>返回 60 位 SHA- 散列后的的byte[](60位对应0个字节)</returns>
private static byte[] HashPassword( string Password )
{
//创建SHA的对象实例sha
SHA sha = SHA.Create();
//计算输入数据的哈希值
return sha.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 值,数据库中的密码的后个字节为salt 值
byte[] saltValue = new byte[saltLength];
int saltOffset = storedPassword.Length - saltLength;
for (int i = ; 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="array"></param>
/// <param name="array"></param>
/// <returns>true:相等/false:不等</returns>
private static bool CompareByteArray(byte[] array, byte[] array)
{
if (array.Length != array.Length)
{
return false;
}
for (int i = ; i < array.Length; i++)
{
if (array[i] != array[i])
{
return false;
}
}
return true;
} /// <summary>
/// 对要存储的密码进行salt运算
/// </summary>
/// <param name="unsaltedPassword">没有进行过salt运算的hash散列密码</param>
/// <returns>经过salt的密码(经过salt的密码长度为:0+=,存储密码的字段为Binary())</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,);
saltValue.CopyTo(rawSalted,unsaltedPassword.Length); //将合并后的rawSalted数组再进行SHA散列的到saltedPassword数组(长度为0字节)
SHA sha = SHA.Create();
byte[] saltedPassword = sha.ComputeHash(rawSalted); //将salt值数组在添加到saltedPassword数组后拼接成dbPassword数组(长度为字节)
byte[] dbPassword = new byte[saltedPassword.Length + saltValue.Length];
saltedPassword.CopyTo(dbPassword,);
saltValue.CopyTo(dbPassword,saltedPassword.Length); return dbPassword;
} }
}

[转]c# 对密码执行散列和 salt 运算方法的更多相关文章

  1. js数据结构之hash散列的详细实现方法

    hash散列中需要确定key和value的唯一确定关系. hash散列便于快速的插入删除和修改,不便于查找最大值等其他操作 以下为字符和数字的hash散列: function HashTable () ...

  2. Flask学习记录之使用Werkzeug散列密码

    数据库中直接存放明文密码是很危险的,Werkzeug库中的security能够方便的实现散列密码的计算 security库中 generate_password_hash(password,metho ...

  3. Shiro入门学习之散列算法与凭证配置(六)

    一.散列算法概述 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5.SHA等,一般进行散列时最好提供一个salt(“盐”),什么意思?举个栗子 ...

  4. JDK8;HashMap:再散列解决hash冲突 ,源码分析和分析思路

    JDK8中的HashMap相对JDK7中的HashMap做了些优化. 接下来先通过官方的英文注释探究新HashMap的散列怎么实现 先不给源码,因为直接看源码肯定会晕,那么我们先从简单的概念先讲起   ...

  5. 【数据结构与算法Python版学习笔记】查找与排序——散列、散列函数、区块链

    散列 Hasing 前言 如果数据项之间是按照大小排好序的话,就可以利用二分查找来降低算法复杂度. 现在我们进一步来构造一个新的数据结构, 能使得查找算法的复杂度降到O(1), 这种概念称为" ...

  6. DotNet加密方式解析--散列加密

    没时间扯淡类,赶紧上车吧. 在现代社会中,信息安全对于每一个人都是至关重要的,例如我们的银行账户安全.支付宝和微信账户安全.以及邮箱等等,说到信息安全,那就必须得提到加密技术,至于加密的一些相关概念, ...

  7. .NET加密方式解析--散列加密

    在现代社会中,信息安全对于每一个人都是至关重要的,例如我们的银行账户安全.支付宝和微信账户安全.以及邮箱等等,说到信息安全,那就必须得提到加密技术,至于加密的一些相关概念,在这里就不说了. 这一次将会 ...

  8. Java 散列集笔记

    散列表 散列表(hash table)为每个对象计算一个整数,称为散列码(hash code). 若需要自定义类,就要负责实现这个类的hashCode方法.注意自己实现的hashCode方法应该与eq ...

  9. [No0000132]正确使用密码加盐散列[译]

    如果你是一个 web 开发工程师,可能你已经建立了一个用户账户系统.一个用户账户系统最重要的部分是如何保护密码.用户账户数据库经常被黑,如果你的网站曾经被攻击过,你绝对必须做点什么来保护你的用户的密码 ...

随机推荐

  1. shell输出颜色、printf输出颜色

    1.echo开启彩色输出: -e 开启echo中的转义: \e或者\033来输出Esc颜色: 恢复默认颜色为:\e[0m; 命令格式: echo -e "\e[字背景颜色:文字颜色m字符串\ ...

  2. Ajax_数据格式_JSON

    [JSON] 1.JSON(JavaScript Object Notation)一种简单的数据格式,比xml更轻巧.JSON是JavaScript原生格式,这意味着在JavaScript中处理JSO ...

  3. HDU 4923 (贪心+证明)

    Room and Moor Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of which is ...

  4. HDU 4903 (模拟+贪心)

    Fighting the Landlords Problem Description Fighting the Landlords is a card game which has been a he ...

  5. [bzoj3893][Usaco2014 Dec]Cow Jog_暴力

    Cow Jog bzoj-3893 Usaco-2014 Dec 题目大意:题目链接. 注释:略. 想法: 先按照坐标排序. 我们发现每个牛只会被后面的牛影响. 所以我们考虑逆向枚举. 记录一下i+1 ...

  6. Java 实现代理(Proxy)模式

    类图 /** * 游戏者接口 * @author stone * */ public interface IGamePlayer { // 登录游戏 public void login(String ...

  7. *** + Polipo 配置全局代理(Linux 版本)

    转,原文:http://blog.csdn.net/jon_me/article/details/53525059 我本来是想查这个问题: How to start server and local ...

  8. 第8章 处理ISDN故障

    第8章 处理ISDN故障 一.ISDN基本原理 二.常见ISDN故障 ISDN问题分成3类:配置不当的路由器.物理线缆和ISDN协议.配置不当的交换机. 1.配置不当的路由器 配置不当由于不同原因:t ...

  9. Scope Is the Enemy of Success

     Scope Is the Enemy of Success Dave Quick SCopE REFERS To A pRojECT'S SizE. How much time, effort, ...

  10. Android系统编译时遇到的几个.mk的疑惑。

    在Android4.2的源代码Build/prduct_config.mk里面遇到几个疑惑: # Convert a short name like "sooner" into t ...