zoukankan      html  css  js  c++  java
  • 兼容javascript和C#的RSA加密解密算法,对web提交的数据进行加密传输

      Web应用中往往涉及到敏感的数据,由于HTTP协议以明文的形式与服务器进行交互,因此可以通过截获请求的数据包进行分析来盗取有用的信息。虽然https可以对传输的数据进行加密,但是必须要申请证书(一般都是收费的),成本较高。那么问题来了,如果对web提交的敏感数据进行加密呢?web应用中,前端的数据处理和交互基本上都是靠javascript来完成,后台的逻辑处理可以C#(java)等进行处理。

      微软的C#中虽然有RSA算法,但是格式和OpenSSL生成的公钥/私钥文件格式并不兼容。这个也给贯通前后台的RSA加密解密带来了难度。为了兼容OpenSSL生成的公钥/私钥文件格式,贯通javascript和C#的RSA加密解密算法,必须对C#内置的方法进行再度封装。

        下面以登录为例,用户在密码框输入密码后,javascript发送ajax请求时,对密码先进行rsa加密后再发送,服务器接收到加密后的密码后,先对其进行解密, 然后再验证登录是否成功。

      1  为了进行RSA加密解密,首先需要用openssl生成一对公钥和私钥(没有的先下载openssl):

       1) 打开openssl.exe文件,输入 genrsa -out openssl_rsa_priv.pem 1024

    此命令在openssl.exe同目录下生成openssl_rsa_private_key.pem文件。

      2) 生成公钥 rsa  -in openssl_rsa__private.pem -pubout -out openssl_rsa__public.pem

      以上命令会创建如下的文件:

    这个文件可以用文本编辑器进行打开,查看内容。

    -----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0w036ClSD0LvxPROMun0u022R
    OJlZE6P3m+gjq3gpi4n7lo8jhTqMqgccDbVJqnIfMzWS9O3lnlQXWTxJ3B4XJ52F
    AcriY5brOXUVgBLx5QMHLLd1gtJnmG4i7r4ytgX7XVKRnojR6zca1YnS0lbGGDF1
    CGllB1riNrdksSQP+wIDAQAB
    -----END PUBLIC KEY-----
    -----BEGIN RSA PRIVATE KEY-----
    MIICXQIBAAKBgQC0w036ClSD0LvxPROMun0u022ROJlZE6P3m+gjq3gpi4n7lo8j
    hTqMqgccDbVJqnIfMzWS9O3lnlQXWTxJ3B4XJ52FAcriY5brOXUVgBLx5QMHLLd1
    gtJnmG4i7r4ytgX7XVKRnojR6zca1YnS0lbGGDF1CGllB1riNrdksSQP+wIDAQAB
    AoGAIOyl6lIxXKULZoBKbEqXfIz0GwxlGg1ywyn5mW2lAGQzKMken0ioBnD9xIVW
    rOlHyhkIvBCyuC0jgfE2Avn93MlB3j0WRuXMFlJpCBlEklMilO9Zgmwl+vTB3VZb
    8VzdrEEEUBio7LWP/KvSo+IFlNjDTKgAczbLTwAmj4w6g0ECQQDm4yxPdxcU2ywZ
    7PyjIMM9qnSah9KcrjU8gjEyHsUpgTjhw1cx7Peo+vRiHqxDy1yaSu1BlwRR52pC
    jKNnl0QhAkEAyGx3NxEIiLk2oXGGbIMZ4P6geC8gYu01BiRNWVf0Yi7+sCH68eUP
    oI+G5bJ8bvzXpvHjQi0s2OlRfct/qtPQmwJBALa+2DONbxdy4lUi3lO/esk0QVaO
    aoTY3gomggnJkQRo4zzOABXkGaIF/6gp3u9J5uG4rFFd1m19XP2Pk0ZK1AECQBYi
    lJAKW4zuF7CA3z3AxOzqckKTwdnrJL4G6FwDsMPfONWvCw4IJE+xSk64BbIkTpTr
    hhPa9WcHba6c+P6e4h0CQQDWeGMMpkqPG/w4afNCGmvRnM8vNkGUAmDGvCsfkTID
    ijpKl5SD55hPHsWE5rsv1TLUpkWtrFBcg61bHwMUP3cv
    -----END RSA PRIVATE KEY-----

    2 用jsencrypt对密码进行加密:

    首先需要导入js包文件

    <script src="dist/js/jsencrypt.js"></script>

     

     1 var encrypt = new JSEncrypt();
     2 var pubkey = "-----BEGIN PUBLIC KEY----- 
     3     MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAj0dPnBMf3Z4VT1B8Ee6bjKNs 
     4     hlYj7xvGijAa8RCdmGR7mrtrExnk8mdUlwdcS05gc4SSFOyWJcYtKUHpWn8/pkS0 
     5     vgGOl9Bzn0Xt9hiqTb3pZAfykNrMDGZMgJgfD6KTnfzVUAOupvxjcGkcoj6/vV5I 
     6     eMcx8mT/z3elfsDSjQIDAQAB 
     7     -----END PUBLIC KEY-----";
     8 encrypt.setPublicKey(pubkey);
     9 var encrypted = encrypt.encrypt($('#txtpwd').val());
    10 //console.log(encrypted);
    11 $.ajax({
    12     type: "POST",
    13     url: "http://localhost:24830/services/rsa_pem.ashx",
    14     data: { "pwd": encrypted },
    15     dataType: "Json",
    16     error: function (xhr, status, error) {
    17            // alert(error);
    18             $("#txtInfo").text(' 请求服务器失败!');
    19             $(that).text('登 录');
    20             $(that).attr('disabled', false);
    21     },
    22     success: function (json) {
    23        
    24         if (uid == "admin" && json.data=="000") {
    25             window.location.href = "index.html";
    26         }
    27         else {
    28             $("#txtInfo").text(' 用户名或者密码错误!');
    29             $(that).text('登 录');
    30             $(that).attr('disabled', false);
    31         }
    32     }
    33 });

    3 后台用C#进行解密

      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.Threading.Tasks;
      8 
      9 namespace CMCloud.SaaS
     10 {
     11     public class RSACryptoService
     12     {
     13         private RSACryptoServiceProvider _privateKeyRsaProvider;
     14         private RSACryptoServiceProvider _publicKeyRsaProvider;
     15 
     16         /// <summary>
     17         /// RSA解密
     18         /// </summary>
     19         /// <param name="cipherText"></param>
     20         /// <returns></returns>
     21         public string Decrypt(string cipherText)
     22         {
     23             if (_privateKeyRsaProvider == null)
     24             {
     25                 throw new Exception("_privateKeyRsaProvider is null");
     26             }
     27             return Decrypt2(cipherText);
     28         }
     29         /// <summary>
     30         /// RSA加密
     31         /// </summary>
     32         /// <param name="text"></param>
     33         /// <returns></returns>
     34         public string Encrypt(string text)
     35         {
     36             if (_publicKeyRsaProvider == null)
     37             {
     38                 throw new Exception("_publicKeyRsaProvider is null");
     39             }
     40             return Encrypt2(text);
     41             //return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(Encoding.UTF8.GetBytes(text), false));
     42 
     43         }
     44         private string Encrypt2(string text)
     45         {
     46 
     47 
     48             Byte[] PlaintextData = Encoding.UTF8.GetBytes(text);
     49             int MaxBlockSize = _publicKeyRsaProvider.KeySize / 8 - 11;//加密块最大长度限制
     50 
     51             if (PlaintextData.Length <= MaxBlockSize)
     52             {
     53                 return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(PlaintextData, false));
     54             }
     55             else
     56             {
     57                 using (MemoryStream PlaiStream = new MemoryStream(PlaintextData))
     58                 using (MemoryStream CrypStream = new MemoryStream())
     59                 {
     60                     Byte[] Buffer = new Byte[MaxBlockSize];
     61                     int BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);
     62 
     63                     while (BlockSize > 0)
     64                     {
     65                         Byte[] ToEncrypt = new Byte[BlockSize];
     66                         Array.Copy(Buffer, 0, ToEncrypt, 0, BlockSize);
     67 
     68                         Byte[] Cryptograph = _publicKeyRsaProvider.Encrypt(ToEncrypt, false);
     69                         CrypStream.Write(Cryptograph, 0, Cryptograph.Length);
     70 
     71                         BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);
     72                     }
     73 
     74                     return Convert.ToBase64String(CrypStream.ToArray(), Base64FormattingOptions.None);
     75                 }
     76             }
     77 
     78 
     79 
     80 
     81         }
     82 
     83         private string Decrypt2(string ciphertext)
     84         {
     85 
     86 
     87             Byte[] CiphertextData = Convert.FromBase64String(ciphertext);
     88             int MaxBlockSize = _privateKeyRsaProvider.KeySize / 8;    //解密块最大长度限制
     89 
     90             if (CiphertextData.Length <= MaxBlockSize)
     91                 return System.Text.Encoding.UTF8.GetString(_privateKeyRsaProvider.Decrypt(CiphertextData, false));
     92 
     93             using (MemoryStream CrypStream = new MemoryStream(CiphertextData))
     94             using (MemoryStream PlaiStream = new MemoryStream())
     95             {
     96                 Byte[] Buffer = new Byte[MaxBlockSize];
     97                 int BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);
     98 
     99                 while (BlockSize > 0)
    100                 {
    101                     Byte[] ToDecrypt = new Byte[BlockSize];
    102                     Array.Copy(Buffer, 0, ToDecrypt, 0, BlockSize);
    103 
    104                     Byte[] Plaintext = _privateKeyRsaProvider.Decrypt(ToDecrypt, false);
    105                     PlaiStream.Write(Plaintext, 0, Plaintext.Length);
    106 
    107                     BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);
    108                 }
    109 
    110                 return System.Text.Encoding.UTF8.GetString(PlaiStream.ToArray());
    111             }
    112         }
    113         public RSACryptoService(string privateKey, string publicKey = null)
    114         {
    115             if (!string.IsNullOrEmpty(privateKey))
    116             {
    117                 _privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey);
    118             }
    119 
    120             if (!string.IsNullOrEmpty(publicKey))
    121             {
    122                 _publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publicKey);
    123             }
    124         }
    125 
    126         
    127 
    128         private RSACryptoServiceProvider CreateRsaProviderFromPrivateKey(string privateKey)
    129         {
    130             var privateKeyBits = System.Convert.FromBase64String(privateKey);
    131 
    132             var RSA = new RSACryptoServiceProvider();
    133             var RSAparams = new RSAParameters();
    134 
    135             using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits)))
    136             {
    137                 byte bt = 0;
    138                 ushort twobytes = 0;
    139                 twobytes = binr.ReadUInt16();
    140                 if (twobytes == 0x8130)
    141                     binr.ReadByte();
    142                 else if (twobytes == 0x8230)
    143                     binr.ReadInt16();
    144                 else
    145                     throw new Exception("Unexpected value read binr.ReadUInt16()");
    146 
    147                 twobytes = binr.ReadUInt16();
    148                 if (twobytes != 0x0102)
    149                     throw new Exception("Unexpected version");
    150 
    151                 bt = binr.ReadByte();
    152                 if (bt != 0x00)
    153                     throw new Exception("Unexpected value read binr.ReadByte()");
    154 
    155                 RSAparams.Modulus = binr.ReadBytes(GetIntegerSize(binr));
    156                 RSAparams.Exponent = binr.ReadBytes(GetIntegerSize(binr));
    157                 RSAparams.D = binr.ReadBytes(GetIntegerSize(binr));
    158                 RSAparams.P = binr.ReadBytes(GetIntegerSize(binr));
    159                 RSAparams.Q = binr.ReadBytes(GetIntegerSize(binr));
    160                 RSAparams.DP = binr.ReadBytes(GetIntegerSize(binr));
    161                 RSAparams.DQ = binr.ReadBytes(GetIntegerSize(binr));
    162                 RSAparams.InverseQ = binr.ReadBytes(GetIntegerSize(binr));
    163             }
    164 
    165             RSA.ImportParameters(RSAparams);
    166             return RSA;
    167         }
    168 
    169         private int GetIntegerSize(BinaryReader binr)
    170         {
    171             byte bt = 0;
    172             byte lowbyte = 0x00;
    173             byte highbyte = 0x00;
    174             int count = 0;
    175             bt = binr.ReadByte();
    176             if (bt != 0x02)
    177                 return 0;
    178             bt = binr.ReadByte();
    179 
    180             if (bt == 0x81)
    181                 count = binr.ReadByte();
    182             else
    183                 if (bt == 0x82)
    184             {
    185                 highbyte = binr.ReadByte();
    186                 lowbyte = binr.ReadByte();
    187                 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
    188                 count = BitConverter.ToInt32(modint, 0);
    189             }
    190             else
    191             {
    192                 count = bt;
    193             }
    194 
    195             while (binr.ReadByte() == 0x00)
    196             {
    197                 count -= 1;
    198             }
    199             binr.BaseStream.Seek(-1, SeekOrigin.Current);
    200             return count;
    201         }
    202 
    203         private RSACryptoServiceProvider CreateRsaProviderFromPublicKey(string publicKeyString)
    204         {
    205             // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
    206             byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
    207             byte[] x509key;
    208             byte[] seq = new byte[15];
    209             int x509size;
    210 
    211             x509key = Convert.FromBase64String(publicKeyString);
    212             x509size = x509key.Length;
    213 
    214             // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
    215             using (MemoryStream mem = new MemoryStream(x509key))
    216             {
    217                 using (BinaryReader binr = new BinaryReader(mem))  //wrap Memory Stream with BinaryReader for easy reading
    218                 {
    219                     byte bt = 0;
    220                     ushort twobytes = 0;
    221 
    222                     twobytes = binr.ReadUInt16();
    223                     if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
    224                         binr.ReadByte();    //advance 1 byte
    225                     else if (twobytes == 0x8230)
    226                         binr.ReadInt16();   //advance 2 bytes
    227                     else
    228                         return null;
    229 
    230                     seq = binr.ReadBytes(15);       //read the Sequence OID
    231                     if (!CompareBytearrays(seq, SeqOID))    //make sure Sequence for OID is correct
    232                         return null;
    233 
    234                     twobytes = binr.ReadUInt16();
    235                     if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
    236                         binr.ReadByte();    //advance 1 byte
    237                     else if (twobytes == 0x8203)
    238                         binr.ReadInt16();   //advance 2 bytes
    239                     else
    240                         return null;
    241 
    242                     bt = binr.ReadByte();
    243                     if (bt != 0x00)     //expect null byte next
    244                         return null;
    245 
    246                     twobytes = binr.ReadUInt16();
    247                     if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
    248                         binr.ReadByte();    //advance 1 byte
    249                     else if (twobytes == 0x8230)
    250                         binr.ReadInt16();   //advance 2 bytes
    251                     else
    252                         return null;
    253 
    254                     twobytes = binr.ReadUInt16();
    255                     byte lowbyte = 0x00;
    256                     byte highbyte = 0x00;
    257 
    258                     if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
    259                         lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
    260                     else if (twobytes == 0x8202)
    261                     {
    262                         highbyte = binr.ReadByte(); //advance 2 bytes
    263                         lowbyte = binr.ReadByte();
    264                     }
    265                     else
    266                         return null;
    267                     byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
    268                     int modsize = BitConverter.ToInt32(modint, 0);
    269 
    270                     int firstbyte = binr.PeekChar();
    271                     if (firstbyte == 0x00)
    272                     {   //if first byte (highest order) of modulus is zero, don't include it
    273                         binr.ReadByte();    //skip this null byte
    274                         modsize -= 1;   //reduce modulus buffer size by 1
    275                     }
    276 
    277                     byte[] modulus = binr.ReadBytes(modsize);   //read the modulus bytes
    278 
    279                     if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
    280                         return null;
    281                     int expbytes = (int)binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
    282                     byte[] exponent = binr.ReadBytes(expbytes);
    283 
    284                     // ------- create RSACryptoServiceProvider instance and initialize with public key -----
    285                     RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
    286                     RSAParameters RSAKeyInfo = new RSAParameters();
    287                     RSAKeyInfo.Modulus = modulus;
    288                     RSAKeyInfo.Exponent = exponent;
    289                     RSA.ImportParameters(RSAKeyInfo);
    290 
    291                     return RSA;
    292                 }
    293 
    294             }
    295         }
    296 
    297         private bool CompareBytearrays(byte[] a, byte[] b)
    298         {
    299             if (a.Length != b.Length)
    300                 return false;
    301             int i = 0;
    302             foreach (byte c in a)
    303             {
    304                 if (c != b[i])
    305                     return false;
    306                 i++;
    307             }
    308             return true;
    309         }
    310     }
    311 }

           虽然将公钥暴露在js文件中,但是如果需要解密得到明文,必须需要私钥(这个存储在后台,不容易获取)。

        调试运行,可以看到获取的密码是加密后的数据,然后在后台可以进行解密获取到明文。

     

  • 相关阅读:
    高精度计算模板
    P1108 低价购买 [DP][统计方案]
    POJ3349 Snowflake Snow Snowflakes [哈希]
    P1312 Mayan游戏 [深搜][模拟]
    P1378 油滴扩展[深搜]
    P1514 引水入城[搜索,线段覆盖]
    TYVJ1391 走廊泼水节
    【BZOJ1196】公路修建问题
    【BZOJ3624】免费道路
    【BZOJ2429】聪明的猴子
  • 原文地址:https://www.cnblogs.com/isaboy/p/csharp_openssl_rsa_jsencrypt.html
Copyright © 2011-2022 走看看