兼容javascript和C#的RSA加密解密算法,对web提交的数据进行加密传输

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

  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

76497-20161107163648295-1668761517.png

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

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

76497-20161107164135842-920775863.png

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

76497-20161107164255092-2015288419.png

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

-----BEGINPUBLICKEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0w036ClSD0LvxPROMun0u022ROJlZE6P3m+gjq3gpi4n7lo8jhTqMqgccDbVJqnIfMzWS9O3lnlQXWTxJ3B4XJ52FAcriY5brOXUVgBLx5QMHLLd1gtJnmG4i7r4ytgX7XVKRnojR6zca1YnS0lbGGDF1CGllB1riNrdksSQP+wIDAQAB-----ENDPUBLICKEY-----
-----BEGINRSAPRIVATEKEY-----MIICXQIBAAKBgQC0w036ClSD0LvxPROMun0u022ROJlZE6P3m+gjq3gpi4n7lo8jhTqMqgccDbVJqnIfMzWS9O3lnlQXWTxJ3B4XJ52FAcriY5brOXUVgBLx5QMHLLd1gtJnmG4i7r4ytgX7XVKRnojR6zca1YnS0lbGGDF1CGllB1riNrdksSQP+wIDAQABAoGAIOyl6lIxXKULZoBKbEqXfIz0GwxlGg1ywyn5mW2lAGQzKMken0ioBnD9xIVWrOlHyhkIvBCyuC0jgfE2Avn93MlB3j0WRuXMFlJpCBlEklMilO9Zgmwl+vTB3VZb8VzdrEEEUBio7LWP/KvSo+IFlNjDTKgAczbLTwAmj4w6g0ECQQDm4yxPdxcU2ywZ7PyjIMM9qnSah9KcrjU8gjEyHsUpgTjhw1cx7Peo+vRiHqxDy1yaSu1BlwRR52pCjKNnl0QhAkEAyGx3NxEIiLk2oXGGbIMZ4P6geC8gYu01BiRNWVf0Yi7+sCH68eUPoI+G5bJ8bvzXpvHjQi0s2OlRfct/qtPQmwJBALa+2DONbxdy4lUi3lO/esk0QVaOaoTY3gomggnJkQRo4zzOABXkGaIF/6gp3u9J5uG4rFFd1m19XP2Pk0ZK1AECQBYilJAKW4zuF7CA3z3AxOzqckKTwdnrJL4G6FwDsMPfONWvCw4IJE+xSk64BbIkTpTrhhPa9WcHba6c+P6e4h0CQQDWeGMMpkqPG/w4afNCGmvRnM8vNkGUAmDGvCsfkTIDijpKl5SD55hPHsWE5rsv1TLUpkWtrFBcg61bHwMUP3cv-----ENDRSAPRIVATEKEY-----

2 用jsencrypt对密码进行加密:

首先需要导入js包文件:

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

然后编写JS加密算法,示例如下:

varencrypt=newJSEncrypt();
varpubkey="-----BEGIN PUBLIC KEY----- \MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAj0dPnBMf3Z4VT1B8Ee6bjKNs \hlYj7xvGijAa8RCdmGR7mrtrExnk8mdUlwdcS05gc4SSFOyWJcYtKUHpWn8/pkS0 \vgGOl9Bzn0Xt9hiqTb3pZAfykNrMDGZMgJgfD6KTnfzVUAOupvxjcGkcoj6/vV5I \eMcx8mT/z3elfsDSjQIDAQAB \-----END PUBLIC KEY-----";
encrypt.setPublicKey(pubkey);
varencrypted=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#进行解密

