Open afinal opened 7 years ago
Public Key Encryption can only handle small amounts of data related to the size of the key being used. For larger amounts of data you need to use a hybrid approach.
@afinal I created a library as a wrapper that helps does encryption and decryption of RSA public-private keypairs natively in Javascript around 5 months ago, you can check it out here:
https://github.com/joshuaquek/QuickEncrypt https://www.npmjs.com/package/quick-encrypt
Is there a library that encrypts larger amounts of data and runs in the browser? Thanks a lot!
I think you should use encryptLong
/* eslint-disable no-plusplus */
/* eslint-disable block-scoped-var */
/* eslint-disable func-names */
/* eslint-disable no-bitwise */
import { JSEncrypt } from 'jsencrypt'
// Convert a hex string to a byte array
function hexToBytes(hex: string) {
// eslint-disable-next-line prefer-const
let bytes = []
for (let c = 0; c < hex.length; c += 2) {
bytes.push(parseInt(hex.substr(c, 2), 16))
}
return bytes
}
// Convert a byte array to a hex string
function bytesToHex(bytes: string | any[]) {
const hex = []
for (let i = 0; i < bytes.length; i++) {
hex.push((bytes[i] >>> 4).toString(16))
hex.push((bytes[i] & 0xf).toString(16))
}
return hex.join('')
}
// 方法一
JSEncrypt.prototype.encryptLong = function (d) {
const k = this.key
// eslint-disable-next-line no-bitwise
const maxLength = ((k.n.bitLength() + 7) >> 3) - 11
try {
let lt = ''
let ct = ''
if (d.length > maxLength) {
lt = d.match(/.{1,117}/g) || ''
// eslint-disable-next-line func-names
lt.forEach(function (entry: any) {
const t1 = k.encrypt(entry)
ct += t1
})
return hexToBytes(ct)
}
const t = k.encrypt(d)
const y = hexToBytes(t)
return y
} catch (ex) {
return false
}
}
JSEncrypt.prototype.decryptLong = function (string) {
const k = this.getKey()
const maxLength = (k.n.bitLength() + 7) >> 3
// var maxLength = 128;
try {
const str = bytesToHex(string)
// var b=hex2Bytes(str);
// const inputLen = str.length
let ct = ''
if (str.length > maxLength) {
const lt = str.match(/.{1,256}/g) || ''
lt.forEach(function (entry: any) {
const t1 = k.decrypt(entry)
ct += t1
})
return ct
}
const y = k.decrypt(bytesToHex(string))
return y
} catch (ex) {
return false
}
}
const b64map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
const b64pad = '='
function hex2b64(d: any) {
let b
let e
let a = ''
for (b = 0; b + 3 <= d.length; b += 3) {
e = parseInt(d.substring(b, b + 3), 16)
a += b64map.charAt(e >> 6) + b64map.charAt(e & 63)
}
if (b + 1 === d.length) {
e = parseInt(d.substring(b, b + 1), 16)
a += b64map.charAt(e << 2)
} else if (b + 2 === d.length) {
e = parseInt(d.substring(b, b + 2), 16)
a += b64map.charAt(e >> 2) + b64map.charAt((e & 3) << 4)
}
while ((a.length & 3) > 0) {
a += b64pad
}
return a
}
/**
* 长文本加密
* @param {string} string 待加密长文本
* @returns {string} 加密后的base64编码
* */
JSEncrypt.prototype.encryptLong = function (string) {
const k = this.getKey()
try {
let ct = ''
// RSA每次加密117bytes,需要辅助方法判断字符串截取位置
// 1.获取字符串截取点
const bytes = []
bytes.push(0)
let byteNo = 0
let c
const len = string.length
let temp = 0
for (let i = 0; i < len; i++) {
c = string.charCodeAt(i)
if (c >= 0x010000 && c <= 0x10ffff) {
// 特殊字符,如Ř,Ţ
byteNo += 4
} else if (c >= 0x000800 && c <= 0x00ffff) {
// 中文以及标点符号
byteNo += 3
} else if (c >= 0x000080 && c <= 0x0007ff) {
// 特殊字符,如È,Ò
byteNo += 2
} else {
// 英文以及标点符号
byteNo += 1
}
if (byteNo % 117 >= 114 || byteNo % 117 === 0) {
if (byteNo - temp >= 114) {
bytes.push(i)
temp = byteNo
}
}
}
// 2.截取字符串并分段加密
if (bytes.length > 1) {
for (let i = 0; i < bytes.length - 1; i++) {
let str
if (i === 0) {
str = string.substring(0, bytes[i + 1] + 1)
} else {
str = string.substring(bytes[i] + 1, bytes[i + 1] + 1)
}
const t1 = k.encrypt(str)
ct += t1
}
if (bytes[bytes.length - 1] !== string.length - 1) {
const lastStr = string.substring(bytes[bytes.length - 1] + 1)
ct += k.encrypt(lastStr)
}
return hex2b64(ct)
}
const t = k.encrypt(string)
const y = hex2b64(t)
return y
} catch (ex) {
return false
}
}
// 之前ssl生成的公钥,复制的时候要小心不要有空格
// example : https://github.com/travist/jsencrypt
export const setContentByPublicKey = (pubKey: string, content: string) => {
if (!pubKey || !content) {
return ''
}
const encryptor = new JSEncrypt() // 创建加密对象实例
encryptor.setPublicKey(pubKey) // 设置公钥
const rsaPassWord = encryptor.encryptLong(content) // 对内容进行加密
return rsaPassWord
}
this is my working code , copy from others
You can try the following code 你可以尝试以下代码,通过分块加密
/**
* 分段加密长字符串
* @param {string} str the string to encrypt
* @return {string} the encrypted string encoded in base64
* @public
*/
encryptLong: function(str,$key) {
var encryptor = new JSEncrypt();
encryptor.setPublicKey($key);
var maxChunkLength = 100,
output = '',
inOffset = 0,
outOffset = 0;
while (inOffset < str.length) {
console.log(str.substring(inOffset, inOffset + maxChunkLength));
output += encryptor.encrypt(str.substring(inOffset, inOffset + maxChunkLength));
inOffset += maxChunkLength;
}
return output;
},
/**
* 长文本解密
* @param {string} string 加密后的base64编码
* @returns {string} 解密后的原文
*/
decryptLong: function(string,$key) {
var decryptor = new JSEncrypt();
decryptor.setPrivateKey($key);
var maxChunkLength = 172,
output = '',
inOffset = 0,
outOffset = 0;
while (inOffset < string.length) {
console.log(string.substring(inOffset, inOffset + maxChunkLength));
output += decryptor.decrypt(string.substring(inOffset, inOffset + maxChunkLength));
inOffset += maxChunkLength;
}
return output;
},
I have the same issue in react-native app but I tried to use this package instead of jsencrypt. it works for me @lsqswl/rsaencrypt
let encrypt = new JSEncrypt(); encrypt.setPublicKey(PUBLIC_KEY); let RequestData = encrypt.encrypt(JSON.stringify({method, data}));