travist / jsencrypt

A zero-dependency Javascript library to perform OpenSSL RSA Encryption, Decryption, and Key Generation.
http://www.travistidwell.com/jsencrypt
Other
6.69k stars 2.02k forks source link

Message too long for RSA #110

Open afinal opened 7 years ago

afinal commented 7 years ago

let encrypt = new JSEncrypt(); encrypt.setPublicKey(PUBLIC_KEY); let RequestData = encrypt.encrypt(JSON.stringify({method, data}));

benjaminwunder commented 6 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.

https://crypto.stackexchange.com/questions/14/how-can-i-use-asymmetric-encryption-such-as-rsa-to-encrypt-an-arbitrary-length

lsqswl commented 6 years ago

https://github.com/lsqswl/rsaencrypt

joshuaquek commented 6 years ago

@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

liebig commented 5 years ago

Is there a library that encrypts larger amounts of data and runs in the browser? Thanks a lot!

xiaominghe2014 commented 5 years ago

I think you should use encryptLong

yangfan0095 commented 4 years ago
/* 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

CreatorEdition commented 1 year ago

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;
        },
sutaungmai commented 3 months ago

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