android js rsa加密,同时兼容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

543deb089ffdd550019999fce023ff23.png

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

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

cef0e9dc7a60772a5a8508f4357878ba.png

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

8a87b1c3062fee03e67444d7a7d05d5b.png

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

-----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包文件

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;

///

/// RSA解密

///

///

///

public string Decrypt(string cipherText)

{

if (_privateKeyRsaProvider == null)

{

throw new Exception("_privateKeyRsaProvider is null");

}

return Decrypt2(cipherText);

}

///

/// RSA加密

///

///

///

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;

}

}

}

54e42dbbdc0a9b10cd4ae3152f8ec3ef.png

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

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

0afd7d13bc92b388980f383272483ba9.png

总结

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值