您的位置:首页 > 其它

加密解密概述及.NET中对加密解密的支持(二)

2011-07-20 11:39 417 查看
.NET中加密解密的支持相信通过前面几页的叙述,大家已经明白了加密解密、数字签名的基本原理,下面我们看一下在.NET中是如何来支持加密解密的。正如上面我们所进行的分类,.NET中也提供了两组类用于加密解密,一组为对称加密,一组为非对称加密。这些类按照名称还可以分为两组,一组后缀为“CryptoServiceProvider”的,是对于底层Windows API的包装类,一组后缀为“Managed”,是在.NET中全新编写的类。.NET对称加密解密支持.NET Framework提供了一些常见的对称算法的实现,包括DES、RC2等。下面列出了与对称算法有关的类的结构:
System.Security.Cryptography.SymmetricAlgorithm System.Security.Cryptography.Aes
System.Security.Cryptography.AesCryptoServiceProvider
System.Security.Cryptography.AesManaged
System.Security.Cryptography.DES System.Security.Cryptography.DESCryptoServiceProvider
System.Security.Cryptography.RC2 System.Security.Cryptography.RC2CryptoServiceProvider
System.Security.Cryptography.Rijndael System.Security.Cryptography.RijndaelManaged
System.Security.Cryptography.TripleDES System.Security.Cryptography.TripleDESCryptoServiceProvider这些类中黑体表示的类为实现算法的具体类,其它的都是抽象类;也可以根据需要实现自己的对称算法。
.NET非对称加密解密支持RSA是当今最常用的非对称算法,其被应用于很多领域。RSA算法的理论依据来自于一个大素数所具有的特性:对于给定的两个大素数A与B,很容易计算出它们的乘积;但是,仅知道AB的成绩却很难计算原来的A与B各自的值。
.NET Frameork提供了两个类供我们使用RSA算法:用于加密数据的RSACryptoServiceProvider类以及用于对数据做数字签名的DSACryptoServiceProvider类(DSA: Digital Signature Algorithm,数字签名算法),其类的层次结构如下

System.Security.Cryptography.AsymmetricAlgorithm
System.Security.Cryptography.DSA System.Security.Cryptography.DSACryptoServiceProvider
System.Security.Cryptography.RSA System.Security.Cryptography.RSACryptoServiceProvider System.Security.Cryptography.ECDiffieHellman(椭圆曲线Diffie-Hellman (ECDH) 算法实现)
System.Security.Cryptography.ECDiffieHellmanCng(椭圆曲线Diffie-Hellman (ECDH) 算法的下一代加密技术 (CNG) 实现)
System.Security.Cryptography.ECDsa
System.Security.Cryptography.ECDsaCng(椭圆曲线数字签名算法 (ECDSA) 的下一代加密技术 (CNG) 实现)

.NET散列算法支持散列算法是把长长的一列数据变成较短的代码,这是最流行的64位散列密钥。两个最流行的散列算法是SHA(Secured Hash Algorithm)和MD5(MessageDigest version5)。这些散列密钥用于标记数字文档。
散列值是根据一个数据集合计算出来的数字。如果数据集合不同,那么计算出来的数字基本上也是不同的。.NET Framework在其System.Security.Cryptography命名空间下提供了一些主要的散列算法,包括:SHAx、RIPEMD160、与MD5。

