写应用的时候遇到个服务器返回私钥加密过的数据 ,然后要在客户端用公钥解密的需求 ,一直没找到方法,应用搁置了一个学期,多方搜索,结论就是.net没有实现公钥解密的方法,要自己实现,于是硬着头皮开始看 portable.bouncycastle
关于RSA的原理,这是我从MSDN盗的图,链接在这https://msdn.microsoft.com/zh-cn/library/system.security.cryptography.rsaparameters.aspx
简单说就是
密文 = (明文 ^privateExponent) mod modulus
明文 = (密文 ^publicExponent) mod modulus
公钥中含有两个参数 一个是modulus ,另一个是publicExponent,私钥中有 modulus和privateExponent两个参数(当然私钥中不止这两个参数,但方法里只用到这两个,其他不管)
由于拿到的公钥和私钥都是PEM格式的,所以要先从PEM格式的公钥和私钥中提取这些参数 ,然后进行大数运算就能得出结果
这里要感谢前辈的努力,详细的解析了PEM文件格式
现在假设假设公钥和私钥分别为
1 const string PUBLICKEY = 2 @"-----BEGIN PUBLIC KEY----- 3 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpsDr+W45aFHIkvotZaGK/THlF 4 FpuZfUtghhWkHAm3H7yvL42J4xHrTr6IeUDCl4eKe6qiIgvYSNoL3u4SERGOeYmV 5 1F+cocu9IMGnNoicbh1zVW6e8/iGT3xaYQizJoVuWA/TC/zdds2ihCJfHDBDsouO 6 CXecPapyWCGQNsH5sQIDAQAB 7 -----END PUBLIC KEY-----"; 8 const string PRIVATEKEY = 9 @"-----BEGIN RSA PRIVATE KEY----- 10 MIICXQIBAAKBgQDpsDr+W45aFHIkvotZaGK/THlFFpuZfUtghhWkHAm3H7yvL42J 11 4xHrTr6IeUDCl4eKe6qiIgvYSNoL3u4SERGOeYmV1F+cocu9IMGnNoicbh1zVW6e 12 8/iGT3xaYQizJoVuWA/TC/zdds2ihCJfHDBDsouOCXecPapyWCGQNsH5sQIDAQAB 13 AoGBAM/JbFs4y5WbMncrmjpQj+UrOXVOCeLrvrc/4kQ+zgCvTpWywbaGWiuRo+cz 14 cXrVQ6bGGU362e9hr8f4XFViKemDL4SmJbgSDa1K71i+/LnnzF6sjiDBFQ/jA9SK 15 4PYrY7a3IkeBQnJmknanykugyQ1xmCjbuh556fOeRPaHnhx1AkEA/flrxJSy1Z+n 16 Y1RPgDOeDqyG6MhwU1Jl0yJ1sw3Or4qGRXhjTeGsCrKqV0/ajqdkDEM7FNkqnmsB 17 +vPd116J6wJBAOuNY3oOWvy2fQ32mj6XV+S2vcG1osEUaEuWvEgkGqJ9co6100Qp 18 j15036AQEEDqbjdqS0ShfeRSwevTJZIap9MCQCeMGDDjKrnDA5CfB0YiQ4FrchJ7 19 a6o90WdAHW3FP6LsAh59MZFmC6Ea0xWHdLPz8stKCMAlVNKYPRWztZ6ctQMCQQC8 20 iWbeAy+ApvBhhMjg4HJRdpNbwO6MbLEuD3CUrZFEDfTrlU2MeVdv20xC6ZiY3Qtq 21 /4FPZZNGdZcSEuc3km5RAkApGkZmWetNwDJMcUJbSBrQMFfrQObqMPBPe+gEniQq 22 Ttwu1OULHlmUg9eW31wRI2uiXcFCJMHuro6iOQ1VJ4Qs 23 -----END RSA PRIVATE KEY-----";
于是获取公钥参数的方法为
1 // 获取modulus和publicExponent 2 string publicKey = PUBLICKEY.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", ""); 3 byte[] btPem = Convert.FromBase64String(publicKey); 4 int pemModulus = 128, pemPublicExponent = 3; 5 byte[] btPemModulus = new byte[128]; 6 byte[] btPemPublicExponent = new byte[3]; 7 for (int i = 0; i < pemModulus; i++) 8 { 9 btPemModulus[i] = btPem[29 + i]; 10 } 11 for (int i = 0; i < pemPublicExponent; i++) 12 { 13 btPemPublicExponent[i] = btPem[159 + i]; 14 }
公钥解密的方法为
1 BigInteger biModulus = new BigInteger(1, btPemModulus); 2 BigInteger biExponent = new BigInteger(1, btPemPublicExponent); 3 RsaKeyParameters publicParameters = new RsaKeyParameters(false, biModulus, biExponent); 4 IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine()); 5 eng.Init(false, publicParameters); 6 // 解密已加密的数据 7 byte[] encryptedData = Convert.FromBase64String(rawData); 8 encryptedData = eng.ProcessBlock(encryptedData, 0, encryptedData.Length); 9 string result = Encoding.UTF8.GetString(encryptedData, 0, encryptedData.Length);
公钥加密的方法为
1 BigInteger biModulus = new BigInteger(1, btPemModulus); 2 BigInteger biExponent = new BigInteger(1, btPemPublicExponent); 3 RsaKeyParameters publicParameters = new RsaKeyParameters(false, biModulus, biExponent); 4 IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine()); 5 eng.Init(true, publicParameters); 6 // 加密数据 7 byte[] encryptData = Encoding.UTF8.GetBytes(rawData); 8 encryptData = eng.ProcessBlock(encryptData, 0, encryptData.Length); 9 string result = Convert.ToBase64String(encryptData);
私钥的通过PEM文件格式详细解析里的图也可以方便的写出来,mark下以后写……( ̄o ̄) . z Z
顺便贴上WP 8.1里自带的RSA公钥加密 私钥解密
1 /// <summary> 2 /// WPRT的RSA公钥加密 3 /// </summary> 4 /// <param name="rawData">源数据</param> 5 /// <returns>加密后的数据</returns> 6 public static string PublicEncrypt(string rawData) 7 { 8 try 9 { 10 /*将文本转换成IBuffer*/ 11 IBuffer bufferRawData = CryptographicBuffer.ConvertStringToBinary(rawData, BinaryStringEncoding.Utf8); 12 13 /*加密算法提供程序*/ 14 AsymmetricKeyAlgorithmProvider provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm 15 (AsymmetricAlgorithmNames.RsaPkcs1); 16 17 /*导入公钥*/ 18 string PUBLIC_KEY = PUBLICKEY.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", ""); 19 CryptographicKey publicKey = provider.ImportPublicKey(CryptographicBuffer.DecodeFromBase64String(PUBLIC_KEY)); 20 21 //加密 22 IBuffer result = CryptographicEngine.Encrypt(publicKey, bufferRawData, null); 23 byte[] res; 24 CryptographicBuffer.CopyToByteArray(result, out res); 25 Debug.WriteLine("WinRT公钥加密后:" + Convert.ToBase64String(res)); 26 return Convert.ToBase64String(res); 27 } 28 catch (Exception e) 29 { 30 Debug.WriteLine("Encrypt Exception:" + e.StackTrace); 31 return rawData; 32 } 33 } 34 35 /// <summary> 36 /// WPRT的RSA私钥解密 37 /// </summary> 38 /// <param name="rawData"></param> 39 /// <returns></returns> 40 public static string PrivateDecrypt(string rawData) 41 { 42 try 43 { 44 /*将文本转换成IBuffer*/ 45 IBuffer bufferRawData = CryptographicBuffer.ConvertStringToBinary(rawData, BinaryStringEncoding.Utf8); 46 47 /*加密算法提供程序*/ 48 AsymmetricKeyAlgorithmProvider provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm 49 (AsymmetricAlgorithmNames.RsaPkcs1); 50 51 /*导入私钥*/ 52 string PRIVATE_KEY = PRIVATEKEY.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", ""); 53 CryptographicKey privateKey = provider.ImportKeyPair(CryptographicBuffer.DecodeFromBase64String(PRIVATE_KEY)); 54 55 //解密 56 IBuffer result = CryptographicEngine.Decrypt(privateKey, bufferRawData, null); 57 byte[] res; 58 CryptographicBuffer.CopyToByteArray(result, out res); 59 Debug.WriteLine("WinRT私钥解密后:" + Encoding.UTF8.GetString(res,0,res.Length)); 60 return Encoding.UTF8.GetString(res,0,res.Length); 61 } 62 catch (Exception e) 63 { 64 Debug.WriteLine("Decrypt Exception:" + e.StackTrace); 65 return rawData; 66 } 67 }
参考链接