标题:关于大家关注的HASH加密算法
只看楼主
天使不哭
Rank: 6Rank: 6
等 级:贵宾
威 望:23
帖 子:677
专家分:22
注 册:2006-7-9
结帖率:100%
 问题点数:0 回复次数:11 
关于大家关注的HASH加密算法

HASH,一对多的加密算法
看看现在的论坛,99%的都有对密码加密,而且有很多采用的是md5方法。在早期,有人说md5加密方法是最安全的,因为它不能解密,这是确实的,但是有没有方法比md5方法更加具有安全性呢?当然有,今天我就要介绍一种另外的加密方式:hash方法。

传统的md5方法就是几个函数的组合,最终调用这句话就实现加密了:md5(encodestr),其中的encodestr与md5(encodestr)是一一对应的,也就是说一个encodestr对应一个md5(encodestr)。而hash方法却不是一一对应的关系,而是一对多的关系。之所以是一对多的关系,就是因为加密方法与md5不同。

让我们看一个例子:
当我们用md5方法加密"111"这个字符串时,我们调用的语句是:
md5("111")
结果是:
698d51a19d8a121ce581499d7b701668
但是我们用hash方法加密"111"这个字符串时,我们调用的语句却是:
hashencode(getsalt(len("111")) & "111")
结果是:
6FCD9AA863A4934929684D092C1EF0364687A1DE,
97E8F16623A0AF64B48FF1CEF6558C8E1D12C94E,
F77F2148F82C342A7971F25D7BA3760AE71AB9BA,
.
.
.
因此,hash方法是一对多的。

在hash方法中,我们先对要加密的字符串的长度执行一个getsalt函数,它的具体作用就是根据要加密字符串的长度生成一个随机的salt值,这个salt值的长度与要加密的字符串的长度是相等的,比如我们调用如下函数:
getsalt(len("111"))
结果是:
4CD
9B7
9A6
.
.
然后我们再将这个salt值与要加密的字符串结合并且用hashencode函数执行,因此,加密后的字符串是任意的,比如我们要将"111"这个字符串加密,实际上我们是在加密4CD111,9B7111,9A6111...........因此hash方法是一对多的关系。那么怎么才能让hash方法向md5一样一对一呢?很简单,比如用户在论坛中注册时,我们要对他的密码进行加密,当用户提交表单后,我们可以将随机生成的salt值
getsalt(len(encodestr))

hashencode(getsalt(len(endodestr)) & encodestr)
值都存入数据库中,当我们验证用户时,我们可以先从数据库中把salt值读出来,然后与用户登陆时提交的密码结合执行hashencode函数,如果执行结果与数据库中的值相同,则通过验证,否则不通过。

这就是hash方法,不知道大家看懂了没有。

简单的说,单从md5函数和hashencode函数来说,除了加密算法不一样,其他都是一样的,都是单向加密,不能解密。但是hash方法并不是像md5方法那样直接加密字符串,而是先对字符串进行一些处理,然后再加密。这个先做的处理就是根据要加密字符串的长度生成一个随机salt值,然后用这个salt值与要加密的字符串一同进行加密,并且把salt值与一同加密后的值都存入数据库中;在验证上,md5方法是将用户提交的字符先进行md5加密,然后与数据库中加密后的字符相比,如果相同则通过验证,否则不通过验证。而hash方法则是先从数据库中读取salt值,然后用salt值与用户提交的字符相结合进行hash加密,再与数据库中的加密后字符比较,相同则通过,否则不通过。

其实如果我们说md5是一次加密里最具有安全性的,那么我们可以说hash方法是对一次加密的又一次加密,也就是说是二次加密。因此从理论上来说比md5方法更加安全。

我的这篇文章的目的是向大家介绍一种新的加密方法,我只是从加密的基本原理上分析了hash方法不同于md5方法的地方,而没有从函数的编写以及内部编程思路上说,因此可能有些片面。毕竟大多数朋友还都是程序的使用者,而不是高级编写者。