System.Security.Cryptography.HashAlgorithmSystem.Security.Cryptography.KeyedHashAlgorithm(键控哈希算法的实现基类) System.Security.Cryptography.HMAC (基于哈希的消息验证代码 (HMAC)的抽象类)System.Security.Cryptography.HMACMD5System.Security.Cryptography.HMACRIPEMD160System.Security.Cryptography.HMACSHA1System.Security.Cryptography.HMACSHA256System.Security.Cryptography.HMACSHA384System.Security.Cryptography.HMACSHA512System.Security.Cryptography.MACTripleDES
System.Security.Cryptography.MD5System.Security.Cryptography.MD5Cng(128 位哈希算法的 CNG(下一代加密技术)实现 System.Security.Cryptography.MD5CryptoServiceProvider
System.Security.Cryptography.RIPEMD160 System.Security.Cryptography.RIPEMD160Managed
System.Security.Cryptography.SHA1 System.Security.Cryptography.SHA1CryptoServiceProvider
System.Security.Cryptography.SHA1Managed System.Security.Cryptography.SHA256 System.Security.Cryptography.SHA256ManagedSystem.Security.Cryptography.SHA384 System.Security.Cryptography.SHA384Managed
System.Security.Cryptography.SHA512 System.Security.Cryptography.SHA512Managed
KeyedHash
键控哈希算法是依赖于密钥的单向哈希函数,用作消息验证代码。只有知道密钥的人才能验证哈希值。加密哈希算法提供没有机密的真实性。
SHA
SHA(安全散列算法)是一个块密码,在64位的数据块上执行,这个算法的改进版本采用了更大的密钥值,当然,密钥值越大所需的计算时间越长。而且,对于相对较小的文件,散列值越小就越安全,就是说,散列算法的块大小应小于或等于数据块本身的大小。 SHA1算法的散列范围是160位。
.NET Framework也提供了更大的密钥值算法,分别为SHA256、SHA384和SHA512。名称最后的数字表示其块大小。
ASP.NET安全性中的成员资格提供程序使用SHA1加密用户密码。
MD5
MD5表示MessageDigest版本5。它是一个加密的单向散列算法。MD5有抗伪造,计算成本低且执行简单等特点。现在MD5已成为散列算法的事实标准。
.NET Framework提供了MD5CryptoServiceProvider这个类实现MD5算法。该类与SHA1共享同一个基类,前面的示例也只需要做简单的改动即可成为使用MD5进行处理的例子。
RIPEMD-160
基于MD5的RIPEMD-160最早出现于欧洲,是一个使用160位的散列算法。.NET也引入了对这种算法的支持。

对称加密解密示例现在假设我们以TripleDES作为算法,那么加密的流程如下:1. 先创建一个TripleDESCryptoServiceProvider的实例,实例名比如叫provider。 2.在provider上指定密钥和IV,也就是它的Key属性和IV属性。这里简单解释一下IV(initialization vector),如果一个字符串(或者数据)加密之前很多部分是重复的比如ABCABCABC,那么加密之后尽管字符串是乱码,但相关部分也是重复的。为了解决这个问题,就引入了IV,当使用它以后,加密之后即使是重复的也被打乱了。对于特定算法,密钥和IV的值可以随意指定,但长度是固定,通常密钥为128位或196位,IV为64位。密钥和IV都是byte[]类型,因此,如果使用Encoding类来将字符串转换为byte[],那么编码方式就很重要,因为UTF8是变长编码,所以对于中文和英文,需要特别注意byte[]的长度问题。 3.如果是加密,在provider上调用CreateEncryptor()方法,创建一个ICryptoTransform类型的加密器对象;如果是解密,在provider上调用CreateDecryptor()方法,同样是创建一个ICryptoTransform类型的解密器对象。ICryptoTransform定义了加密转换的运算,.NET将在底层调用这个接口。 4.因为流和byte[]是数据类型无关的一种数据结构,可以保存和传输任何形式的数据,区别只是byte[]是一个静态的概念而流是一个动态的概念。因此,.NET采用了流的方式进行加密和解密,我们可以想到有两个流,一个是明文流,含有加密前的数据;一个是密文流,含有加密后的数据。那么就必然有一个中介者,将明文流转换为密文流;或者将密文流转换为明文流。.NET中执行这个操作的中介者也是一个流类型,叫做CryptoStream。它的构造函数如下,共有三个参数: publicCryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)5. 当加密时,stream为密文流(注意此时密文流还没有包含数据,仅仅是一个空流);ICryptoTransform是第3步创建的加密器,包含着加密的算法;CryptoStreamMode枚举为Write,意思是将流经CryptoStream的明文流写入到密文流中。最后,从密文流中获得加密后的数据。 6. 当解密时,stream为密文流(此时密文流含有数据);ICryptoTransform是第3步创建的解密器,包含着解密的算法;CryptoStreamMode枚举为Read,意思是将密文流中的数据读出到byte[]数组中,进而再由byte[]转换为明文流、明文字符串。 可见,CryptoStream总是接受密文流,并且根据CryptoStreamMode枚举的值来决定是将明文流写入到密文流(加密),还是将密文流读入到明文流中(解密)。下面是我编写的一个加密解密的Helper类:
// 对称加密帮助类
public class CryptoHelper
{
private SymmetricAlgorithm provider;
private ICryptoTransform encryptor;
private ICryptoTransform decryptor;
private const int BufferSize = 1024;

public CryptoHelper(string algorithmName)
{
provider = SymmetricAlgorithm.Create(algorithmName);
string strKey = ConfigurationManager.AppSettings["CryptoKey"];
string strIV = ConfigurationManager.AppSettings["CryptoIV"];
if (string.IsNullOrEmpty(strKey) || string.IsNullOrEmpty(strIV))
throw new ArgumentNullException("CryptoKey");

//Key
byte[] bsKey = Encoding.UTF8.GetBytes(strKey);
int keySize = provider.KeySize/8;
if (bsKey.Length != keySize)
{
byte[] key = new byte[keySize];
if (bsKey.Length > keySize)
Array.Copy(bsKey, key, keySize);
else
Array.Copy(bsKey, key, bsKey.Length);
provider.Key = key;
}
else
{
provider.Key = bsKey;
}

//IV
byte[] bsIV = Encoding.UTF8.GetBytes(strIV);
int ivSize = provider.BlockSize / 8;
if (bsIV.Length != ivSize)
{
byte[] iv = new byte[ivSize];
if(bsIV.Length > ivSize)
Array.Copy(bsIV, iv, ivSize);
else
Array.Copy(bsIV, iv, bsIV.Length);
provider.IV = iv;
}
else
{
provider.IV = bsIV;
}

encryptor = provider.CreateEncryptor();
decryptor = provider.CreateDecryptor();
}

public CryptoHelper() : this("TripleDES") { }

// Encrypt
public string Encrypt(string clearText)
{
byte[] clearBuffer = Encoding.UTF8.GetBytes(clearText);
MemoryStream clearStream = null;
MemoryStream encryptedStream = null;
CryptoStream cryptoStream = null;
try
{
clearStream = new MemoryStream(clearBuffer);
encryptedStream = new MemoryStream();
cryptoStream = new CryptoStream(encryptedStream, encryptor, CryptoStreamMode.Write);

byte[] buffer = new byte[BufferSize];
int bytesRead = 0;
while((bytesRead = clearStream.Read(buffer, 0, BufferSize)) > 0)
{
cryptoStream.Write(buffer, 0, bytesRead);
}

cryptoStream.FlushFinalBlock();
buffer = encryptedStream.ToArray();
string encryptedText = Convert.ToBase64String(buffer);
return encryptedText;
}
finally
{
if (cryptoStream != null)
{
cryptoStream.Close();
cryptoStream = null;
}
if (encryptedStream != null)
{
encryptedStream.Close();
encryptedStream = null;
}
if (clearStream != null)
{
clearStream.Close();
clearStream = null;
}
if (provider != null)
{
provider.Clear();
}
}

}

// Decrypt
public string Decrypt(string encryptedText)
{
byte[] encryptedBuffer = Convert.FromBase64String(encryptedText);
byte[] buffer = new byte[BufferSize];
Stream encryptedStream = null;
MemoryStream clearStream = null;
CryptoStream cryptoStream = null;

try
{
encryptedStream = new MemoryStream(encryptedBuffer);

clearStream = new MemoryStream();
cryptoStream = new CryptoStream(encryptedStream, decryptor, CryptoStreamMode.Read);

int bytesRead = 0;

while ((bytesRead = cryptoStream.Read(buffer, 0, BufferSize)) > 0)
{
clearStream.Write(buffer, 0, bytesRead);
}

buffer = clearStream.GetBuffer();
string clearText = Encoding.UTF8.GetString(buffer, 0, (int)clearStream.Length);

return clearText;
}
finally
{
if (encryptedStream != null)
{
encryptedStream.Close();
encryptedStream = null;
}
if (clearStream != null)
{
clearStream.Close();
clearStream = null;
}
if (cryptoStream != null)
{
cryptoStream.Close();
cryptoStream = null;
}
if (provider != null)
{
provider.Clear();
}
}
}

}


