C# 常用散列算法与加解密算法使用-散列算法

在应用系统开发中,安全涉及的机密性、完整性、身份认证都需要散列算法或加解密算法的参与,C# 提供了常用的散列算法和加解密算法类,利用这些类,我们可以方便地实现所需功能。

1.散列算法

散列算法是把任意长度的输入,变换成固定长度的输出,且不能由输出推算出输入,这里的输出,也就是我们常说的散列值。理论上来说,存在两个不同的输入,经过散列算法后获得相同的散列值,但是由于要找到这样的一组输入,几乎是不可能的任务,所以我们可以认为世界万事万物中不存在拥有相同散列值的事物(尽管实际是存在的),鉴于散列算法的这种特性,它常常被用于文件校验、密码存储、数字签名等场合。

常用的散列算法是 MD5、SHA-1(程序中受特殊字符限制,常常用 SHA1 表示),在 C# 中有多种方式可以创建 MD5、SHA1 的散列值。

法一、使用 FormsAuthentication。

FormsAuthentication 类的命名空间是 System.Web.Security,在 ASP.NET 环境中可以直接使用,但在 VC# 环境中,需要先在引用中添加程序集 System.Web,该程序集位于类似 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Web.dll 的地方。

如上第二个参数指明了要使用哪种散列算法,不区分大小写

法二、使用 HashAlgorithm。

HashAlgorithm 类的命名空间是 System.Security.Cryptography。

HashAlgorithm.Create 的参数指明了要使用哪种散列算法,不区分大小写。BitConverter 将二进制用十六进制字符串表示,删除掉横线间隔便于与其他散列算法的结果兼容。

上述两种方法,输出的散列值都是用大写的十六进制字符串表示的二进制,其他语言中有的是小写字符,所以在与其他语言进行交互时,要注意大小写。

 

 

 

在应用系统开发中,安全涉及的机密性、完整性、身份认证都需要散列算法或加解密算法的参与,C# 提供了常用的散列算法和加解密算法类,利用这些类,我们可以方便地实现所需功能。

2.对称加密

对称加密只有一套密钥,加密和解密均使用该密钥,该密钥决定了密文的安全与否,所以一定要保存好该密钥。对称加密的特点是速度快,能对大容量数据进入加密解密。

本文介绍的 TripleDES 是对 DES 的加强,使用的类是 TripleDESCryptoServiceProvider,其命名空间是 System.Security.Cryptography。

我们可以看到加密后的 byte 数组,和散列算法不同,这次是通过转换为 Base64 格式的字符串,主要是还有个解密的过程,用 Base64 的话,解密过程中可以更方便地转换回 byte 数组。

另外,我们会发现,没有密钥!的确,这里是随机产生的。下面看看如何指定密钥进行加密、解密。

指定密钥是在 tripleDES.CreateEncryptor 和 tripleDES. CreateDecryptor 中指定的,而解密的代码是加密的一个反向的过程。要注意:明文与 byte 数组之间的转换用的是 Encoding.UTF8.GetBytes、Encoding.UTF8.GetString(也可以是其他编码);密文与 byte 数组之间的转换用的是 Convert.ToBase64String、Convert.FromBase64String;密钥用 Base64 存储。

 

在使用Convert.ToBase64String()对字符串进行Base64编码时,注意的几点:
  
例:string s = "Hello";
      byte[] bytes = Convert.FromBase64String(s);
以上代码在运行时会抛出FormatException异常.提示为:Base-64字符数组的无效长度

原因:
Convert.FromBase64String方法的参数s的长度小于4或不是4的偶数倍时,将会抛出FormatException
   
  

       Convert.FromBase64String("Hell");      // Normal.
       Convert.FromBase64String("Hell ");     // Normal.
(忽略空格)
       Convert.FromBase64String("Hello!");     // throw FormatException.
       Convert.FromBase64String("Hello Net"); // Normal.
(忽略空格)

