Author:zfive5(zidong)
Email:zfive5@yahoo.com.cn
引子
一直以来认为网络是me的强项,自然书也买了和看了不少,日子久了,好书坏书靠经验去分辨, 但往往经验也同样会影响我对事物的正确判断。例如,很早看到过王达写的网络方面的书,第一印象觉得有凑数赚钱的嫌疑,连翻的机会都不给它,但上星期去海淀买来一本(感谢网上的评论),察觉到这系列简直就是网络基础的百科全书!虽然不是太深入,但讲什么是A之类的命题足以,我也对PPPoE协议格式理解比以前多些!
写标准加密散列算法,像DES /MD5之类,都统统用c/c++,觉得只有在自己代码里包含最深层次的code才是正道,任何用其它库或控件是对这些算法无知的表露!
这些天看.net比较多! 打开System.Security.Cryptography命名空间后才有了写它一点的冲动(感谢老天在我阅读msdn时,让鼠标偏了一下)!
正文
System.Security.Cryptography加密算法主要分为:
l 散列算法 (MD5/SHA1/ RIPEMD160/ SHA256 / SHA384等 )
l 对称加密算法 (DES/TRI-DES等)
l 非对称加密算法(RSA/DSA)
1.散列
散列,简单点就是一种变换,使变换后的数据在一定小概率情况下代表变换前数据的“标签”,这个标签就是散列,变换就是散列算法,往往这些算法是公开的、不可逆的!因为算法公开的,为了防止大家谁都可以对源数据进行散列,所以出现增加一个KEY的变形散列算法(HMAC算法)。
散列主要用在对数据有效性的验证方面。例如,BT就是用SHA1验证收到数据块是否有效的,Email服务器的登录就有一中名为HMACMD5的验证模式!
C#代码
//对byte数据串进行散列
HashAlgorithm oTransform = (HashAlgorithm)MD5.Create();
byte[] AInput={0x31,0x31,0x31,0x31};
byte[] AOutput = oTransform.ComputeHash(AInput);
//对文件流进行散列
FileStream oFile = new FileStream("c://10.vbs", FileMode.Open);
HashAlgorithm oTransform = (HashAlgorithm)MD5.Create();
byte[] AOutput = oTransform.ComputeHash(oFile);
oFile.Close();
//对byte数据串进行HMACMD5
//KeyedHashAlgorithm oHash = (KeyedHashAlgorithm)HMACMD5.Create();
//HMACMD5.Create()其实为返回一个HMACSHA1,HMACMD5没有定义Create
KeyedHashAlgorithm oHash = (KeyedHashAlgorithm)new HMACMD5();
byte[] oKey={0x31};
oHash.Key = oKey;
byte[] AInput ={ 0x31, 0x31, 0x31, 0x31 };
byte[] AOutput = oHash.ComputeHash(AInput);
还有要说的MD5与MD5CryptoServiceProvider 为什么有两个,它们之间的关系是怎样的?如果第一次用这个类库的话,真有点糊涂(此前我在糊涂ing)—“既生瑜,何生亮!”
源码之下无密码,开始反编译:
MD5.Create() —>
CryptoConfig.CreateFromName(“System.Security.Cryptography.MD5”) —>
CryptoConfig.defaultNameHT[“System.Security.Cryptography.MD5”] —>
Type type1 = (Type) typeof(MD5CryptoServiceProvider); —>
反射一个MD5CryptoServiceProvider实例
所以最终用户使用的还是MD5CryptoServiceProvider,MD5主要起到作用就是简名的作用!
还有一点疑虑关于算列就剩下了“.net是否包含md2、md4算法?”,其实也是以下代码给我的灵感的:
//MD5
Utils._CreateHash(Utils.Static ProvHandle, 0x8003, ref handle1);
this._safeHashHandle = handle1;
//SHA1
Utils._CreateHash(Utils.StaticProvHandle, 0x8004, ref handle1);
this._safeHashHandle = handle1;
是否0x8001<->MD2 , 0x8002<->MD4 ,这只是我的猜想,由于保护机制,无法在自己的类中使用SafeHashHandle 类(真不知道ms为什么不暴露出这个类呢?),但用户完全可以模仿SHA1Managed类写一个MD4类!
2.对称加密
所谓对称就是指加密解密中使用的key值是一样的,这种加密算法也是我们大家日常用的最多的加密算法了,这类加密算法一般公开, 遭受考验的也主要是key的长度,当然了你也完全写一个不公开的算法,只要能在数学上证明有一个可逆过程与其一一对应就可以了!
想象A加完密的密文发送给B,如果B想知道原文,还要根据解密算法解开才可以 ! 因此key值的保密性在这类应用中的重中之重!
对称加密要注意的地方主要就是块加密模式(这个也不是对称独有的,在非对称中也存在模式概念)!CipherMode类型定义如下:
public enum CipherMode
{
CBC = 1,
ECB = 2,
OFB = 3,
CFB = 4,
CTS = 5
}
关于CipherMode的解释见
ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.chs/cpref11/html/T_System_Security_Cryptography_CipherMode.htm
本来打算ctrl+c/ ctrl+v的,但看了半天都不知道在说什么,真不知道翻译的人是不懂呢?还是其它原因?现在只能自己写这部分了。
ECB 电子密码本
把加密串分成64bit一组,不足部分添齐(这里留到后面说),然后对每一个块单独加密,最终一块块的密文块组成密文,解密过程相反!如图:
CBC密码块链
CBC模式的出现 就是为了补救ECB模式的一些缺点(密文一样原文也一样),过程如图所示,这里就不画蛇了:
OFB 输出反溃模式
下图E’是加密函数E的一种变换,具体过程可以看书,这里主要展示的它的大至过程:
CFB 密码反馈模式
与上面的OFB类似,也是对OFB模式的一种加强,E’函数与OFB一样
CTR 记数模式
这种模式用IV加密,再与明文异或得到密文块,且下次加密块用到的IV是先前的IV加1,过程如图:
C#代码
//这样就可以实现文件或内存块的加密了,解密类似!
//这里需要注意的是:SymmetricAlgorithm默认的加密模式为CBC,见下代码:
//protected SymmetricAlgorithm ()
//{
// this.ModeValue = CipherMode.CBC;
// this.PaddingValue = PaddingMode.PKCS7;
//}
//这样当64位块一样时,出现同样的密文可能性很小!
//用户可以通过改变SymmetricAlgorithm成员ModeValue来改变加密模式来比较一下了!
//看上SymmetricAlgorithm构造函数发现pad也是可选的,后面可以看msdn,总算可以看明白了,感谢翻译!
SymmetricAlgorithm oSym = DES.Create();
MemoryStream oMem=new MemoryStream();
byte [] AKey={0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31};
byte [] AIV= {0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31};
CryptoStream oStream = new CryptoStream(oMem, oSym.CreateEncryptor(AKey,AIV), CryptoStreamMode.Write);
byte[] AInput ={ 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,0x31,0x31,0x31 };
oStream.Write(AInput, 0, AInput.Length);
oStream.Close();
byte[] AOutput=oMem.ToArray();
这里还的引用一下msdn的关于pad的描述:
ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.chs/cpref11/html/T_System_Security_Cryptography_PaddingMode.htm
ANSIX923
ANSIX923 填充字符串由一个字节序列组成,此字节序列的最后一个字节填充字节序列的长度,其余字节均填充数字零。
下面的示例演示此模式的工作原理。假定块长度为 8,数据长度为 9,则填充用八位字节数等于 7,数据等于 FF FF FF FF FF FF FF FF FF:
数据: FF FF FF FF FF FF FF FF FF
X923 填充: FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07
ISO10126
ISO10126 填充字符串由一个字节序列组成,此字节序列的最后一个字节填充字节序列的长度,其余字节填充随机数据。
下面的示例演示此模式的工作原理。假定块长度为 8,数据长度为 9,则填充用八位字节数等于 7,数据等于 FF FF FF FF FF FF FF FF FF:
数据: FF FF FF FF FF FF FF FF FF
ISO10126 填充: FF FF FF FF FF FF FF FF FF 7D 2A 75 EF F8 EF 07
None 不填充。
PKCS7
PKCS #7 填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。
下面的示例演示这些模式的工作原理。假定块长度为 8,数据长度为 9,则填充用八位字节数等于 7,数据等于 FF FF FF FF FF FF FF FF FF:
数据: FF FF FF FF FF FF FF FF FF
PKCS7 填充: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
Zeros
填充字符串由设置为零的字节组成。
以上红字部分出自《MSDN》
3.非对称加密
意指加解密的密钥是不一样的,加密一个,解密一个!一个叫公钥,一个叫私钥!加密方式的安全性要比对称的安全些,但安全不是绝对的!这种算法最主要运用场景就是数字签名!像RSA/DSA!
C#代码
//加解密数据
//生成公私钥
RSACryptoServiceProvider oRSA = new RSACryptoServiceProvider();
string privatekey=oRSA.ToXmlString(true);
string publickey=oRSA.ToXmlString(false);
byte[] AOutput;
//公钥加密
RSACryptoServiceProvider oRSA1 = new RSACryptoServiceProvider();
oRSA1.FromXmlString(publickey);
byte[] AInput={0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31};
AOutput = oRSA1.Encrypt(AInput,false);
//私钥解密
RSACryptoServiceProvider oRSA2 = new RSACryptoServiceProvider();
oRSA2.FromXmlString(privatekey);
AInput = oRSA2.Decrypt(AOutput, false);
//私钥签名
RSACryptoServiceProvider oRSA3 = new RSACryptoServiceProvider();
oRSA3.FromXmlString(privatekey);
AOutput = oRSA3.SignData(AInput, "MD5");
//公钥验证
RSACryptoServiceProvider oRSA4 = new RSACryptoServiceProvider();
oRSA4.FromXmlString(publickey);
bool bVerify= oRSA4.VerifyData(AInput, "MD5",AOutput);
这里需要提到的是DSA只能运用到数字签名和验证,加解密还的用RSA,关于最后一个参数“false:是什么意思,可以参考msdn,这里也不想添足了!
完