本文转自: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. IOC控制反转之Autofac

    https://www.jianshu.com/p/1b6cb076e2e5 博主:衡泽_徐峰 Autofac官网:https://autofac.org/ Autofac 是.Net非常好的一个IO ...

  2. 【Codeforces 348A】Mafia

    [链接] 我是链接,点我呀:) [题意] 每轮游戏都要有一个人当裁判,其余n-1个人当玩家 给出每个人想当玩家的次数ai 请你求出所需要最少的玩游戏的轮数 使得每个人都能满足他们当玩家的要求. [题解 ...

  3. poj 3164 最小树形图模板!!!

    /* tle十几次,最后发现当i从1开始时,给环赋值时要注意啊! 最小树形图 */ #include<stdio.h> #include<string.h> #include& ...

  4. hdu 1853 KM算法

    #include<stdio.h> #include<math.h> #include<string.h> #define N 200 #define inf 99 ...

  5. jsp内置对象(转)

    JSP中一共预先定义了9个这样的对象,分别为:request.response.session.application.out.pagecontext.config.page.exception 1. ...

  6. 0213微信ZABBIX报警

    简介 微信作为日常使用最频繁的工具,因此希望将微信接入zabbix报警. 微信企业号 1.申请微信企业号 申请后,请在“我的企业”页面下记录企业号的CorpID 2.添加通讯录 部门添加完成后,根据实 ...

  7. Linux进程空间分布 & 上下文

    Linux使用两级保护机制:0级供内核使用,3级供用户程序使用.从图中可以看出,每个进程有各自的私有用户空间(0~3G),这个空间对系统中的其他进程是不可见的.最高的1GB字节虚拟内核空间则为所有进程 ...

  8. Windows 由于无法验证发布者,windows阻止控件安装怎么办

    1 打开Internet选项   2 下载未签名的ACTIVEX控件-设为启动    

  9. Android:使用SparseArray取代HashMap优化性能

    之前看到一篇关于adapter的文章用到了SparseArray,所以在这里写写关于SparseArray的使用方法. SparseArray是官方针对安卓所写的容器,与HashMap类似,只是性能比 ...

  10. leetCode(49):Count Primes

    Description: Count the number of prime numbers less than a non-negative number, n. 推断一个数是否是质数主要有下面几种 ...