前幾天發現博客園登陸時,對登陸的數據進行了加密,在我這種菜鳥看來算是高大上的功能了,因而決定研究一下。javascript
後來發現其實園子裏或者網上有相似文章,但好像都是php寫的demo,並無c#的示例,因此在收集了各位大牛的文章後,進行加工,造成了今天的demo,因此嚴格意義上來講此文並不是原創。在這裏要感謝@趴在巨人肩上的矮子 @duduphp
首先科普一下相關技術:html
Openssl
OpenSSL 是一個強大的安全套接字層密碼庫,囊括主要的密碼算法、經常使用的密鑰和證書封裝管理功能及SSL協議,並提供豐富的應用程序供測試或其它目的使用。java
SSL是Secure Sockets Layer(安全套接層協議)的縮寫,能夠在Internet上提供祕密性傳輸。Netscape公司在推出第一個Web瀏覽器的同時,提出了SSL協議標準。其目標是保證兩個應用間通訊的保密性和可靠性,可在服務器端和用戶端同時實現支持。已經成爲Internet上保密通信的工業標準。
SSL能使用戶/服務器應用之間的通訊不被攻擊者竊聽,而且始終對服務器進行認證,還可選擇對用戶進行認證。SSL協議要求創建在可靠的傳輸層協議(TCP)之上。SSL協議的優點在於它是與應用層協議獨立無關的,高層的應用層協議(例如:HTTP,FTP,TELNET等)能透明地創建於SSL協議之上。SSL協議在應用層協議通訊以前就已經完成加密算法、通訊密鑰的協商及服務器認證工做。在此以後應用層協議所傳送的數據都會被加密,從而保證通訊的私密性。jquery
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------web
RSA算法ajax
RSA算法是第一個既能用於數據加密也能用於數字簽名的算法。它易於理解和操做,也很流行。它的安全性是基於大整數素因子分解的困難性,而大整數因子分解問題是數學上的著名難題,至今沒有有效的方法予以解決,所以能夠確保RSA算法的安全性。算法
RSA算法實現主要分爲三部分:包括公鑰和私鑰的產生,非對稱加密和解密,數字簽名和驗證,下面將逐個介紹RSA算法的工做原理及個人實現方法。json
1.公鑰和私鑰的產生c#
隨意選擇兩個大素數p、q,p不等於q,計算n = p * q。
隨機選擇一個整數e,知足e和( p –1 ) * ( q –1 )互質。(注:e很容易選擇,如3, 17, 65537等均可以。.NET Framework中e默認選擇的就是65537)
利用Euclid算法計算解密密鑰d,知足
e * d ≡1 ( mod ( p - 1 ) * ( q - 1 ) )
其中n和d也要互質。
其中e和n就是公鑰,d和n就是私鑰。P、q銷燬。
jsencrypt官網:http://travistidwell.com/jsencrypt/
在線生成非對稱加密公鑰私鑰對:http://web.chacuo.net/netrsakeypair
作非對稱加密時候,常常要生成密鑰對,公鑰私鑰。通常經常使用openssl命令行生成,每次操做比較複雜,提供在線工具能夠選定生成私鑰位數以及私鑰密碼,能夠直接在線生成非對稱加密密鑰對。本工具提供pkcs#1格式公私鑰對,還有pkcs#8公私鑰對。早期openssl1.0以前版本,通常提供是pkcs#1格式,有不少軟件只支持pkcs#1格式(js rsa模塊),那麼你能夠選擇生成該種類型。如今通常流行是pkcs#8格式。詳細能夠上網找找,pkcs#1與pkcs#8區別。
如下是代碼實現部分:
1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %> 2 3 <!DOCTYPE html> 4 5 <html xmlns="http://www.w3.org/1999/xhtml"> 6 <head runat="server"> 7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 8 <title></title> 9 <script src="http://code.jquery.com/jquery-1.8.3.min.js"></script> 10 <script src="http://passport.cnblogs.com/scripts/jsencrypt.min.js"></script> 11 <script type="text/javascript"> 12 // 使用jsencrypt類庫加密js方法, 13 function encryptRequest(reqUrl, data, publicKey) { 14 var encrypt = new JSEncrypt(); 15 encrypt.setPublicKey(publicKey); 16 // ajax請求發送的數據對象 17 var sendData = new Object(); 18 // 將data數組賦給ajax對象 19 for (var key in data) { 20 sendData[key] = encrypt.encrypt(data[key]); 21 } 22 23 $.ajax({ 24 url: reqUrl, 25 type: 'post', 26 data: sendData, 27 dataType: 'json', 28 //contentType: 'application/json; charset=utf-8', 29 success: function (data) { 30 console.info(data); 31 }, 32 error: function (xhr) { 33 //console.error('出錯了'); 34 } 35 }); 36 37 } 38 39 // Call this code when the page is done loading. 40 $(function () { 41 42 $('#testme').click(function () { 43 44 var data = []; 45 data['username'] = $('#username').val(); 46 data['passwd'] = $('#passwd').val(); 47 48 var pkey = $('#pubkey').val(); 49 encryptRequest('/WebForm2.aspx', data, pkey); 50 }); 51 }); 52 </script> 53 </head> 54 <body> 55 <form id="form1" runat="server"> 56 <div> 57 <label for="pubkey">Public Key</label><br /> 58 <textarea id="pubkey" rows="15" cols="65"> 59 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCC0hrRIjb3noDWNtbDpANbjt5I 60 wu2NFeDwU16Ec87ToqeoIm2KI+cOs81JP9aTDk/jkAlU97mN8wZkEMDr5utAZtMV 61 ht7GLX33Wx9XjqxUsDfsGkqNL8dXJklWDu9Zh80Ui2Ug+340d5dZtKtd+nv09QZq 62 GjdnSp9PTfFDBY133QIDAQAB 63 </textarea><br /> 64 <label for="input">Text to encrypt:</label><br /> 65 name:<input id="username" name="username" type="text"></input><br /> 66 password:<input id="passwd" name="passwd" type="password"></input><br /> 67 <input id="testme" type="button" value="submit" /><br /> 68 </div> 69 </form> 70 </body> 71 </html>
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Security.Cryptography; 6 using System.Text; 7 using System.Web; 8 using System.Web.UI; 9 using System.Web.UI.WebControls; 10 11 namespace WebApplication1 12 { 13 public partial class WebForm2 : System.Web.UI.Page 14 { 15 private const string privateKey = @"MIICXAIBAAKBgQCC0hrRIjb3noDWNtbDpANbjt5Iwu2NFeDwU16Ec87ToqeoIm2K 16 I+cOs81JP9aTDk/jkAlU97mN8wZkEMDr5utAZtMVht7GLX33Wx9XjqxUsDfsGkqN 17 L8dXJklWDu9Zh80Ui2Ug+340d5dZtKtd+nv09QZqGjdnSp9PTfFDBY133QIDAQAB 18 AoGAJBNTOITaP6LCyKVKyEdnHaKNAz0DS+V9UwjKhyAgfcAxwm3sDdd6FQCEW0TI 19 JA7Np7rFYrGwcR1UOoKxkNxB10ACl6JX4rE7xKS6NLZumdwxON/KgDb+2SQtWEXD 20 gBySZ7Znv/FhEp1RmoBDjZ05E99kILWO3ToorUM0Eq2GHQkCQQCnUMXgZa4HS0tu 21 INzysgB37d7ene9+CIARyJphs079qao2UWCgXqen43Ob6GJUgulz7We+4JOZFld0 22 TfEi1E5rAkEAyClQAVzafLO3gXgqH7tbRbPPx788+4opxT9QBo2Trzl6/3FlcC1P 23 IZeqbQ/Oc2wT7jmidFnpyTEnM2p7Yq3U1wJBAILTWaX4W3dAnJ5j+9+Y51zfFiEj 24 hRwbMWi2XmB+gAlAHOOUBeXfnWBdLQx/TEOgiUIoI7LQjxhoq8E5II+HSjkCQDlK 25 SdH6B7dFoTJ3eGcYsykiLEiZ3hSJGSeR1Y/qmei/ZQsUI9qVvV56EJeivI6g0puO 26 94ah7Z5eaT/4LFS0OIUCQDgLn586pGgeidLhQsIe/AR3y9YOCAygTFLxzmeBXOKt 27 M90q4516KWlTtK2u99442mNi7hNmjryBVwk62foWo8w="; 28 29 private const string publicKey = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCC0hrRIjb3noDWNtbDpANbjt5I 30 wu2NFeDwU16Ec87ToqeoIm2KI+cOs81JP9aTDk/jkAlU97mN8wZkEMDr5utAZtMV 31 ht7GLX33Wx9XjqxUsDfsGkqNL8dXJklWDu9Zh80Ui2Ug+340d5dZtKtd+nv09QZq 32 GjdnSp9PTfFDBY133QIDAQAB"; 33 34 protected void Page_Load(object sender, EventArgs e) 35 { 36 if (!IsPostBack) 37 { 38 RSACryptoService rsa = new RSACryptoService(privateKey, publicKey); 39 string data = rsa.Encrypt("我是加密"); 40 Response.Write(rsa.Decrypt(Request.Form["username"]));//解密 41 } 42 } 43 44 } 45 46 public class RSACryptoService 47 { 48 private RSACryptoServiceProvider _privateKeyRsaProvider; 49 private RSACryptoServiceProvider _publicKeyRsaProvider; 50 51 public RSACryptoService(string privateKey, string publicKey = null) 52 { 53 if (!string.IsNullOrEmpty(privateKey)) 54 { 55 _privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey); 56 } 57 58 if (!string.IsNullOrEmpty(publicKey)) 59 { 60 _publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publicKey); 61 } 62 } 63 64 public string Decrypt(string cipherText) 65 { 66 if (_privateKeyRsaProvider == null) 67 { 68 throw new Exception("_privateKeyRsaProvider is null"); 69 } 70 return Encoding.UTF8.GetString(_privateKeyRsaProvider.Decrypt(System.Convert.FromBase64String(cipherText), false)); 71 } 72 73 public string Encrypt(string text) 74 { 75 if (_publicKeyRsaProvider == null) 76 { 77 throw new Exception("_publicKeyRsaProvider is null"); 78 } 79 return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(Encoding.UTF8.GetBytes(text), false)); 80 } 81 82 private RSACryptoServiceProvider CreateRsaProviderFromPrivateKey(string privateKey) 83 { 84 var privateKeyBits = System.Convert.FromBase64String(privateKey); 85 86 var RSA = new RSACryptoServiceProvider(); 87 var RSAparams = new RSAParameters(); 88 89 using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits))) 90 { 91 byte bt = 0; 92 ushort twobytes = 0; 93 twobytes = binr.ReadUInt16(); 94 if (twobytes == 0x8130) 95 binr.ReadByte(); 96 else if (twobytes == 0x8230) 97 binr.ReadInt16(); 98 else 99 throw new Exception("Unexpected value read binr.ReadUInt16()"); 100 101 twobytes = binr.ReadUInt16(); 102 if (twobytes != 0x0102) 103 throw new Exception("Unexpected version"); 104 105 bt = binr.ReadByte(); 106 if (bt != 0x00) 107 throw new Exception("Unexpected value read binr.ReadByte()"); 108 109 RSAparams.Modulus = binr.ReadBytes(GetIntegerSize(binr)); 110 RSAparams.Exponent = binr.ReadBytes(GetIntegerSize(binr)); 111 RSAparams.D = binr.ReadBytes(GetIntegerSize(binr)); 112 RSAparams.P = binr.ReadBytes(GetIntegerSize(binr)); 113 RSAparams.Q = binr.ReadBytes(GetIntegerSize(binr)); 114 RSAparams.DP = binr.ReadBytes(GetIntegerSize(binr)); 115 RSAparams.DQ = binr.ReadBytes(GetIntegerSize(binr)); 116 RSAparams.InverseQ = binr.ReadBytes(GetIntegerSize(binr)); 117 } 118 119 RSA.ImportParameters(RSAparams); 120 return RSA; 121 } 122 123 private int GetIntegerSize(BinaryReader binr) 124 { 125 byte bt = 0; 126 byte lowbyte = 0x00; 127 byte highbyte = 0x00; 128 int count = 0; 129 bt = binr.ReadByte(); 130 if (bt != 0x02) 131 return 0; 132 bt = binr.ReadByte(); 133 134 if (bt == 0x81) 135 count = binr.ReadByte(); 136 else 137 if (bt == 0x82) 138 { 139 highbyte = binr.ReadByte(); 140 lowbyte = binr.ReadByte(); 141 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; 142 count = BitConverter.ToInt32(modint, 0); 143 } 144 else 145 { 146 count = bt; 147 } 148 149 while (binr.ReadByte() == 0x00) 150 { 151 count -= 1; 152 } 153 binr.BaseStream.Seek(-1, SeekOrigin.Current); 154 return count; 155 } 156 157 private RSACryptoServiceProvider CreateRsaProviderFromPublicKey(string publicKeyString) 158 { 159 // encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1" 160 byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; 161 byte[] x509key; 162 byte[] seq = new byte[15]; 163 int x509size; 164 165 x509key = Convert.FromBase64String(publicKeyString); 166 x509size = x509key.Length; 167 168 // --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------ 169 using (MemoryStream mem = new MemoryStream(x509key)) 170 { 171 using (BinaryReader binr = new BinaryReader(mem)) //wrap Memory Stream with BinaryReader for easy reading 172 { 173 byte bt = 0; 174 ushort twobytes = 0; 175 176 twobytes = binr.ReadUInt16(); 177 if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) 178 binr.ReadByte(); //advance 1 byte 179 else if (twobytes == 0x8230) 180 binr.ReadInt16(); //advance 2 bytes 181 else 182 return null; 183 184 seq = binr.ReadBytes(15); //read the Sequence OID 185 if (!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct 186 return null; 187 188 twobytes = binr.ReadUInt16(); 189 if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81) 190 binr.ReadByte(); //advance 1 byte 191 else if (twobytes == 0x8203) 192 binr.ReadInt16(); //advance 2 bytes 193 else 194 return null; 195 196 bt = binr.ReadByte(); 197 if (bt != 0x00) //expect null byte next 198 return null; 199 200 twobytes = binr.ReadUInt16(); 201 if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) 202 binr.ReadByte(); //advance 1 byte 203 else if (twobytes == 0x8230) 204 binr.ReadInt16(); //advance 2 bytes 205 else 206 return null; 207 208 twobytes = binr.ReadUInt16(); 209 byte lowbyte = 0x00; 210 byte highbyte = 0x00; 211 212 if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81) 213 lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus 214 else if (twobytes == 0x8202) 215 { 216 highbyte = binr.ReadByte(); //advance 2 bytes 217 lowbyte = binr.ReadByte(); 218 } 219 else 220 return null; 221 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order 222 int modsize = BitConverter.ToInt32(modint, 0); 223 224 int firstbyte = binr.PeekChar(); 225 if (firstbyte == 0x00) 226 { //if first byte (highest order) of modulus is zero, don't include it 227 binr.ReadByte(); //skip this null byte 228 modsize -= 1; //reduce modulus buffer size by 1 229 } 230 231 byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes 232 233 if (binr.ReadByte() != 0x02) //expect an Integer for the exponent data 234 return null; 235 int expbytes = (int)binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values) 236 byte[] exponent = binr.ReadBytes(expbytes); 237 238 // ------- create RSACryptoServiceProvider instance and initialize with public key ----- 239 RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); 240 RSAParameters RSAKeyInfo = new RSAParameters(); 241 RSAKeyInfo.Modulus = modulus; 242 RSAKeyInfo.Exponent = exponent; 243 RSA.ImportParameters(RSAKeyInfo); 244 245 return RSA; 246 } 247 248 } 249 } 250 251 private bool CompareBytearrays(byte[] a, byte[] b) 252 { 253 if (a.Length != b.Length) 254 return false; 255 int i = 0; 256 foreach (byte c in a) 257 { 258 if (c != b[i]) 259 return false; 260 i++; 261 } 262 return true; 263 } 264 } 265 }
Demo下載
http://pan.baidu.com/s/1i31vfI9
Tips
貌似目前jsencrypt密鑰格式只支持pkcs#1格式,因此在生成時請生成pkcs#1格式