Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Message too long for RSA #110

Open
afinal opened this issue Oct 30, 2017 · 8 comments
Open

Message too long for RSA #110

afinal opened this issue Oct 30, 2017 · 8 comments

Comments

@afinal
Copy link

afinal commented Oct 30, 2017

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

@benjaminwunder
Copy link

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
Copy link

lsqswl commented Oct 12, 2018

https://github.com/lsqswl/rsaencrypt

@joshuaquek
Copy link

@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
Copy link

liebig commented Jul 4, 2019

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

@xiaominghe2014
Copy link

I think you should use encryptLong

@yangfan0095
Copy link

/* 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
Copy link

CreatorEdition commented Apr 2, 2023

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
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants