• RSA加密解密在jsencrypt+c#的实现-博客园加密登录


    前几天发现博客园登录时,对登录的数据进行了加密,在我这种菜鸟看来算是高大上的功能了,于是决定研究一下。

    后来发现其实园子里或者网上有类似文章,但好像都是php写的demo,并没有c#的示例,所以在收集了各位大牛的文章后,进行加工,形成了今天的demo,所以严格意义上来说此文并非原创。在这里要感谢@趴在巨人肩上的矮子   @dudu

    首先科普一下相关技术:

    Openssl 
    OpenSSL 是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。

    SSL是Secure Sockets Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。Netscape公司在推出第一个Web浏览器的同时,提出了SSL协议标准。其目标是保证两个应用间通信的保密性和可靠性,可在服务器端和用户端同时实现支持。已经成为Internet上保密通讯的工业标准。
    SSL能使用户/服务器应用之间的通信不被攻击者窃听,并且始终对服务器进行认证,还可选择对用户进行认证。SSL协议要求建立在可靠的传输层协议(TCP)之上。SSL协议的优势在于它是与应用层协议独立无关的,高层的应用层协议(例如:HTTP,FTP,TELNET等)能透明地建立于SSL协议之上。SSL协议在应用层协议通信之前就已经完成加密算法、通信密钥的协商及服务器认证工作。在此之后应用层协议所传送的数据都会被加密,从而保证通信的私密性。

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    RSA算法

    RSA算法是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。它的安全性是基于大整数素因子分解的困难性,而大整数因子分解问题是数学上的著名难题,至今没有有效的方法予以解决,因此可以确保RSA算法的安全性。

      RSA算法实现主要分为三部分:包括公钥和私钥的产生,非对称加密和解密,数字签名和验证,下面将逐个介绍RSA算法的工作原理及我的实现方法。

        1.公钥和私钥的产生

        随意选择两个大素数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格式

  • 相关阅读:
    LeetCode 112. Path Sum
    LeetCode 866. Prime Palindrome
    LeetCode 51.N-Queens
    【Codeforces 4D】Mysterious Present
    【Codeforces 158C】Cd and pwd commands
    【Codeforces 27A】Next Test
    【Codeforces 385C】Bear and Prime Numbers
    【Codeforces 474D】Flowers
    【Codeforces 1B】Spreadsheets
    【Codeforces 1114D】Flood Fill
  • 原文地址:https://www.cnblogs.com/jrsnd/p/4786767.html
Copyright © 2020-2023  润新知