using System.Web.Security;
using System.Security.Cryptography;
using System.IO;
/// <summary>
/// 加密解密类
/// </summary>
public class Crypt
{
    
public static string sKey = "你的密钥字符串";//长度为8位,要不报错:指定键的大小对于此算法无效
    
/// <summary>
    
/// md5加密算法
    
/// </summary>
    
/// <param name="str">要加密的字符创</param>
    
/// <param name="Len16">是否长度为16,对应asp的md5加密</param>
    
/// <returns>加密后的字符串</returns>
    
public static string MD5(string str, bool Len16)
    {
        
if (Len16) return FormsAuthentication.HashPasswordForStoringInConfigFile(str, "md5").ToLower().Substring(8, 16);
        
else return FormsAuthentication.HashPasswordForStoringInConfigFile(str, "md5").ToLower();
    }
    
/// <summary>
    
/// DES 加密过程
    
/// </summary>
    
/// <param name="pToDecrypt">被解密的字符串</param>
    
/// <returns>返回被解密的字符串</returns>
    
public static string Encrypt(string pToEncrypt)
    {
        
//访问数据加密标准(DES)算法的加密服务提供程序 (CSP) 版本的包装对象
        DESCryptoServiceProvider des = 
new DESCryptoServiceProvider();
        des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
 //建立加密对象的密钥和偏移量
        des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
  //原文使用ASCIIEncoding.ASCII方法的GetBytes方法
        
byte[] inputByteArray = Encoding.UTF8.GetBytes(pToEncrypt);//把字符串放到byte数组中
        MemoryStream ms = 
new MemoryStream();//创建其支持存储区为内存的流 
        
//定义将数据流链接到加密转换的流
        CryptoStream cs = 
new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
        cs.Write(inputByteArray, 0, inputByteArray.Length);
        cs.FlushFinalBlock();
        
//上面已经完成了把加密后的结果放到内存中去
        StringBuilder ret = 
new StringBuilder();
        
foreach (byte b in ms.ToArray())
        {
            ret.AppendFormat(
"{0:X2}", b);
        }
        ret.ToString();
        
return ret.ToString();
    }
    
/// <summary>
    
/// DES 解密过程
    
/// </summary>
    
/// <param name="pToDecrypt">被解密的字符串</param>
    
/// <returns>返回被解密的字符串</returns>
    
public static string Decrypt(string pToDecrypt)
    {
        DESCryptoServiceProvider des = 
new DESCryptoServiceProvider();
        
byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
        
for (int x = 0; x < pToDecrypt.Length / 2; x++)
        {
            
int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
            inputByteArray[x] = (
byte)i;
        }
        des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
 //建立加密对象的密钥和偏移量,此值重要,不能修改
        des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
        MemoryStream ms = 
new MemoryStream();
        CryptoStream cs = 
new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
        cs.Write(inputByteArray, 0, inputByteArray.Length);
        cs.FlushFinalBlock();
        
//建立StringBuild对象,createDecrypt使用的是流对象,必须把解密后的文本变成流对象
        StringBuilder ret = 
new StringBuilder();
        
return System.Text.Encoding.UTF8.GetString(ms.ToArray());
    }
}

3.不对称加密

不对称加密有两套密钥,一套为公钥可以公开,一套为私钥需要保密。不对称加密速度慢,且无法对大容量的数据进入加密解密,但它可以对外公开公钥,保存一个别人不知道的私钥。常用的不对称加密算法是 RSA。

可使用 RSACryptoServiceProvider 进行 RSA 加密、解密,该类的命名空间是 System.Security.Cryptography。

不对称加密的密钥并不是随便输一串字符就可以当作密钥的,它是经过严格的算法产生的,如上没有指定,那么就使用自动产生的密钥。

如果要获取这个密钥,怎么办呢?使用 rsa.ToXmlString(false),参数 false 表示不要把私钥输出来。下面用实例演示一下使用特定的密钥进行加密、解密。

上述密钥是含有私钥的,实际应用中,如果我们希望公众发来的数据是加密的,那么我们公开公钥,公众只需要用公钥进行加密,然后接收方再用私钥进行解密。

不对称加密常常和对称加密组合使用:对称加密对大内容进行加密,不对称加密再把对称加密的密钥进行加密,这样组合起来就达到了安全传输大内容的效果。

 

 

 

在其他一些文章中,我们会发现,还有以 Managed 结尾的类,比如:

·          System.Security.Cryptography.SHA1

·          System.Security.Cryptography.SHA1Managed

·          System.Security.Cryptography.SHA1CryptoServiceProvider

这三个类有什么关系呢?

SHA1 是抽象类,SHA1Managed 和 SHA1CryptoServiceProvider 继承于 SHA1。

SHA1Managed 和 SHA1CryptoServiceProvider 有什么区别呢?

二者功能都一样。SHA1Managed 被写入了托管 .NET 语言(比如:C#、VB.NET);而 SHA1CryptoServiceProvider 是基于 Windows Crypto API 的,也就是说它是依赖于 Windows 中某个 DLL 的。后者性能要高些。


 

posted @ 2016-05-23 19:28  常想一二,不思八九  阅读(1614)  评论(0)    收藏  举报