usingSystem;
usingSystem.Collections.Generic;
usingSystem.IO;
usingSystem.Linq;
usingSystem.Security.Cryptography;
usingSystem.Text;
usingSystem.Threading.Tasks;
namespaceCMCloud.SaaS{
publicclassRSACryptoService    {
privateRSACryptoServiceProvider_privateKeyRsaProvider;
privateRSACryptoServiceProvider_publicKeyRsaProvider;
/// <summary>/// RSA解密/// </summary>/// <param name="cipherText"></param>/// <returns></returns>publicstringDecrypt(stringcipherText)
        {
if (_privateKeyRsaProvider==null)
            {
thrownewException("_privateKeyRsaProvider is null");
            }
returnDecrypt2(cipherText);
        }
/// <summary>/// RSA加密/// </summary>/// <param name="text"></param>/// <returns></returns>publicstringEncrypt(stringtext)
        {
if (_publicKeyRsaProvider==null)
            {
thrownewException("_publicKeyRsaProvider is null");
            }
returnEncrypt2(text);
//return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(Encoding.UTF8.GetBytes(text), false));        }
privatestringEncrypt2(stringtext)
        {
Byte[] PlaintextData=Encoding.UTF8.GetBytes(text);
intMaxBlockSize=_publicKeyRsaProvider.KeySize/8-11;//加密块最大长度限制if (PlaintextData.Length<=MaxBlockSize)
            {
returnConvert.ToBase64String(_publicKeyRsaProvider.Encrypt(PlaintextData, false));
            }
else            {
using (MemoryStreamPlaiStream=newMemoryStream(PlaintextData))
using (MemoryStreamCrypStream=newMemoryStream())
                {
Byte[] Buffer=newByte[MaxBlockSize];
intBlockSize=PlaiStream.Read(Buffer, 0, MaxBlockSize);
while (BlockSize>0)
                    {
Byte[] ToEncrypt=newByte[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);
                    }
returnConvert.ToBase64String(CrypStream.ToArray(), Base64FormattingOptions.None);
                }
            }
        }
privatestringDecrypt2(stringciphertext)
        {
Byte[] CiphertextData=Convert.FromBase64String(ciphertext);
intMaxBlockSize=_privateKeyRsaProvider.KeySize/8;    //解密块最大长度限制if (CiphertextData.Length<=MaxBlockSize)
returnSystem.Text.Encoding.UTF8.GetString(_privateKeyRsaProvider.Decrypt(CiphertextData, false));
using (MemoryStreamCrypStream=newMemoryStream(CiphertextData))
using (MemoryStreamPlaiStream=newMemoryStream())
            {
Byte[] Buffer=newByte[MaxBlockSize];
intBlockSize=CrypStream.Read(Buffer, 0, MaxBlockSize);
while (BlockSize>0)
                {
Byte[] ToDecrypt=newByte[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);
                }
returnSystem.Text.Encoding.UTF8.GetString(PlaiStream.ToArray());
            }
        }
publicRSACryptoService(stringprivateKey, stringpublicKey=null)
        {
if (!string.IsNullOrEmpty(privateKey))
            {
_privateKeyRsaProvider=CreateRsaProviderFromPrivateKey(privateKey);
            }
if (!string.IsNullOrEmpty(publicKey))
            {
_publicKeyRsaProvider=CreateRsaProviderFromPublicKey(publicKey);
            }
        }
privateRSACryptoServiceProviderCreateRsaProviderFromPrivateKey(stringprivateKey)
        {
varprivateKeyBits=System.Convert.FromBase64String(privateKey);
varRSA=newRSACryptoServiceProvider();
varRSAparams=newRSAParameters();
using (BinaryReaderbinr=newBinaryReader(newMemoryStream(privateKeyBits)))
            {
bytebt=0;
ushorttwobytes=0;
twobytes=binr.ReadUInt16();
if (twobytes==0x8130)
binr.ReadByte();
elseif (twobytes==0x8230)
binr.ReadInt16();
elsethrownewException("Unexpected value read binr.ReadUInt16()");
twobytes=binr.ReadUInt16();
if (twobytes!=0x0102)
thrownewException("Unexpected version");
bt=binr.ReadByte();
if (bt!=0x00)
thrownewException("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);
returnRSA;
        }
privateintGetIntegerSize(BinaryReaderbinr)
        {
bytebt=0;
bytelowbyte=0x00;
bytehighbyte=0x00;
intcount=0;
bt=binr.ReadByte();
if (bt!=0x02)
return0;
bt=binr.ReadByte();
if (bt==0x81)
count=binr.ReadByte();
elseif (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);
returncount;
        }
privateRSACryptoServiceProviderCreateRsaProviderFromPublicKey(stringpublicKeyString)
        {
// 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=newbyte[15];
intx509size;
x509key=Convert.FromBase64String(publicKeyString);
x509size=x509key.Length;
// ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------using (MemoryStreammem=newMemoryStream(x509key))
            {
using (BinaryReaderbinr=newBinaryReader(mem))  //wrap Memory Stream with BinaryReader for easy reading                {
bytebt=0;
ushorttwobytes=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 byteelseif (twobytes==0x8230)
binr.ReadInt16();   //advance 2 byteselsereturnnull;
seq=binr.ReadBytes(15);       //read the Sequence OIDif (!CompareBytearrays(seq, SeqOID))    //make sure Sequence for OID is correctreturnnull;
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 byteelseif (twobytes==0x8203)
binr.ReadInt16();   //advance 2 byteselsereturnnull;
bt=binr.ReadByte();
if (bt!=0x00)     //expect null byte nextreturnnull;
twobytes=binr.ReadUInt16();
if (twobytes==0x8130) //data read as little endian order (actual data order for Sequence is 30 81)binr.ReadByte();    //advance 1 byteelseif (twobytes==0x8230)
binr.ReadInt16();   //advance 2 byteselsereturnnull;
twobytes=binr.ReadUInt16();
bytelowbyte=0x00;
bytehighbyte=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 moduluselseif (twobytes==0x8202)
                    {
highbyte=binr.ReadByte(); //advance 2 byteslowbyte=binr.ReadByte();
                    }
elsereturnnull;
byte[] modint= { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian orderintmodsize=BitConverter.ToInt32(modint, 0);
intfirstbyte=binr.PeekChar();
if (firstbyte==0x00)
                    {   //if first byte (highest order) of modulus is zero, don't include itbinr.ReadByte();    //skip this null bytemodsize-=1;   //reduce modulus buffer size by 1                    }
byte[] modulus=binr.ReadBytes(modsize);   //read the modulus bytesif (binr.ReadByte() !=0x02)            //expect an Integer for the exponent datareturnnull;
intexpbytes= (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 -----RSACryptoServiceProviderRSA=newRSACryptoServiceProvider();
RSAParametersRSAKeyInfo=newRSAParameters();
RSAKeyInfo.Modulus=modulus;
RSAKeyInfo.Exponent=exponent;
RSA.ImportParameters(RSAKeyInfo);
returnRSA;
                }
            }
        }
privateboolCompareBytearrays(byte[] a, byte[] b)
        {
if (a.Length!=b.Length)
returnfalse;
inti=0;
foreach (bytecina)
            {
if (c!=b[i])
returnfalse;
i++;
            }
returntrue;
        }
    }
}

     虽然将公钥暴露在js文件中,但是如果需要解密得到明文,必须需要私钥(这个存储在后台,不容易获取)。调试运行,可以看到获取的密码是加密后的数据,然后在后台可以进行解密获取到明文。

相关文章
|
4天前
|
JavaScript 前端开发
Angular.js 应用中数据模式的删除操作实现
Angular.js 应用中数据模式的删除操作实现
16 0
|
5天前
|
存储 监控 NoSQL
Redis处理大量数据主要依赖于其内存存储结构、高效的数据结构和算法,以及一系列的优化策略
【5月更文挑战第15天】Redis处理大量数据依赖内存存储、高效数据结构和优化策略。选择合适的数据结构、利用批量操作减少网络开销、控制批量大小、使用Redis Cluster进行分布式存储、优化内存使用及监控调优是关键。通过这些方法,Redis能有效处理大量数据并保持高性能。
23 0
|
3天前
|
前端开发 JavaScript 算法
JavaScript 中实现常见数据结构:栈、队列与树
JavaScript 中实现常见数据结构:栈、队列与树
|
4天前
|
机器学习/深度学习 算法 数据挖掘
【机器学习】聚类算法中,如何判断数据是否被“充分”地聚类,以便算法产生有意义的结果?
【5月更文挑战第14天】【机器学习】聚类算法中,如何判断数据是否被“充分”地聚类,以便算法产生有意义的结果?
|
4天前
|
机器学习/深度学习 运维 算法
【机器学习】可以利用K-means算法找到数据中的离群值吗?
【5月更文挑战第14天】【机器学习】可以利用K-means算法找到数据中的离群值吗?
|
4天前
|
存储 JSON JavaScript
Node.js 上开发一个 HTTP 服务器,监听某个端口,接收 HTTP POST 请求并处理传入的数据
Node.js 上开发一个 HTTP 服务器,监听某个端口,接收 HTTP POST 请求并处理传入的数据
13 0
|
5天前
|
数据采集 机器学习/深度学习 人工智能
【机器学习】在使用K-means算法之前,如何预处理数据?
【5月更文挑战第12天】【机器学习】在使用K-means算法之前,如何预处理数据?
|
5天前
|
XML 存储 开发框架
c#教你网站数据轻松解析抓取,HtmlAgilityPack解析的奇妙之处
c#教你网站数据轻松解析抓取,HtmlAgilityPack解析的奇妙之处
13 0
|
5天前
|
机器学习/深度学习 自然语言处理 算法
Python遗传算法GA对长短期记忆LSTM深度学习模型超参数调优分析司机数据|附数据代码
Python遗传算法GA对长短期记忆LSTM深度学习模型超参数调优分析司机数据|附数据代码
|
5天前
|
SQL 存储 开发框架
C# DataSet结合FlyTreeView显示树状模型数据
C# DataSet结合FlyTreeView显示树状模型数据
http://www.vxiaotou.com