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

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 微软的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文件中,但是如果需要解密得到明文,必须需要私钥(这个存储在后台,不容易获取)。调试运行,可以看到获取的密码是加密后的数据,然后在后台可以进行解密获取到明文。

相关文章
|
2月前
|
前端开发 JavaScript Python
Python Web应用中的WebSocket实战:前后端分离时代的实时数据交换
在前后端分离的Web应用开发模式中,如何实现前后端之间的实时数据交换成为了一个重要议题。传统的轮询或长轮询方式在实时性、资源消耗和服务器压力方面存在明显不足,而WebSocket技术的出现则为这一问题提供了优雅的解决方案。本文将通过实战案例,详细介绍如何在Python Web应用中运用WebSocket技术,实现前后端之间的实时数据交换。
91 0
|
16天前
|
资源调度 前端开发 JavaScript
vite3+vue3 实现前端部署加密混淆 javascript-obfuscator
【11月更文挑战第10天】本文介绍了在 Vite 3 + Vue 3 项目中使用 `javascript-obfuscator` 实现前端代码加密混淆的详细步骤,包括安装依赖、创建混淆脚本、修改 `package.json` 脚本命令、构建项目并执行混淆,以及在 HTML 文件中引用混淆后的文件。通过这些步骤,可以有效提高代码的安全性。
|
19天前
|
前端开发 JavaScript 安全
vite3+vue3 实现前端部署加密混淆 javascript-obfuscator
【11月更文挑战第7天】本文介绍了在 Vite 3 + Vue 3 项目中使用 `javascript-obfuscator` 实现前端代码加密混淆的详细步骤。包括项目准备、安装 `javascript-obfuscator`、配置 Vite 构建以应用混淆,以及最终构建项目进行混淆。通过这些步骤,可以有效提升前端代码的安全性,防止被他人轻易分析和盗用。
|
2月前
|
SQL 缓存 分布式计算
C#如何处理上亿级数据的查询效率
C#如何处理上亿级数据的查询效率
26 1
|
2月前
|
存储 前端开发 API
前端开发中,Web Storage的存储数据的方法localstorage和sessionStorage的使用及区别
前端开发中,Web Storage的存储数据的方法localstorage和sessionStorage的使用及区别
101 0
|
2月前
|
存储 JSON 前端开发
JSON与现代Web开发:数据交互的最佳选择
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也便于机器解析和生成。它以文本格式存储数据,常用于Web应用中的数据传输,尤其是在客户端和服务器之间。
61 0
|
3月前
|
开发框架 JSON 缓存
震撼发布!Python Web开发框架下的RESTful API设计全攻略,让数据交互更自由!
在数字化浪潮推动下,RESTful API成为Web开发中不可或缺的部分。本文详细介绍了在Python环境下如何设计并实现高效、可扩展的RESTful API,涵盖框架选择、资源定义、HTTP方法应用及响应格式设计等内容,并提供了基于Flask的示例代码。此外,还讨论了版本控制、文档化、安全性和性能优化等最佳实践,帮助开发者实现更流畅的数据交互体验。
90 1
|
2月前
|
中间件 数据库连接 API
C#数据分表核心代码
C#数据分表核心代码
41 0
|
3月前
|
存储 C# 开发者
枚举与结构体的应用:C#中的数据组织艺术
在C#编程中,枚举(`enum`)和结构体(`struct`)是非常重要的数据类型。枚举用于定义命名常量集合,提高代码可读性;结构体则封装相关数据字段,适合小型数据集。本文从基本概念入手,探讨它们的使用技巧、常见问题及解决方案,帮助开发者更好地利用这些特性构建健壮的应用程序。
46 8
|
2月前
|
XML JSON 前端开发
C#使用HttpClient四种请求数据格式:json、表单数据、文件上传、xml格式
C#使用HttpClient四种请求数据格式:json、表单数据、文件上传、xml格式
396 0