(一)简介
最早、最著名的保密密钥或对称密钥加密算法DES(Data Encryption Standard)是由IBM公司在70年代发展起来的,并经政府的加密标准筛选后,于1976年11月被美国政府采用,DES随后被美国国家标准局和美国国家标准协会(American National Standard Institute,ANSI)承认。 DES使用56位密钥对64位的数据块进行加密,并对64位的数据块进行16轮编码。与每轮编码时,一个48位的"每轮"密钥值由56位的完整密钥得出来。DES用软件进行解码需用很长时间,而用硬件解码速度非常快。幸运的是,当时大多数黑客并没有足够的设备制造出这种硬件设备。在1977年,人们估计要耗资两千万美元才能建成一个专门计算机用于DES的解密,而且需要12个小时的破解才能得到结果。当时DES被认为是一种十分强大的加密方法。
随着计算机硬件的速度越来越快,制造一台这样特殊的机器的花费已经降到了十万美元左右,而用它来保护十亿美元的银行,那显然是不够保险了。另一方面,如果只用它来保护一台普通服务器,那么DES确实是一种好的办法,因为黑客绝不会仅仅为入侵一个服务器而花那么多的钱破解DES密文。
另一种非常著名的加密算法就是RSA了,RSA(Rivest-Shamir-Adleman)算法是基于大数不可能被质因数分解假设的公钥体系。简单地说就是找两个很大的质数。一个对外公开的为“公钥”(Public key) ,另一个不告诉任何人,称为"私钥”(Private key)。这两个密钥是互补的,也就是说用公钥加密的密文可以用私钥解密,反过来也一样。
假设用户甲要寄信给用户乙,他们互相知道对方的公钥。甲就用乙的公钥加密邮件寄出,乙收到后就可以用自己的私钥解密出甲的原文。由于别人不知道乙的私钥,所以即使是甲本人也无法解密那封信,这就解决了信件保密的问题。另一方面,由于每个人都知道乙的公钥,他们都可以给乙发信,那么乙怎么确信是不是甲的来信呢?那就要用到基于加密技术的数字签名了。
甲用自己的私钥将签名内容加密,附加在邮件后,再用乙的公钥将整个邮件加密(注意这里的次序,如果先加密再签名的话,别人可以将签名去掉后签上自己的签名,从而篡改了签名)。这样这份密文被乙收到以后,乙用自己的私钥将邮件解密,得到甲的原文和数字签名,然后用甲的公钥解密签名,这样一来就可以确保两方面的安全了。
加密
////////////////////////// //加密函数 public string EncryptData(String strKey, String strData) { string strResult; //返回值 //1. 字符串长度不能超过90kb,否则,内存将溢出,看3就知道原因 if (strData.Length > 92160) { strResult="Error. Data String too large. Keep within 90Kb."; return strResult; } //2. 发生密码 if (!InitKey(strKey)) { strResult="Error. Fail to generate key for encryption"; return strResult; } //3. 准备字符串 // 字符串的头5个字符将被格式化后存储数据的实际长度. // 这是最简单的方法来记住数据的初始长度,不借助于复杂的计算. strData = String.Format("{0,5:00000}"+strData, strData.Length); //4. 加密数据 byte[] rbData = new byte[strData.Length]; ASCIIEncoding aEnc = new ASCIIEncoding(); aEnc.GetBytes(strData, 0, strData.Length, rbData, 0); DESCryptoServiceProvider descsp = new DESCryptoServiceProvider(); ICryptoTransform desEncrypt = descsp.CreateEncryptor(m_Key, m_IV); //5. 流: // mOut 是输出流. // mStream 是输入流. // cs 是转换流 MemoryStream mStream = new MemoryStream(rbData); CryptoStream cs = new CryptoStream(mStream, desEncrypt, CryptoStreamMode.Read); MemoryStream mOut = new MemoryStream(); //6. 开始实施加密 int bytesRead; byte[] output = new byte[1024]; do { bytesRead = cs.Read(output,0,1024); if (bytesRead != 0) mOut.Write(output,0,bytesRead); } while (bytesRead > 0); //7. 返回加密结果在base64编码之后 // 在这种情况,实际结果是转换成base64编码以至它能被HTTP协议传输而不发生损坏. if (mOut.Length == 0) strResult = ""; else strResult = Convert.ToBase64String(mOut.GetBuffer(), 0, (int)mOut.Length); return strResult; } |
解密
//解密函数 public string DecryptData(String strKey, String strData) { string strResult; //1. 用来解密的密钥 if (!InitKey(strKey)) { strResult="Error. Fail to generate key for decryption"; return strResult; } //2. 提供初始化服务 int nReturn = 0; DESCryptoServiceProvider descsp = new DESCryptoServiceProvider(); ICryptoTransform desDecrypt = descsp.CreateDecryptor(m_Key, m_IV); //3. 预备流: // mOut 是输出流. // cs 是转换流. MemoryStream mOut = new MemoryStream(); CryptoStream cs = new CryptoStream(mOut, desDecrypt, CryptoStreamMode.Write); //4. 记着将base64编码恢复到到字节数组存在最初的数据流 byte[] bPlain = new byte[strData.Length]; try { bPlain = Convert.FromBase64CharArray(strData.ToCharArray(), 0, strData.Length); } catch (Exception) { strResult = "Error. Input Data is not base64 encoded."; return strResult; } long lRead = 0; long lTotal = strData.Length; try { //5. 实施解码 while (lTotal >= lRead) { cs.Write(bPlain,0,(int)bPlain.Length); //descsp.BlockSize=64 lRead = mOut.Length + Convert.ToUInt32(((bPlain.Length / descsp.BlockSize) * descsp.BlockSize)); }; ASCIIEncoding aEnc = new ASCIIEncoding(); strResult = aEnc.GetString(mOut.GetBuffer(), 0, (int)mOut.Length); //6. 将字符串整齐化,返回成只含有有实际意义的数据 // 记着在加密函数中,头5个字符指示了实际数据的长度 // 这是最简单的方法来记着最初数据的长度,不用借助任何复杂的计算 String strLen = strResult.Substring(0,5); int nLen = Convert.ToInt32(strLen); strResult = strResult.Substring(5, nLen); nReturn = (int)mOut.Length; return strResult; } catch (Exception) { strResult = "Error. Decryption Failed. Possibly due to incorrect Key or corrputed data"; return strResult; } } |
KEY
///////////////////////////////////////////////////////////// //私有函数将生成keys成为成员变量 static private bool InitKey(String strKey) { try { // 将key转换成字节数组 byte[] bp = new byte[strKey.Length]; ASCIIEncoding aEnc = new ASCIIEncoding(); aEnc.GetBytes(strKey, 0, strKey.Length, bp, 0); //用SHA1来哈希key SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider(); byte[] bpHash = sha.ComputeHash(bp); int i; // 使用低64位作为key值 for (i=0; i<8; i++) m_Key[i] = bpHash[i]; for (i=8; i<16; i++) m_IV[i-8] = bpHash[i]; return true; } catch (Exception) { //错误操作 return false; } } |
调用
FE_Symmetric Crypt; Crypt = new FE_Symmetric(); string tempAddress =textBox1.Text; this.textBox2.Text = Crypt.EncryptData("42", tempAddress); //提供服务方加密过程,得到sn,显示在textBox2中 this.textBox2.Text = Crypt. DecryptData("42", tempAddress); |
一定要先加密再解密,而且加密和解密的密码要一样!