首先上资源
jsencrypt.js下载地址:https://github.com/travist/jsencrypt
第三方Rsa密钥生成工具:BouncyCastle.Crypto.dll,直接可以在NuGet中查找。
至于为什么用第三方工具生成密钥,是为了和jsencrypt配合。c#本身RSACryptoServiceProvider类生成的工具不能再jsencrypt中使用。
有关知识:http://www.cnblogs.com/dudu/p/dotnet-core-rsa-openssl.html
并且:(信息来源:https://www.jianshu.com/p/f22b4e565ec1)文中的生成RSAParameters方法来源于此。
-
RSACryptoServiceProvider
在Windows 环境下依然可以使用RSACryptoServiceProvider
, 但在Linux 环境下编译不过. 参考 dudu 的文章 .net core中使用openssl的公钥私钥进行加解密 -
FromXmlString方法和ToXmlString
由于不在使用RSACryptoServiceProvider
这两个方法不在提供,我们可以通过扩展方法来添加这两个方法,以处理C#生成的密钥.
这边引用BouncyCastle.Crypto.dll会在NuGet里有个警告提示,如图:
我在Centos7,和windows10 里测试过,可以使用,其他就不懂了。
这是BouncyCastle.Crypto.dll在NuGet相关信息:
好了开始上代码。
使用BouncyCastle.Crypto.dll生成PEM密钥字符串
1 public static RSAKey GetKey() 2 { 3 var key = new RSAKey(); 4 Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator g = new Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator(); 5 g.Init(new Org.BouncyCastle.Crypto.KeyGenerationParameters(new SecureRandom(), 1024)); 6 var pair = g.GenerateKeyPair(); 7 8 9 10 TextWriter textWriter = new StringWriter(); 11 PemWriter pemWriter = new PemWriter(textWriter); 12 pemWriter.WriteObject(pair.Private); 13 pemWriter.Writer.Flush(); 14 15 string privateKey = textWriter.ToString(); 16 key.privateKey = privateKey; 17 18 19 TextWriter textpubWriter = new StringWriter(); 20 PemWriter pempubWriter = new PemWriter(textpubWriter); 21 pempubWriter.WriteObject(pair.Public); 22 pempubWriter.Writer.Flush(); 23 string pubKey = textpubWriter.ToString(); 24 key.publicKey = pubKey; 25 26 27 28 #region 使用该部分代码偶尔会在解析私钥时候发生“不正常数据”异常。 29 //PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(pair.Private); 30 //byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetDerEncoded(); 31 //key.privateKey = Convert.ToBase64String(serializedPrivateBytes);//PEM秘钥 32 33 //SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pair.Public); 34 //byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded(); 35 //key.publicKey = Convert.ToBase64String(serializedPublicBytes);//PEM公钥 36 #endregion 37 38 return key; 39 }
然后是将字符串转换为Pem密钥
1 #region 解析 2 private static RSAParameters CreateRsaFromPrivateKey(string privateKey) 3 { 4 string tmp = privateKey.Replace(" ", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("-----BEGIN RSA PRIVATE KEY-----", ""); 5 var privateKeyBits = System.Convert.FromBase64String(tmp); 6 var RSAparams = new RSAParameters(); 7 8 using (var binr = new BinaryReader(new MemoryStream(privateKeyBits))) 9 { 10 byte bt = 0; 11 ushort twobytes = 0; 12 twobytes = binr.ReadUInt16(); 13 if (twobytes == 0x8130) 14 binr.ReadByte(); 15 else if (twobytes == 0x8230) 16 binr.ReadInt16(); 17 else 18 throw new Exception("Unexpected value read binr.ReadUInt16()"); 19 20 twobytes = binr.ReadUInt16(); 21 if (twobytes != 0x0102) 22 throw new Exception("Unexpected version"); 23 24 bt = binr.ReadByte(); 25 if (bt != 0x00) 26 throw new Exception("Unexpected value read binr.ReadByte()"); 27 28 RSAparams.Modulus = binr.ReadBytes(GetIntegerSize(binr)); 29 RSAparams.Exponent = binr.ReadBytes(GetIntegerSize(binr)); 30 RSAparams.D = binr.ReadBytes(GetIntegerSize(binr)); 31 RSAparams.P = binr.ReadBytes(GetIntegerSize(binr)); 32 RSAparams.Q = binr.ReadBytes(GetIntegerSize(binr)); 33 RSAparams.DP = binr.ReadBytes(GetIntegerSize(binr)); 34 RSAparams.DQ = binr.ReadBytes(GetIntegerSize(binr)); 35 RSAparams.InverseQ = binr.ReadBytes(GetIntegerSize(binr)); 36 } 37 return RSAparams; 38 } 39 40 private static int GetIntegerSize(BinaryReader binr) 41 { 42 byte bt = 0; 43 byte lowbyte = 0x00; 44 byte highbyte = 0x00; 45 int count = 0; 46 bt = binr.ReadByte(); 47 if (bt != 0x02) 48 return 0; 49 bt = binr.ReadByte(); 50 51 if (bt == 0x81) 52 count = binr.ReadByte(); 53 else 54 if (bt == 0x82) 55 { 56 highbyte = binr.ReadByte(); 57 lowbyte = binr.ReadByte(); 58 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; 59 count = BitConverter.ToInt32(modint, 0); 60 } 61 else 62 { 63 count = bt; 64 } 65 66 while (binr.ReadByte() == 0x00) 67 { 68 count -= 1; 69 } 70 binr.BaseStream.Seek(-1, SeekOrigin.Current); 71 return count; 72 } 73 74 private static RSAParameters CreateRsaFromPublicKey(string publicKeyString) 75 { 76 byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; 77 byte[] x509key; 78 byte[] seq = new byte[15]; 79 int x509size; 80 81 var tmp = publicKeyString.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace(" ", ""); 82 83 x509key = Convert.FromBase64String(tmp); 84 x509size = x509key.Length; 85 86 using (var mem = new MemoryStream(x509key)) 87 { 88 using (var binr = new BinaryReader(mem)) 89 { 90 byte bt = 0; 91 ushort twobytes = 0; 92 93 twobytes = binr.ReadUInt16(); 94 if (twobytes == 0x8130) 95 binr.ReadByte(); 96 else if (twobytes == 0x8230) 97 binr.ReadInt16(); 98 else 99 return new RSAParameters(); 100 101 seq = binr.ReadBytes(15); 102 if (!CompareBytearrays(seq, SeqOID)) 103 return new RSAParameters(); 104 105 twobytes = binr.ReadUInt16(); 106 if (twobytes == 0x8103) 107 binr.ReadByte(); 108 else if (twobytes == 0x8203) 109 binr.ReadInt16(); 110 else 111 return new RSAParameters(); 112 113 bt = binr.ReadByte(); 114 if (bt != 0x00) 115 return new RSAParameters(); 116 117 twobytes = binr.ReadUInt16(); 118 if (twobytes == 0x8130) 119 binr.ReadByte(); 120 else if (twobytes == 0x8230) 121 binr.ReadInt16(); 122 else 123 return new RSAParameters(); 124 125 twobytes = binr.ReadUInt16(); 126 byte lowbyte = 0x00; 127 byte highbyte = 0x00; 128 129 if (twobytes == 0x8102) 130 lowbyte = binr.ReadByte(); 131 else if (twobytes == 0x8202) 132 { 133 highbyte = binr.ReadByte(); 134 lowbyte = binr.ReadByte(); 135 } 136 else 137 return new RSAParameters(); 138 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; 139 int modsize = BitConverter.ToInt32(modint, 0); 140 141 int firstbyte = binr.PeekChar(); 142 if (firstbyte == 0x00) 143 { 144 binr.ReadByte(); 145 modsize -= 1; 146 } 147 148 byte[] modulus = binr.ReadBytes(modsize); 149 150 if (binr.ReadByte() != 0x02) 151 return new RSAParameters(); 152 int expbytes = (int)binr.ReadByte(); 153 byte[] exponent = binr.ReadBytes(expbytes); 154 var rsaKeyInfo = new RSAParameters 155 { 156 Modulus = modulus, 157 Exponent = exponent 158 }; 159 return rsaKeyInfo; 160 } 161 162 } 163 } 164 165 private static bool CompareBytearrays(byte[] a, byte[] b) 166 { 167 if (a.Length != b.Length) 168 return false; 169 int i = 0; 170 foreach (byte c in a) 171 { 172 if (c != b[i]) 173 return false; 174 i++; 175 } 176 return true; 177 } 178 #endregion
C#后端加密解密方法
1 //RSA加密 2 public static string RSAEncrypt(string context, string publicKey) 3 { 4 UTF8Encoding ByteConverter = new UTF8Encoding(); 5 byte[] DataToEncrypt = ByteConverter.GetBytes(context); 6 try 7 { 8 var rsa = RSA.Create(); 9 rsa.ImportParameters(CreateRsaFromPublicKey(publicKey)); 10 11 byte[] bytes = rsa.Encrypt(DataToEncrypt, RSAEncryptionPadding.Pkcs1); 12 string str = Convert.ToBase64String(bytes); 13 return str; 14 } 15 catch (CryptographicException e) 16 { 17 throw e; 18 } 19 } 20 21 //RSA解密 22 public static string RSADecrypt(string context, string privateKey) 23 { 24 byte[] DataToDecrypt = Convert.FromBase64String(context); 25 try 26 { 27 var rsa = RSA.Create(); 28 rsa.ImportParameters(CreateRsaFromPrivateKey(privateKey)); 29 30 byte[] bytes = rsa.Decrypt(DataToDecrypt, RSAEncryptionPadding.Pkcs1); 31 UTF8Encoding ByteConverter = new UTF8Encoding(); 32 string str = ByteConverter.GetString(bytes); 33 return str; 34 } 35 catch (CryptographicException e) 36 { 37 return null; 38 throw e; 39 } 40 }
ok以上就是后端代码。
前段代码就简单了,这个是jsencrypt官方的demo。
<!doctype html> <html> <head> <title>JavaScript RSA Encryption</title> <script src="http://code.jquery.com/jquery-1.8.3.min.js"></script> <script src="bin/jsencrypt.min.js"></script> <script type="text/javascript"> // Call this code when the page is done loading. $(function() { // Run a quick encryption/decryption when they click. $('#testme').click(function() { // Encrypt with the public key... var encrypt = new JSEncrypt(); encrypt.setPublicKey($('#pubkey').val()); var encrypted = encrypt.encrypt($('#input').val()); // Decrypt with the private key... var decrypt = new JSEncrypt(); decrypt.setPrivateKey($('#privkey').val()); var uncrypted = decrypt.decrypt(encrypted); // Now a simple check to see if the round-trip worked. if (uncrypted == $('#input').val()) { alert('It works!!!'); } else { alert('Something went wrong....'); } }); }); </script> </head> <body> <label for="privkey">Private Key</label><br/> <textarea id="privkey" rows="15" cols="65">-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDlOJu6TyygqxfWT7eLtGDwajtNFOb9I5XRb6khyfD1Yt3YiCgQ WMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76xFxdU6jE0NQ+Z+zEdhUTooNR aY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4gwQco1KRMDSmXSMkDwIDAQAB AoGAfY9LpnuWK5Bs50UVep5c93SJdUi82u7yMx4iHFMc/Z2hfenfYEzu+57fI4fv xTQ//5DbzRR/XKb8ulNv6+CHyPF31xk7YOBfkGI8qjLoq06V+FyBfDSwL8KbLyeH m7KUZnLNQbk8yGLzB3iYKkRHlmUanQGaNMIJziWOkN+N9dECQQD0ONYRNZeuM8zd 8XJTSdcIX4a3gy3GGCJxOzv16XHxD03GW6UNLmfPwenKu+cdrQeaqEixrCejXdAF z/7+BSMpAkEA8EaSOeP5Xr3ZrbiKzi6TGMwHMvC7HdJxaBJbVRfApFrE0/mPwmP5 rN7QwjrMY+0+AbXcm8mRQyQ1+IGEembsdwJBAN6az8Rv7QnD/YBvi52POIlRSSIM V7SwWvSK4WSMnGb1ZBbhgdg57DXaspcwHsFV7hByQ5BvMtIduHcT14ECfcECQATe aTgjFnqE/lQ22Rk0eGaYO80cc643BXVGafNfd9fcvwBMnk0iGX0XRsOozVt5Azil psLBYuApa66NcVHJpCECQQDTjI2AQhFc1yRnCU/YgDnSpJVm1nASoRUnU8Jfm3Oz uku7JUXcVpt08DFSceCEX9unCuMcT72rAQlLpdZir876 -----END RSA PRIVATE KEY-----</textarea><br/> <label for="pubkey">Public Key</label><br/> <textarea id="pubkey" rows="15" cols="65">-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlOJu6TyygqxfWT7eLtGDwajtN FOb9I5XRb6khyfD1Yt3YiCgQWMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76 xFxdU6jE0NQ+Z+zEdhUTooNRaY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4 gwQco1KRMDSmXSMkDwIDAQAB -----END PUBLIC KEY-----</textarea><br/> <label for="input">Text to encrypt:</label><br/> <textarea id="input" name="input" type="text" rows=4 cols=70>This is a test!</textarea><br/> <input id="testme" type="button" value="Test Me!!!" /><br/> </body> </html>
打完,收功,希望能给大家带来一点用处^_^