非对称加密解密示例如果对文件的安全性要求不是很严格,只是控制文件在传输中的完整性,可以用散列算法算出一个文件的散列,然后用非对称算法加密并把加密后的信息附加于文件中,接收方使用收到的文件中的散列验证文件的完整性,同时也能确认文件的发送者,即实现了简单的文件签名的功能。

下面示例演示了如何使用RSACryptoServiceProvider类加密一个字符串。其中,ExpertParameter(bool)方法根据参数的真假允许获得公钥/私钥对(true)或只有公钥(false)。

using System;
using System.Text;
using System.Security.Cryptography;
class Program
{
static void Main()
{
string sMsg = "The message to encrypt!";
string sEnc, sDec;
Encoding utf = new UTF8Encoding();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
RSAParameters publicKey = rsa.ExportParameters(false);
RSAParameters publicAndPrivateKey = rsa.ExportParameters(true);
{
RSACryptoServiceProvider rsaEncryptor = new
RSACryptoServiceProvider();
rsaEncryptor.ImportParameters(publicKey);
byte[] bMsg = utf.GetBytes(sMsg);
byte[] bEnc = rsaEncryptor.Encrypt(bMsg, false);
sEnc = Convert.ToBase64String(bEnc);
}
{
RSACryptoServiceProvider rsaDecryptor = new
RSACryptoServiceProvider();
rsaDecryptor.ImportParameters(publicAndPrivateKey);
byte[] bEnc = Convert.FromBase64String(sEnc);
byte[] bDec = rsaDecryptor.Decrypt(bEnc, false);
sDec = utf.GetString(bDec);
}
Console.WriteLine("Message : " + sMsg);
Console.WriteLine("Encrypted: " + sEnc);
Console.WriteLine("Decrypted: " + sDec);
}
}


哈希计算示例以下以MD5算法计算哈希值为例,给出简单示例。
public string MD5Crypto(string input)
{
MD5 md5Hasher = null;
try
{
// 创建? MD5CryptoServiceProvider 对象U的I实例a
md5Hasher = MD5.Create();

//计算Z哈u希o代a码
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));

StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("X2"));
}
return sBuilder.ToString();

}
finally
{
if (md5Hasher != null)
{
md5Hasher.Clear();
md5Hasher.Dispose();
md5Hasher = null;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