搜索更多相关主题的帖子: HASH 算法 
2007-05-23 14:19
天使不哭
Rank: 6Rank: 6
等 级:贵宾
威 望:23
帖 子:677
专家分:22
注 册:2006-7-9
得分:0 

1 .Net Framework1.1中常见加密算法
加密类(可以从密文中还原出原始信息)

DES,TripleDES,RC2,RC4,Rijndael(AES)

消息摘要类(不能从消息摘要中还原出原始信息,只能用于数据校验)

MD5,SHA1,SHA256,SHA384,SHA512

2 加密知识简介
如果以密钥为标准,可将密码系统分为单钥密码(又称为对称密码或私钥密码)体系和双钥密码(又称为非对称密码或公钥密码)体系。所谓密钥差不多可以理解成密码。

在单钥体制下,加密密钥和解密密钥是一样的,如果加密密钥丢失,信息也就失去了保密性。而在双钥体制下,加密密钥与解密密钥是不同的,此时根本就不需要安全信道来传送密钥,而只需利用本地密钥发生器产生解密密钥即可。

双钥密码是1976年W.Diffie和M.E.Heilinan提出的一种新型密码体制。由于双钥密码体制的加密和解密不同,且能公开加密密钥,而仅需保密解密密钥,所以双钥密码不存在密钥管理问题。双钥密码还有一个优点是可以拥有数字签名等新功能。最有名的双钥密码体系是1977年由Rivest,Shamir和Ad1eman人提出的RSA密码体制。双钥密码的缺点是:双钥密码算法一般比较复杂,加解密速度慢。

因此,网络中的加密普遍采用双钥和单钥密码相结合的混合加密体制,即加解密时采用单钥密码,密钥传送则采用双钥密码。这样既解决了密钥管理的困难,又解决了加解密速度的问题。目前看来,这种方法好象也只能这样了。你可以在下面的连接中找到一些密码学的基础知识。

http://www.chinaitpower.com/A/2002-01-02/9726.html

http://dev.csdn.net/article/13/13370.shtm

如果你想了解各种算法的介绍和实现细节,可以从下面的链接得到一些信息

DES: http://www.itl.nist.gov/fipspubs/fip46-2.htm

http://www.iusmentis.com/technology/encryption/des/

TripleDES: http://www.zvon.org/tmRFC/RFC3217/Output/chapter1.html

RC2: http://www.zvon.org/tmRFC/RFC2268/Output/index.html

RC4: http://www.wisdom.weizmann.ac.il/~itsik/RC4/rc4.html

AES: http://csrc.nist.gov/encryption/aes/rijndael/rijndael.pdf

http://fp.gladman.plus.com/aes/aes.zip

3 常用对称加密算法简介
DES是最有影响的单钥密码算法,由美国国家标准局在1977年颁布。它的特点是无论加密还是解密都使用同一个密钥,因此,此密码体制的安全性就是密钥的安全。如果密钥泄露,则此密码系统便被攻破。它的优点是:安全性高。加解密速度快。缺点是:1)随着网络规模的扩大,密钥的管理成为一个难点;2)无法解决消息确认问题;3)缺乏自动检测密钥泄露的能力。现在DES算法已经不再安全,用一台20万美元的设备可在56小时之内将56位DES破译(详见:www.eff.org)。

DES是一种古老的算法,现在已经有些过时了;TripleDES也比较古老了,但是现在还是比较安全的;RC2也是一种比较老的算法,但现在还是比较有用;AES是一种较新的算法,现在也非常流行。这几种算法在.Net Framework1.1中已经有了实现,我们只需要调用即可。

RC4算法是在.Net Framework2.0中新增的。它们的基本特点如下面的表所示。

尽管RC4在.Net Framework2.0里面才提供了实现,但是SourceForge上面有了一个C#的实现,你可以用在自己的Web工程里面。你可以参考我前面一篇文章得到RC4的代码。
算法
Key(密钥)
向量
对称加密
.Net Framework
地位

