标签:
这两天在捣鼓 RSA 加密的问题.
WebService 一直使用的是明文传递账号密码.. 实在是受不了. 于是觉得还是加密一下.
由于一直没有使用过RSA,所以我提议用了RSA做。 然后就做了.
首先RSA是非对称加密.
会生成 密钥a 和 密钥b.
用a 加密 用b解密,反之亦然. 这样就解决了安全性问题.
至于RSA算法的原理。 可以去阮一峰的博客上看. 深入浅出。很是厉害.
.net 自己有RSA加密的库,使用起来也比较简单.
生成公钥和私钥.
//声明一个RSA算法的实例,由RSACryptoServiceProvider类型的构造函数指定了密钥长度为1024位 //实例化RSACryptoServiceProvider后,RSACryptoServiceProvider会自动生成密钥信息。 rsaProvider = new RSACryptoServiceProvider(1024); //将RSA算法的公钥导出到字符串PublicKey中,参数为false表示不导出私钥 PublicKey = rsaProvider.ToXmlString(false); //将RSA算法的私钥导出到字符串PrivateKey中,参数为true表示导出私钥 PrivateKey = rsaProvider.ToXmlString(true);
接下来就是加密和解密
1 public static byte[] EncryptData(byte[] data) 2 { 3 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024); 4 //将公钥导入到RSA对象中,准备加密; 5 //rsa.FromXmlString(PublicKey); 6 rsa.FromXmlString(PrivateKey); 7 //对数据data进行加密,并返回加密结果; 8 //第二个参数用来选择Padding的格式 9 return rsa.Encrypt(data, false); 10 } 11 12 public static byte[] DecryptData(byte[] data) 13 { 14 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024); 15 //将私钥导入RSA中,准备解密; 16 //rsa.FromXmlString(PrivateKey); 17 rsa.FromXmlString(PublicKey); 18 //对数据进行解密,并返回解密结果; 19 return rsa.Decrypt(data, false); 20 }
其实到这里。第一个需求就已经搞定了。
公钥发给发送者.
然后这边用私钥解密. 就OK了.
至于传递会将 byte[] 转成Base64.
其中遇到了一个问题。
Base64在传递时, + 号变空格。
我这里比较偷懒,replace即可.
由于是非对称解密,有时候验证也可以用RSA来做.
私钥加密公钥解密。
私钥只有我一个人有。 所以能确定只要你用公钥能解开就相当于一次验证.
可是在用 .net 自带测试的时候报错了
说好的非对称呢.. 为什么会这样.
网上说是 .net 算法问题.
于是就反编译了一下源码看了下.
公钥
1 <?xml version="1.0"?> 2 <RSAKeyValue> 3 <Modulus>0Avy88U8M1rLqrO/Vk9eIbGUDLQZ1jPk5EvbA4IHTrp+5OnRzvwd8CV0YDroDLcw6J1P0Cw2gjjyIGuRqKw9ws/0vhDaNliJUsO/i6eTzcRVgBXHWtJ996dO6CgoCgIw/SOJCFv3oY9SzJXmMwbEjYeWKKOC8OX4uwxpGw30gqc=</Modulus> 4 <Exponent>AQAB</Exponent> 5 </RSAKeyValue>
私钥
1 <?xml version="1.0"?> 2 <RSAKeyValue> 3 <Modulus>0Avy88U8M1rLqrO/Vk9eIbGUDLQZ1jPk5EvbA4IHTrp+5OnRzvwd8CV0YDroDLcw6J1P0Cw2gjjyIGuRqKw9ws/0vhDaNliJUsO/i6eTzcRVgBXHWtJ996dO6CgoCgIw/SOJCFv3oY9SzJXmMwbEjYeWKKOC8OX4uwxpGw30gqc=</Modulus> 4 <Exponent>AQAB</Exponent> 5 <P>6HD3+ubvGyvE3Ech+OO6/ZMjkkt82S06h3Dk6YfL1eXkHcakPf+U3oUutYx/NxvZyg/e9Mp+KZgmsflM1rVA0w==</P> 6 <Q>5SIGvkG6KW9OOgkLZcdjEnXTFHSMiMzaJy3FJ3gyGuAiJLsa0CX0HRWulEUaV/u3OpeDQouIyXIjmIMHlQpyXQ==</Q> 7 <DP>KKjaOAF9gfs+DGpE/wyXARRj/ItH45WNz3NoF5GxjlEQfkTpJg83M1WIvik9d55fkoEENz3Uo+IBotBBKK28EQ==</DP> 8 <DQ>AFtLM2Say5G2x3RYJjJnPxIb3/5GcbgP5tu1YNhZC52pr/Dym7xTYvAzs1tgLR7hLCAsPiBFeDrLP2OE0YCQqQ==</DQ> 9 <InverseQ>uYX674j70WN2r5f3+aj7chyijctpNuSv4JZF2zApKxF3yPw3fTTrOeePZoubtt6AydB5oKflkvdTol8Ml7ag2A==</InverseQ> 10 <D>INFht7ZrMqal7f2Atzq53JLIieB3GuUAvEqC9+CxCmg80BtaL05x4onl+7APHsJfArKd/naa+pvFBfwx8+uHqkSX6rkIlvqH4J+ZK8RQgDbuw9cxzlTzWQBlvMWmWZD90IfawGN4OsxCfYsAzNyl+wckZ0R1KUpa9oqAsSyxK/E=</D> 11 </RSAKeyValue>
以下是C#源码
首先
rsaProvider = new RSACryptoServiceProvider(1024);
是来源于密封类 RSACryptoServiceProvider
[ComVisible(true)] public sealed class RSACryptoServiceProvider : RSA, ICspAsymmetricAlgorithm { [SecuritySafeCritical] public RSACryptoServiceProvider(int dwKeySize) : this(dwKeySize, new CspParameters(0x18, null, null, s_UseMachineKeyStore), false) { } }
生成公钥密钥 ToXmlString
1 //将RSA算法的公钥导出到字符串PublicKey中,参数为false表示不导出私钥 2 PublicKey = rsaProvider.ToXmlString(false); 3 //将RSA算法的私钥导出到字符串PrivateKey中,参数为true表示导出私钥 4 PrivateKey = rsaProvider.ToXmlString(true);
1 public override string ToXmlString(bool includePrivateParameters) 2 { 3 RSAParameters parameters = this.ExportParameters(includePrivateParameters); 4 StringBuilder builder = new StringBuilder(); 5 builder.Append("<RSAKeyValue>"); 6 builder.Append("<Modulus>" + Convert.ToBase64String(parameters.Modulus) + "</Modulus>"); 7 builder.Append("<Exponent>" + Convert.ToBase64String(parameters.Exponent) + "</Exponent>"); 8 if (includePrivateParameters) 9 { 10 builder.Append("<P>" + Convert.ToBase64String(parameters.P) + "</P>"); 11 builder.Append("<Q>" + Convert.ToBase64String(parameters.Q) + "</Q>"); 12 builder.Append("<DP>" + Convert.ToBase64String(parameters.DP) + "</DP>"); 13 builder.Append("<DQ>" + Convert.ToBase64String(parameters.DQ) + "</DQ>"); 14 builder.Append("<InverseQ>" + Convert.ToBase64String(parameters.InverseQ) + "</InverseQ>"); 15 builder.Append("<D>" + Convert.ToBase64String(parameters.D) + "</D>"); 16 } 17 builder.Append("</RSAKeyValue>"); 18 return builder.ToString(); 19 }
1 [SecuritySafeCritical] 2 public override RSAParameters ExportParameters(bool includePrivateParameters) 3 { 4 this.GetKeyPair(); 5 if (includePrivateParameters && !CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) 6 { 7 KeyContainerPermission permission = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags); 8 KeyContainerPermissionAccessEntry accessEntry = new KeyContainerPermissionAccessEntry(this._parameters, KeyContainerPermissionFlags.Export); 9 permission.AccessEntries.Add(accessEntry); 10 permission.Demand(); 11 } 12 RSACspObject cspObject = new RSACspObject(); 13 int blobType = includePrivateParameters ? 7 : 6; 14 Utils._ExportKey(this._safeKeyHandle, blobType, cspObject); 15 return RSAObjectToStruct(cspObject); 16 }
1 [MethodImpl(MethodImplOptions.InternalCall), SecurityCritical] 2 internal static extern void _ExportKey(SafeKeyHandle hKey, int blobType, object cspObject);
找到这里就卡住了。
具网上说。是由于.net 算法问题导致。
网上有很多自己学的RSA算法类,基本使用时没有问题。
可是当位数上去. .net 最长Int64. 超出只能使用 biginteger。
biginteger 以前在项目中使用过,性能实在是不敢恭维.
而且目测在客户端调用的时候也会出问题。
比如JAVA 默认应该是无填充模式。 .net 是随机填充。
到时候和JAVA的同事一起测试一下吧.
标签:
原文地址:http://www.cnblogs.com/HeyTommy/p/4414061.html