寫應用的時候遇到個服務器返回私鑰加密過的數據 ,然后要在客戶端用公鑰解密的需求 ,一直沒找到方法,應用擱置了一個學期,多方搜索,結論就是.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 }
參考鏈接