DES
8字节
8字节

1.1
老,过时

TripleDES
16字节或24字节
8字节

1.1
老,有用

RC2
Any
8字节

1.1
老,有用

RC4
Any


2.0
新,有用

AES
16字节,24字节或32字节
16字节

1.1
新,流行

4 常用hash加密算法简介
关于MD5和SHA1等的介绍和实现可以参看本博客中其它的文章,在这儿我只提供一个在.Net Framework中引用实现的例子。


C#Winform技术群:25380362
博客:http:///boyliupan/
2007-05-23 14:25
天使不哭
Rank: 6Rank: 6
等 级:贵宾
威 望:23
帖 子:677
专家分:22
注 册:2006-7-9
得分:0 

5 代码实例:调用常用加密算法的实例


using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;

public class EncryptClass
{
private string mKey = string.Empty;
private ServiceProviderEnum mAlgorithm;
private SymmetricAlgorithm mCryptoService;

private void SetLegalIV()
{
//对称算法的初始化向量
//对于DES, TripleDES, RC2向量的长度为8字节
//对于Rijndael算法,向量长度为16字节
//可以人工输入,也可以随机生成,方法是:des.GenerateIV();
//在这儿为了简单起见,我们使用固定的值,
//也可以按照调整key的办法来调整向量。
switch(mAlgorithm)
{
case ServiceProviderEnum.Rijndael:
mCryptoService.IV = new byte[] {0xf, 0x6f, 0x13, 0x2e, 0x35, 0xc2, 0xcd, 0xf9, 0x5, 0x46, 0x9c, 0xea, 0xa8, 0x4b, 0x73,0xcc};
break;
default:
mCryptoService.IV = new byte[] {0xf, 0x6f, 0x13, 0x2e, 0x35, 0xc2, 0xcd, 0xf9};
break;
}
}

public enum ServiceProviderEnum: int
{
// .Net Framework1.1中支持的对称加密算法
Rijndael,
RC2,
DES,
TripleDES
}

//加密使用的Key
public string Key
{
get
{
return mKey;
}
set
{
mKey = value;
}
}

// 设定缺省的加密算法为Rijndael(AES)
public EncryptClass()
{
mCryptoService = new RijndaelManaged();
mCryptoService.Mode = CipherMode.CBC;
mAlgorithm = ServiceProviderEnum.Rijndael;
}

// 利用ServiceProviderEnum来选择一种加密算法
public EncryptClass(ServiceProviderEnum serviceProvider)
{
switch(serviceProvider)
{
case ServiceProviderEnum.Rijndael:
mCryptoService = new RijndaelManaged();
mAlgorithm = ServiceProviderEnum.Rijndael;
break;
case ServiceProviderEnum.RC2:
mCryptoService = new RC2CryptoServiceProvider();
mAlgorithm = ServiceProviderEnum.RC2;
break;
case ServiceProviderEnum.DES:
mCryptoService = new DESCryptoServiceProvider();
mAlgorithm = ServiceProviderEnum.DES;
break;
case ServiceProviderEnum.TripleDES:
mCryptoService = new TripleDESCryptoServiceProvider();
mAlgorithm = ServiceProviderEnum.TripleDES;
break;
}
mCryptoService.Mode = CipherMode.CBC;
}

//利用算法名来选择加密算法
public EncryptClass(string serviceProviderName)
{
try
{
switch(serviceProviderName.ToLower())
{
case "rijndael":
serviceProviderName = "Rijndael";
mAlgorithm = ServiceProviderEnum.Rijndael;
break;
case "rc2":
serviceProviderName = "RC2";
mAlgorithm = ServiceProviderEnum.RC2;
break;
case "des":
serviceProviderName = "DES";
mAlgorithm = ServiceProviderEnum.DES;
break;
case "tripledes":
serviceProviderName = "TripleDES";
mAlgorithm = ServiceProviderEnum.TripleDES;
break;
}

mCryptoService = (SymmetricAlgorithm)CryptoConfig.CreateFromName(serviceProviderName);
mCryptoService.Mode = CipherMode.CBC;
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}

public byte[] GetLegalKey()
{
//对称算法的机密密钥的长度如下:
//对于DES算法,密钥长度为8字节
//对于TripleDES算法,密钥长度为16或者24字节
//对于Rijndael算法,密钥长度为16,24或者32字节
//可以人工输入,也可以随机生成,方法是:des.GenerateKey();
//对于不符合要求的key,就需要调整其内容
if (mCryptoService.LegalKeySizes.Length > 0)
{
// 用位来表示key的大小
int keySize = mKey.Length * 8;
int minSize = mCryptoService.LegalKeySizes[0].MinSize;
int maxSize = mCryptoService.LegalKeySizes[0].MaxSize;
int skipSize = mCryptoService.LegalKeySizes[0].SkipSize;

if (keySize > maxSize)
{
// 去除多余的部分
mKey = mKey.Substring(0, maxSize / 8);
}
else if (keySize < maxSize)
{
// 设定有效大小
int validSize = (keySize <= minSize)? minSize : (keySize - keySize % skipSize) + skipSize;
if (keySize < validSize)
{
// 使用*来填补不足的部分
mKey = mKey.PadRight(validSize / 8, '*');
}
}
}
PasswordDeriveBytes key = new PasswordDeriveBytes(mKey, ASCIIEncoding.ASCII.GetBytes(string.Empty));
return key.GetBytes(mKey.Length);
}

public string Encrypt(string plainText)
{
byte[] cryptoByte = null;
try
{
byte[] plainByte = System.Text.UTF8Encoding.UTF8.GetBytes(plainText);
byte[] keyByte = GetLegalKey();

// 设定key和向量
mCryptoService.Key = keyByte;
SetLegalIV();
// 加密对象
ICryptoTransform cryptoTransform = mCryptoService.CreateEncryptor();
// 内存流对象
MemoryStream ms = new MemoryStream();
// 初始化加密流
CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write);
// 将加密后的数据写入加密流
cs.Write(plainByte, 0, plainByte.Length);
cs.FlushFinalBlock();
cs.Close();
// 得到加密后的数据
cryptoByte = ms.ToArray();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
// 将数据转换成base64字符串
return Convert.ToBase64String(cryptoByte, 0, cryptoByte.GetLength(0));
}


C#Winform技术群:25380362
博客:http:///boyliupan/
2007-05-23 14:25
天使不哭
Rank: 6Rank: 6
等 级:贵宾
威 望:23
帖 子:677
专家分:22
注 册:2006-7-9
得分:0 

//解密的时候用的key和向量必须和加密的时候用的一样
public string Decrypt(string cryptoText)
{
// 从base64字符串转换成字节
if(cryptoText == null)
return null;

byte[] cryptoByte = Convert.FromBase64String(cryptoText);
byte[] keyByte = GetLegalKey();

//设定key和向量
mCryptoService.Key = keyByte;
SetLegalIV();
// 解密对象
ICryptoTransform cryptoTransform = mCryptoService.CreateDecryptor();
try
{
// 内存流对象
MemoryStream ms = new MemoryStream(cryptoByte, 0, cryptoByte.Length);
// 初始化一个解密流对象
CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Read);
// 从解密流对象中得到解密后的数据
StreamReader sr = new StreamReader(cs);
return sr.ReadToEnd();
}
catch
{
return null;
}
}

public static void Main(string[] args)
{
string plainText = "a example 小朋友";
string key = "wqdj~yriu!@*k0_^fa7431%p$#=@hd+&";
string testEnc = null;
string testDec = null;

Console.WriteLine("Plain text: " + plainText);
Console.WriteLine("Key: " + key + "\n");

EncryptClass enc1 = new EncryptClass();
enc1.Key = key;
testEnc = enc1.Encrypt(plainText);
testDec = enc1.Decrypt(testEnc);
Console.WriteLine("Use Encrypt algorithm: " + enc1.mAlgorithm);
Console.WriteLine("Encrypted text: " + testEnc);
Console.WriteLine("Decrypted text: " + testDec+"\n");

EncryptClass enc2 = new EncryptClass(ServiceProviderEnum.TripleDES);
enc2.Key = key;
testEnc = enc2.Encrypt(plainText);
testDec = enc2.Decrypt(testEnc);
Console.WriteLine("Use Encrypt algorithm: " + enc2.mAlgorithm);
Console.WriteLine("Encrypted text: " + testEnc);
Console.WriteLine("Decrypted text: " + testDec+"\n");

EncryptClass enc3 = new EncryptClass("rc2");
enc3.Key = key;
testEnc = enc3.Encrypt(plainText);
testDec = enc3.Decrypt(testEnc);
Console.WriteLine("Use Encrypt algorithm: " + enc3.mAlgorithm);
Console.WriteLine("Encrypted text: " + testEnc);
Console.WriteLine("Decrypted text: " + testDec+"\n");

Console.Read();
}
}


