原文: 非对称加密算法RSA使用注意事项
第一个问题,也是最重要的一个——RSA无法对超过117字节的数据进行加密!切记!其实也勿需要求对更大数据的加密,虽然网上已经有相关解决方案,比如BigInteger项目。但这点确实需要注意,如果对大于117字节的数据加密就会抛异常出来,说法还有点莫名其妙。考虑下RSA的主要用途就可以理解了,一般我们使用RSA的主要用途是进行数字签名,另外就是对“对称加密”算法的KEY和IV向量进行加密;
第二个问题,假设要对一个文本文件(比如xml文件)中的某些数据进行加密,加密后再写入文本文件怎么办呢?(如果将加密后的byte数组直接以流的形式写入文件,则无此问题)这就涉及到一个byte[]到String的转换问题,有的人马上会说,这简单嘛,用Encoding.Default.GetString呗,果真如此的话,也就没有本问题了!如果你使用Encoding.Default.GetString保存加密结果到文件中,再解密的话你就会遇到下面这个异常:
未处理 System.Security.Cryptography.CryptographicException Message="不正确的数据。/r/n" Source="mscorlib" StackTrace: 在 System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr) 在 System.Security.Cryptography.Utils._DecryptKey(SafeKeyHandle hPubKey, Byte[] key, Int32 dwFlags) 在 System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP) 在 crse3363ae_lab01.Program.Decrypt() 位置 D:/Training/dotNet Framework 2.0/示例程序/crse3363ae_lab01/crse3363ae_lab01/crse3363ae_lab01/Program.cs:行号 286 在 crse3363ae_lab01.Program.Main() 位置 D:/Training/dotNet Framework 2.0/示例程序/crse3363ae_lab01/crse3363ae_lab01/crse3363ae_lab01/Program.cs:行号 56 在 System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) 在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ThreadHelper.ThreadStart_Context(Object state) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 在 System.Threading.ThreadHelper.ThreadStart() InnerException:
原因是因为使用Encoding.Default.GetString()对加密后的byte[](为了后文方便,此处赋予其一个变量名right)进行处理后,再写入文本文件,解密的时候再使用Encoding.Default.GetBytes()对将加密内容(String类型)转换得到byte[]数组,这个时候得到的byte[]数组(变量名:wrong)已经不是前文的那个right变量来,内容和大小都不同!你拿一个错误的字符串去解密当然会报“不正确的数据”了,确实不正确嘛!
呵呵!下面说一下如何解决这个问题(下面只提供问题相关的代码):
1)加密
byte[] value = rsa.Encrypt(Encoding.Default.GetBytes(temp), false); //用公钥加密 var stringBuilder = new StringBuilder(); //声明一个变量,存放byte[]转换后的字符 for (int i = 0; i < value.Length; i++) { stringBuilder.Append(value[i].ToString("x2")); //x2是转换为两位的16进制数,转换后的长度为加密长度的两倍:256位 } SaveToFile("1.dat", stringBuilder.ToString()); //写入文件
2)解密
byte[] tmp = GetBytes(ReadFromFile("1.dat")); //GetBytes函数后面提供 byte[] value = rsa.Decrypt(tmp, false); //使用私钥正常解密,再也没有烦人的数据不正确错误了 Console.WriteLine(Encoding.Default.GetString(value));//显示解密后的数据 GetBytes函数如下: private static byte[] GetBytes(string hexStr) { var rtnByteArray = new byte[hexStr.Length/2];//建立一个byte数组 int j = 0; for (int i = 0; i < hexStr.Length; i = i + 2) { string tmp = hexStr.Substring(i, 2);//每读取两位然后转换为十进制 rtnByteArray[j++] = Convert.ToByte(Convert.ToInt32(tmp, 16));//转换为byte类型 } return rtnByteArray; }
好了,现在一切OK!!顺便说一下,RSA无法对超过128 BYTE的数据进行解密。
后记,今天突然想到可以Base64编码,看来前面绕路了,下面我们使用Base64编码再来实现一次,非常简单:
1)加密
byte[] value = rsa.Encrypt(Encoding.Default.GetBytes(kvp.Value), false); enPatient.Add(Convert.ToBase64String(value));
2)解密
byte[] value = rsa.Decrypt(Convert.FromBase64String(kvp.Value), false); dePatient.Add(Encoding.Default.GetString(value));