代码改变世界

net加密基础1-对称加密

2012-02-04 21:43  海不是蓝  阅读(1799)  评论(2编辑  收藏  举报

.NET中常用的3个密码术命名空间

using System.Security.Cryptography;

using System.Security.Cryptography.Xml;

using System.Security.Cryptography.X509Certificates;

 

它们依次的大概作用解释:

1.System.Security.Cryptography

包含所有加密任务的核心类

2.System.Security.Cryptography.Xml

包含结合使用System.Security.Cryptography,对XML文档部分内容进行加密和签名的类

3.System.Security.Cryptography.X509Certificates

包含允许检索证书信息的类

 

System.Security.Cryptography3层模型

 

 

 

第一层:第一层是一组抽象类,它们表示加密算法的类型,用于完成特定的加密任务。

第二层:表示包含特定加密算法的类,由第一层派生而来,它们也是抽象类,例如DES算法类。

第三层:就是加密的实现方案。都是由算法类派生而来。

 

构建块

NET系统使用基于流的体系结构来加密和解密,这样就可以方便的对来自不同数据源的不同数据类型进行加密处理。

 

它是如何工作的?ICryptoTransform接口和CryptoStream


ICryptoTransform接口

由可以执行块加密转换的类实现,可以是加密,解密,散列计算,基于64的编码/解码或格式化操作。

DES des = DES.Create();

ICryptoTransform ic = des.CreateEncryptor();

这个接口的详细解释请去msdn观看。多数情况我们用CryptoStream类替换这个接口。

 

CryptoStream

这个类是个重点,它包装了,并使用ICryptoTransform 在后台执行操作。

优点是它采用了缓冲访问,使用它就可以进行加密。不用担心算法所需要块的大小。

另外一个优点是它包装了普通NET Stream派生类,所以它可以很方便的和各种流进行操作。

下面介绍下加密算法的分类

 

对称密码算法

加密解密都使用相同的密钥,那么这个密码算法就是对称密码算法。

即如果密钥K用于将明文加密成NajDs78a,那么密钥K也就用解密NajDs78a。

由于加密解密都采用相同的密钥,所以有时候称为同一密钥和单密钥。

 

对称密码算法分为两大类:

1.块密码算法

2.流密码算法

它们分别用于不同的应用程序领域。

 

NET中提供的对称算法

算 法

抽象算法类

默认实现类

有效密钥大小

默认密钥大小

DES

DES

DESCryptoServiceProvider

64位

64

TripleDES

TripleDES

TripleDESCryptoServiceProvider

 

128,192

192

RC2

RC2

RC2CryptoServiceProvider

 

40-128

128

Rijndael

Rijndael

RijndaelManaged

 

128,192,256

256

 

大多数情况可以使用Rijndael作为默认推荐的算法.

 

SymmetricAlgorithm类

上面所有的对称加密类都是继承SymmetricAlgorithm类。

几个重要的属性

 属性

说明

BlockSize 

使用该算法在一次操作中可以加密或解密的数据基本单位。

Key 

用于加密或解密数据的秘密值。

KeySize 

分配给秘密密钥的位数。

IV 

初始化向量,提供加密过程额外输入并提高安全性,初始化向量与密钥一样,加密者和解密者都必须知道,不过,它不需要保密。

重点:IV的长度总是和BlockSize 数据块的长度一样!

LegalBlockSizes

获取对称算法支持的块大小。 

LegalKeySizes

获取对称算法支持的密钥大小。

 

非对称密码算法

 

net加密基础-非对称加密中介绍。

 

使用对称加密DES算法

1.创建DES对象

DES des = DES.Create();

然后我们就要设置密钥Key和初始化向量IV。

 

2.设置密钥Key和初始化向量IV

我们先看看Net中对Key和IV的定义

// Fields

private static KeySizes[] s_legalBlockSizes = new KeySizes[] { new KeySizes(0x40, 0x40, 0) };

private static KeySizes[] s_legalKeySizes = new KeySizes[] { new KeySizes(0x40, 0x40, 0) };

 

s_legalBlockSizesBlockSize ,也就是加密或解密的数据块。

s_legalKeySizes 就是密钥。

 

再看看KeySizes的定义

public KeySizes(int minSize, int maxSize, int skipSize)

{

    this.m_minSize = minSize;

    this.m_maxSize = maxSize;

    this.m_skipSize = skipSize;

}

通过上面我们知道了DES算法的数据块大小为0x40位,也就是64位,转换成byte数组就是长度为8。也就是64除以8=8个字节大小。

上面我们提到过IV的长度总是和BlockSize 数据块的长度一样!

所以我们使用DES算法的时候IV的长度应该为8个长度的byte数组。

 

同理,使用DES算法的密钥Key的长度为8个长度的byte数组。

 

注意KeySizes定义了最大和最小!只是这里DES算法最大最小都是一样的

码如果在使用加密算法的时候不按照算法要求设置Key长度和IV长度,就会抛出异常!

 

 

static void Main()
{
//假设这里是加密客户
DES des = DES.Create();
Encoding e = Encoding.UTF8;
//注意下面的Key和IV都是设置为64位长度的,转换以后就是长度为8的byte数组
string str = DEScryptor(des, "我是明文", e, "ujd87yr4", "ujd87yr4");
Console.WriteLine("密文:{0}", str);
//假设这里是解密客户
DES des1 = DES.Create();
Console.WriteLine("明文:{0}", DESDecryptor(des1, str, e, "ujd87yr4", "ujd87yr4"));
Console.Read();
}
/// <summary>
/// DES对称加密算法
/// </summary>
/// <typeparam name="T">对称加密算法类型</typeparam>
/// <param name="Encryptor">加密算法实例对象</param>
/// <param name="EncryptString">待加密的字符</param>
/// <param name="encd">待加密的字符编码</param>
/// <param name="Key">加密算法密钥</param>
/// <param name="IV">加密算法初始化向量</param>
/// <returns></returns>
public static string DEScryptor(DES Encryptor, string EncryptString, Encoding encd, string Key, string IV)
{
if (string.IsNullOrEmpty(EncryptString)
|| string.IsNullOrEmpty(Key)
|| string.IsNullOrEmpty(IV))
throw new ArgumentNullException("参数不正确!");
CryptoStream cs = null;
Encoding ec = encd ?? Encoding.Default;
Byte[] StrBytes = ec.GetBytes(EncryptString);
Byte[] KeyBytes = Encoding.ASCII.GetBytes(Key);
Byte[] IVBytes = Encoding.ASCII.GetBytes(IV);
try
{
MemoryStream ms = new MemoryStream();
cs = new CryptoStream(ms, Encryptor.CreateEncryptor(KeyBytes, IVBytes), CryptoStreamMode.Write);
cs.Write(StrBytes, 0, StrBytes.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
catch (CryptographicException ex)
{
throw new ArgumentException(ex.Message);
}
finally
{
if (cs != null)
cs.Close();
}
}
/// <summary>
/// DES对称解密算法
/// </summary>
/// <typeparam name="T">对称解密算法类型</typeparam>
/// <param name="Decryptor">对称解密算法实例对象</param>
/// <param name="DecryptorString">代解密的字符串</param>
/// <param name="encd">输出的解密字符串编码</param>
/// <param name="Key">解密密钥</param>
/// <param name="IV">解密初始化向量</param>
/// <returns></returns>
public static string DESDecryptor(DES Decryptor, string DecryptorString, Encoding encd, string Key, string IV)
{
if (string.IsNullOrEmpty(DecryptorString)
|| string.IsNullOrEmpty(Key)
|| string.IsNullOrEmpty(IV))
throw new ArgumentNullException("参数不正确!");
CryptoStream cs = null;
Encoding ec = encd ?? Encoding.Default;
Byte[] StrBytes = Convert.FromBase64String(DecryptorString);
Byte[] KeyBytes = Encoding.ASCII.GetBytes(Key);
Byte[] IVBytes = Encoding.ASCII.GetBytes(IV);
try
{
MemoryStream ms = new MemoryStream();
cs = new CryptoStream(ms, Decryptor.CreateDecryptor(KeyBytes, IVBytes), CryptoStreamMode.Write);
cs.Write(StrBytes, 0, StrBytes.Length);
cs.FlushFinalBlock();
return ec.GetString(ms.ToArray());
}
catch (CryptographicException ex)
{
throw new ArgumentException(ex.Message);
}
finally
{
if (cs != null)
cs.Close();
}
}

 

其它对称算法介绍

微软是将Rijndael作为默认推荐的算法

通过Reflector这个工具我们可以查看它的Key长度等信息

// Fields

private static KeySizes[] s_legalBlockSizes = new KeySizes[] { new KeySizes(0x80, 0x100, 0x40) };

private static KeySizes[] s_legalKeySizes = new KeySizes[] { new KeySizes(0x80, 0x100, 0x40) };

所以Rijndael加密算法的密钥Key的长度有2个合法的,最小是长度为16的byte数组,最大为32长度的byte数组。

IV的长度和Key一样,小是长度为16的byte数组,最大为32长度的byte数组

 

TripleDES加密算法

// Fields

private static KeySizes[] s_legalBlockSizes = new KeySizes[] { new KeySizes(0x40, 0x40, 0) };

private static KeySizes[] s_legalKeySizes = new KeySizes[] { new KeySizes(0x80, 0xc0, 0x40) };

 

RC2加密算法

// Fields

protected int EffectiveKeySizeValue;

private static KeySizes[] s_legalBlockSizes = new KeySizes[] { new KeySizes(0x40, 0x40, 0) };

private static KeySizes[] s_legalKeySizes = new KeySizes[] { new KeySizes(40, 0x400, 8) };

 

为了方便使用,我写了个对称加密的泛型方法

 

static void Main()
{
//假设这里是加密客户
Rijndael rj = Rijndael.Create();
Encoding e = Encoding.UTF8;
//注意下面的Key和IV都是设置为128位长度的,转换以后就是长度为16的byte数组
string str = SymmetryEncryptor<Rijndael>(rj, "我是明文", e, "ujd87yr4sdf34rt5", "ujd87yr4sdf34rt5");
Console.WriteLine("密文:{0}", str);
//假设这里是解密客户
Rijndael rj1 = Rijndael.Create();
Console.WriteLine("明文:{0}", SymmetryDecryptor<Rijndael>(rj1, str, e, "ujd87yr4sdf34rt5", "ujd87yr4sdf34rt5"));
Console.Read();
}

 

/// <summary>
/// 对称加密算法
/// </summary>
/// <typeparam name="T">对称加密算法类型</typeparam>
/// <param name="Encryptor">加密算法实例对象</param>
/// <param name="EncryptString">待加密的字符</param>
/// <param name="encd">待加密的字符编码</param>
/// <param name="Key">加密算法密钥</param>
/// <param name="IV">加密算法初始化向量</param>
/// <returns></returns>
public static string SymmetryEncryptor<T>(T Encryptor, string EncryptString, Encoding encd, string Key, string IV)
where T : SymmetricAlgorithm
{
if (string.IsNullOrEmpty(EncryptString)
|| string.IsNullOrEmpty(Key)
|| string.IsNullOrEmpty(IV))
throw new ArgumentNullException("参数不正确!");
CryptoStream cs = null;
Encoding ec = encd ?? Encoding.Default;
Byte[] StrBytes = ec.GetBytes(EncryptString);
Byte[] KeyBytes = Encoding.ASCII.GetBytes(Key);
Byte[] IVBytes = Encoding.ASCII.GetBytes(IV);
try
{
MemoryStream ms = new MemoryStream();
cs = new CryptoStream(ms, Encryptor.CreateEncryptor(KeyBytes, IVBytes), CryptoStreamMode.Write);
cs.Write(StrBytes, 0, StrBytes.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
catch (CryptographicException ex)
{
throw new ArgumentException(ex.Message);
}
finally
{
if (cs != null)
cs.Close();
}
}

 

/// <summary>
/// 对称解密算法
/// </summary>
/// <typeparam name="T">对称解密算法类型</typeparam>
/// <param name="Decryptor">对称解密算法实例对象</param>
/// <param name="DecryptorString">代解密的字符串</param>
/// <param name="encd">输出的解密字符串编码</param>
/// <param name="Key">解密密钥</param>
/// <param name="IV">解密初始化向量</param>
/// <returns></returns>
public static string SymmetryDecryptor<T>(T Decryptor, string DecryptorString, Encoding encd, string Key, string IV)
where T : SymmetricAlgorithm
{
if (string.IsNullOrEmpty(DecryptorString)
|| string.IsNullOrEmpty(Key)
|| string.IsNullOrEmpty(IV))
throw new ArgumentNullException("参数不正确!");
CryptoStream cs = null;
Encoding ec = encd ?? Encoding.Default;
Byte[] StrBytes = Convert.FromBase64String(DecryptorString);
Byte[] KeyBytes = Encoding.ASCII.GetBytes(Key);
Byte[] IVBytes = Encoding.ASCII.GetBytes(IV);
try
{
MemoryStream ms = new MemoryStream();
cs = new CryptoStream(ms, Decryptor.CreateDecryptor(KeyBytes, IVBytes), CryptoStreamMode.Write);
cs.Write(StrBytes, 0, StrBytes.Length);
cs.FlushFinalBlock();
return ec.GetString(ms.ToArray());
}
catch (CryptographicException ex)
{
throw new ArgumentException(ex.Message);
}
finally
{
if (cs != null)
cs.Close();
}
}




作者:海不是蓝

博客:http://www.cnblogs.com/hailan2012/

邮箱:hailan2012@sina.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。