C#Winform技术群:25380362
博客:http:///boyliupan/
2007-05-23 14:26
天使不哭
Rank: 6Rank: 6
等 级:贵宾
威 望:23
帖 子:677
专家分:22
注 册:2006-7-9
得分:0 

6 代码实例:调用常用哈希算法的实例


using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;

public class Hash
{
private HashAlgorithm mCryptoService;
private ServiceProviderEnum mAlgorithm;

public enum ServiceProviderEnum: int
{
// 支持的hash算法
SHA1,
SHA256,
SHA384,
SHA512,
MD5
}

public Hash()
{
// 缺省的hash算法
mCryptoService = new SHA1Managed();
mAlgorithm = ServiceProviderEnum.SHA1;
}

public Hash(ServiceProviderEnum serviceProvider)
{
//根据ServiceProviderEnum选择一个hash算法
switch(serviceProvider)
{
case ServiceProviderEnum.MD5:
mAlgorithm = ServiceProviderEnum.MD5;
mCryptoService = new MD5CryptoServiceProvider();
break;
case ServiceProviderEnum.SHA1:
mAlgorithm = ServiceProviderEnum.SHA1;
mCryptoService = new SHA1Managed();
break;
case ServiceProviderEnum.SHA256:
mAlgorithm = ServiceProviderEnum.SHA256;
mCryptoService = new SHA256Managed();
break;
case ServiceProviderEnum.SHA384:
mAlgorithm = ServiceProviderEnum.SHA384;
mCryptoService = new SHA384Managed();
break;
case ServiceProviderEnum.SHA512:
mAlgorithm = ServiceProviderEnum.SHA512;
mCryptoService = new SHA512Managed();
break;
}
}

public Hash(string serviceProviderName)
{
try
{
//根据hash算法的名字选择hash算法
switch(serviceProviderName.ToUpper())
{
case "MD5":
serviceProviderName = "MD5";
mAlgorithm = ServiceProviderEnum.MD5;
break;
case "SHA1":
serviceProviderName = "SHA1";
mAlgorithm = ServiceProviderEnum.SHA1;
break;
case "SHA256":
serviceProviderName = "SHA256";
mAlgorithm = ServiceProviderEnum.SHA256;
break;
case "SHA384":
serviceProviderName = "SHA384";
mAlgorithm = ServiceProviderEnum.SHA384;
break;
case "SHA512":
serviceProviderName = "SHA512";
mAlgorithm = ServiceProviderEnum.SHA512;
break;
}
mCryptoService = (HashAlgorithm)CryptoConfig.CreateFromName(serviceProviderName);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}

//hash一个文件
public string HashFile(string filePath)
{
string hashCode = null;

try
{
FileStream fs=File.Open(filePath,FileMode.Open,FileAccess.Read);
byte[] encodedBytes = this.mCryptoService.ComputeHash(fs);
hashCode = BitConverter.ToString(encodedBytes).Replace("-", "");
fs.Close();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}

return hashCode;
}

//hash一个字符串
public string HashString(string originalPassword)
{
byte[] originalBytes;
byte[] encodedBytes;
string hashCode = null;

try
{
originalBytes = System.Text.UTF8Encoding.UTF8.GetBytes(originalPassword);
encodedBytes = this.mCryptoService.ComputeHash(originalBytes);
hashCode = BitConverter.ToString(encodedBytes).Replace("-", "");
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}

return hashCode;
}

public static void Main(string[] args)
{
string plainText = "a example 小朋友 *&HHF";
string filePath = @"C:\WINDOWS\system32\notepad.exe";
string hashText = null;
string hashFile = null;

Console.WriteLine("Plain text: " + plainText);

Hash hash = new Hash("md5");
hashText = hash.HashString(plainText);
hashFile = hash.HashFile(filePath);
Console.WriteLine("Use Hash algorithm: " + hash.mAlgorithm);
Console.WriteLine("Hash code for text: " + hashText);
Console.WriteLine("Hash code for file: " + hashFile+"\n");

Hash hash1 = new Hash();
hashText = hash1.HashString(plainText);
hashFile = hash1.HashFile(filePath);
Console.WriteLine("Use Hash algorithm: " + hash1.mAlgorithm);
Console.WriteLine("Hash code for text: " + hashText);
Console.WriteLine("Hash code for file: " + hashFile+"\n");

Hash hash2 = new Hash(ServiceProviderEnum.SHA384);
hashText = hash2.HashString(plainText);
hashFile = hash2.HashFile(filePath);
Console.WriteLine("Use Hash algorithm: " + hash2.mAlgorithm);
Console.WriteLine("Hash code for text: " + hashText);
Console.WriteLine("Hash code for file: " + hashFile+"\n");

Hash hash3 = new Hash("sha512");
hashText = hash3.HashString(plainText);
hashFile = hash3.HashFile(filePath);
Console.WriteLine("Use Hash algorithm: " + hash3.mAlgorithm);
Console.WriteLine("Hash code for text: " + hashText);
Console.WriteLine("Hash code for file: " + hashFile+"\n");

Console.Read();
}
}


C#Winform技术群:25380362
博客:http:///boyliupan/
2007-05-23 14:27
天使不哭
Rank: 6Rank: 6
等 级:贵宾
威 望:23
帖 子:677
专家分:22
注 册:2006-7-9
得分:0 
竟然没有人顶......

C#Winform技术群:25380362
博客:http:///boyliupan/
2007-07-27 21:09
上来下去
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2006-3-12
得分:0 
我来顶你一下,并告诉你.我转贴了!
如有不妥请短消息告知.

2007-07-27 21:16
天使不哭
Rank: 6Rank: 6
等 级:贵宾
威 望:23
帖 子:677
专家分:22
注 册:2006-7-9
得分:0 
以下是引用上来下去在2007-7-27 21:16:29的发言:
我来顶你一下,并告诉你.我转贴了!
如有不妥请短消息告知.

o(∩_∩)o...没有关系


C#Winform技术群:25380362
博客:http:///boyliupan/
2007-07-27 21:25
ziyao1101
Rank: 1
等 级:新手上路
帖 子:4
专家分:0
注 册:2007-5-20
得分:0 
看不懂。。还是顶个
2007-08-04 13:38
反正都是自我
Rank: 1
等 级:新手上路
帖 子:70
专家分:0
注 册:2007-7-27
得分:0 

好强大的帖子啊。虽然看不懂,但还是顶啊。


2007-08-04 17:33



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-141812-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.064262 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved