好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

同时兼容JS和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 >

?

var encrypt = new jsencrypt();

var pubkey = "-----begin public key----- \

  migfma0gcsqgsib3dqebaquaa4gnadcbiqkbgqdaj0dpnbmf3z4vt1b8ee6bjkns \

  hlyj7xvgijaa8rcdmgr7mrtrexnk8mdulwdcs05gc4ssfoywjcytkuhpwn8/pks0 \

  vggol9bzn0xt9hiqtb3pzafyknrmdgzmgjgfd6ktnfzvuaoupvxjcgkcoj6/vv5i \

  emcx8mt/z3elfsdsjqidaqab \

  -----end public key-----" ;

encrypt.setpublickey(pubkey);

var encrypted = encrypt.encrypt($( '#txtpwd' ).val());

//console.log(encrypted);

$.ajax({

  type: "post" ,

  url: "http://localhost:24830/services/rsa_pem.ashx" ,

  data: { "pwd" : encrypted },

  datatype: "json" ,

  error: function (xhr, status, error) {

   // alert(error);

   $( "#txtinfo" ).text( ' 请求服务器失败!' );

   $(that).text( '登 录' );

   $(that).attr( 'disabled' , false );

  },

  success: function (json) {

 

  if (uid == "admin" && json.data== "000" ) {

   window.location.href = "index.html" ;

  }

  else {

   $( "#txtinfo" ).text( ' 用户名或者密码错误!' );

   $(that).text( '登 录' );

   $(that).attr( 'disabled' , false );

  }

  }

});

3、后台用c#进行解密

?

using system;

using system.collections.generic;

using system.io;

using system.linq;

using system.security.cryptography;

using system.text;

using system.threading.tasks;

 

namespace cmcloud.saas

{

  public class rsacryptoservice

  {

  private rsacryptoserviceprovider _privatekeyrsaprovider;

  private rsacryptoserviceprovider _publickeyrsaprovider;

 

  /// <summary>

  /// rsa解密

  /// </summary>

  /// <param name="ciphertext"></param>

  /// <returns></returns>

  public string decrypt(string ciphertext)

  {

   if (_privatekeyrsaprovider == null )

   {

   throw new exception( "_privatekeyrsaprovider is null" );

   }

   return decrypt2(ciphertext);

  }

  /// <summary>

  /// rsa加密

  /// </summary>

  /// <param name="text"></param>

  /// <returns></returns>

  public string encrypt(string text)

  {

   if (_publickeyrsaprovider == null )

   {

   throw new exception( "_publickeyrsaprovider is null" );

   }

   return encrypt2(text);

   //return convert.tobase64string(_publickeyrsaprovider.encrypt(encoding.utf8.getbytes(text), false));

 

  }

  private string encrypt2(string text)

  {

 

 

   byte [] plaintextdata = encoding.utf8.getbytes(text);

   int maxblocksize = _publickeyrsaprovider.keysize / 8 - 11 ; //加密块最大长度限制

 

   if (plaintextdata.length <= maxblocksize)

   {

   return convert.tobase64string(_publickeyrsaprovider.encrypt(plaintextdata, false ));

   }

   else

   {

   using (memorystream plaistream = new memorystream(plaintextdata))

   using (memorystream crypstream = new memorystream())

   {

    byte [] buffer = new byte [maxblocksize];

    int blocksize = plaistream.read(buffer, 0 , maxblocksize);

 

    while (blocksize > 0 )

    {

    byte [] toencrypt = new byte [blocksize];

    array.copy(buffer, 0 , toencrypt, 0 , blocksize);

 

    byte [] cryptograph = _publickeyrsaprovider.encrypt(toencrypt, false );

    crypstream.write(cryptograph, 0 , cryptograph.length);

 

    blocksize = plaistream.read(buffer, 0 , maxblocksize);

    }

 

    return convert.tobase64string(crypstream.toarray(), base64formattingoptions.none);

   }

   }

 

 

 

 

  }

 

  private string decrypt2(string ciphertext)

  {

 

 

   byte [] ciphertextdata = convert.frombase64string(ciphertext);

   int maxblocksize = _privatekeyrsaprovider.keysize / 8 ; //解密块最大长度限制

 

   if (ciphertextdata.length <= maxblocksize)

   return system.text.encoding.utf8.getstring(_privatekeyrsaprovider.decrypt(ciphertextdata, false ));

 

   using (memorystream crypstream = new memorystream(ciphertextdata))

   using (memorystream plaistream = new memorystream())

   {

   byte [] buffer = new byte [maxblocksize];

   int blocksize = crypstream.read(buffer, 0 , maxblocksize);

 

   while (blocksize > 0 )

   {

    byte [] todecrypt = new byte [blocksize];

    array.copy(buffer, 0 , todecrypt, 0 , blocksize);

 

    byte [] plaintext = _privatekeyrsaprovider.decrypt(todecrypt, false );

    plaistream.write(plaintext, 0 , plaintext.length);

 

    blocksize = crypstream.read(buffer, 0 , maxblocksize);

   }

 

   return system.text.encoding.utf8.getstring(plaistream.toarray());

   }

  }

  public rsacryptoservice(string privatekey, string publickey = null )

  {

   if (!string.isnullorempty(privatekey))

   {

   _privatekeyrsaprovider = creatersaproviderfromprivatekey(privatekey);

   }

 

   if (!string.isnullorempty(publickey))

   {

   _publickeyrsaprovider = creatersaproviderfrompublickey(publickey);

   }

  }

 

 

 

  private rsacryptoserviceprovider creatersaproviderfromprivatekey(string privatekey)

  {

   var privatekeybits = system.convert.frombase64string(privatekey);

 

   var rsa = new rsacryptoserviceprovider();

   var rsaparams = new rsaparameters();

 

   using (binaryreader binr = new binaryreader( new memorystream(privatekeybits)))

   {

   byte bt = 0 ;

   ushort twobytes = 0 ;

   twobytes = binr.readuint16();

   if (twobytes == 0x8130 )

    binr.readbyte();

   else if (twobytes == 0x8230 )

    binr.readint16();

   else

    throw new exception( "unexpected value read binr.readuint16()" );

 

   twobytes = binr.readuint16();

   if (twobytes != 0x0102 )

    throw new exception( "unexpected version" );

 

   bt = binr.readbyte();

   if (bt != 0x00 )

    throw new exception( "unexpected value read binr.readbyte()" );

 

   rsaparams.modulus = binr.readbytes(getintegersize(binr));

   rsaparams.exponent = binr.readbytes(getintegersize(binr));

   rsaparams.d = binr.readbytes(getintegersize(binr));

   rsaparams.p = binr.readbytes(getintegersize(binr));

   rsaparams.q = binr.readbytes(getintegersize(binr));

   rsaparams.dp = binr.readbytes(getintegersize(binr));

   rsaparams.dq = binr.readbytes(getintegersize(binr));

   rsaparams.inverseq = binr.readbytes(getintegersize(binr));

   }

 

   rsa.importparameters(rsaparams);

   return rsa;

  }

 

  private int getintegersize(binaryreader binr)

  {

   byte bt = 0 ;

   byte lowbyte = 0x00 ;

   byte highbyte = 0x00 ;

   int count = 0 ;

   bt = binr.readbyte();

   if (bt != 0x02 )

   return 0 ;

   bt = binr.readbyte();

 

   if (bt == 0x81 )

   count = binr.readbyte();

   else

   if (bt == 0x82 )

   {

   highbyte = binr.readbyte();

   lowbyte = binr.readbyte();

   byte [] modint = { lowbyte, highbyte, 0x00 , 0x00 };

   count = bitconverter.toint32(modint, 0 );

   }

   else

   {

   count = bt;

   }

 

   while (binr.readbyte() == 0x00 )

   {

   count -= 1 ;

   }

   binr.basestream.seek(- 1 , seekorigin.current);

   return count;

  }

 

  private rsacryptoserviceprovider creatersaproviderfrompublickey(string publickeystring)

  {

   // encoded oid sequence for pkcs #1 rsaencryption szoid_rsa_rsa = "1.2.840.113549.1.1.1"

   byte [] seqoid = { 0x30 , 0x0d , 0x06 , 0x09 , 0x2a , 0x86 , 0x48 , 0x86 , 0xf7 , 0x0d , 0x01 , 0x01 , 0x01 , 0x05 , 0x00 };

   byte [] x509key;

   byte [] seq = new byte [ 15 ];

   int x509size;

 

   x509key = convert.frombase64string(publickeystring);

   x509size = x509key.length;

 

   // --------- set up stream to read the asn.1 encoded subjectpublickeyinfo blob ------

   using (memorystream mem = new memorystream(x509key))

   {

   using (binaryreader binr = new binaryreader(mem)) //wrap memory stream with binaryreader for easy reading

   {

    byte bt = 0 ;

    ushort twobytes = 0 ;

 

    twobytes = binr.readuint16();

    if (twobytes == 0x8130 ) //data read as little endian order (actual data order for sequence is 30 81)

    binr.readbyte(); //advance 1 byte

    else if (twobytes == 0x8230 )

    binr.readint16(); //advance 2 bytes

    else

    return null ;

 

    seq = binr.readbytes( 15 ); //read the sequence oid

    if (!comparebytearrays(seq, seqoid)) //make sure sequence for oid is correct

    return null ;

 

    twobytes = binr.readuint16();

    if (twobytes == 0x8103 ) //data read as little endian order (actual data order for bit string is 03 81)

    binr.readbyte(); //advance 1 byte

    else if (twobytes == 0x8203 )

    binr.readint16(); //advance 2 bytes

    else

    return null ;

 

    bt = binr.readbyte();

    if (bt != 0x00 ) //expect null byte next

    return null ;

 

    twobytes = binr.readuint16();

    if (twobytes == 0x8130 ) //data read as little endian order (actual data order for sequence is 30 81)

    binr.readbyte(); //advance 1 byte

    else if (twobytes == 0x8230 )

    binr.readint16(); //advance 2 bytes

    else

    return null ;

 

    twobytes = binr.readuint16();

    byte lowbyte = 0x00 ;

    byte highbyte = 0x00 ;

 

    if (twobytes == 0x8102 ) //data read as little endian order (actual data order for integer is 02 81)

    lowbyte = binr.readbyte(); // read next bytes which is bytes in modulus

    else if (twobytes == 0x8202 )

    {

    highbyte = binr.readbyte(); //advance 2 bytes

    lowbyte = binr.readbyte();

    }

    else

    return null ;

    byte [] modint = { lowbyte, highbyte, 0x00 , 0x00 }; //reverse byte order since asn.1 key uses big endian order

    int modsize = bitconverter.toint32(modint, 0 );

 

    int firstbyte = binr.peekchar();

    if (firstbyte == 0x00 )

    { //if first byte (highest order) of modulus is zero, don't include it

    binr.readbyte(); //skip this null byte

    modsize -= 1 ; //reduce modulus buffer size by 1

    }

 

    byte [] modulus = binr.readbytes(modsize); //read the modulus bytes

 

    if (binr.readbyte() != 0x02 )  //expect an integer for the exponent data

    return null ;

    int expbytes = ( int )binr.readbyte(); // should only need one byte for actual exponent data (for all useful values)

    byte [] exponent = binr.readbytes(expbytes);

 

    // ------- create rsacryptoserviceprovider instance and initialize with public key -----

    rsacryptoserviceprovider rsa = new rsacryptoserviceprovider();

    rsaparameters rsakeyinfo = new rsaparameters();

    rsakeyinfo.modulus = modulus;

    rsakeyinfo.exponent = exponent;

    rsa.importparameters(rsakeyinfo);

 

    return rsa;

   }

 

   }

  }

 

  private bool comparebytearrays( byte [] a, byte [] b)

  {

   if (a.length != b.length)

   return false ;

   int i = 0 ;

   foreach ( byte c in a)

   {

   if (c != b[i])

    return false ;

   i++;

   }

   return true ;

  }

  }

}

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

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

总结

好了,大概就这样,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持

原文链接:http://HdhCmsTestcnblogs测试数据/isaboy/p/csharp_openssl_rsa_jsencrypt.html

dy("nrwz");

查看更多关于同时兼容JS和C#的RSA加密解密算法详解(对web提交的数据加密传输)的详细内容...

  阅读:46次