RSA加解密,可加密的最长明文长度为1024bit,即128字节,但是某段明文长度小于128字节,就需要进行padding,因为如果没有padding,用户无法确分解密后内容的真实长度。由于padding的存在,占用了明文的11字节长度,最后一次能加密的明文长度就变为传说中的117字节。
附上一段运用js的rsa加解密代码:
加密:
import { Buffer } from 'buffer'
import { publicEncrypt, constants } from 'crypto'
const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH/b8R+bDeOArUlvxe7nN1gPTO
oV3YmuwQoqH2B1TjfaADBMzZYnRJg+uBJ0dSYzGBj5yR/6jNNJG9ElM9oIXe4BZ5
YGeAeUmdars9lgdbN3sYf9pV7EZhuu7ClxSC75L0Ni8HlOhHXx6fS2VxN0Y8d5bY
VeuD+WMDoxqaTJt80QIDAQAB
-----END PUBLIC KEY-----`
export const encrypt = origin => {
const buffer = Buffer.from(encodeURI(JSON.stringify(origin)))
const blocks = Math.ceil(buffer.length / 117)
const cipherBuffer = Buffer.alloc(blocks * 128)
for (let i = 0; i < blocks; i++) {
const chunk = buffer.slice(i * 117, (i + 1) * 117)
publicEncrypt({
key: publicKey,
padding: constants.RSA_PKCS1_PADDING
}, chunk).copy(cipherBuffer, i * 128)
}
return cipherBuffer.toString('base64')
}
解密:
import { privateDecrypt, constants } from 'crypto'
import { privateKey } from '../config/auth'
const blockDecrypt = block => {
try {
const decrypted = privateDecrypt({
key: privateKey,
padding: constants.RSA_PKCS1_PADDING
}, block)
return decrypted
} catch (err) {
if (block.length === 128) {
return blockDecrypt(block.slice(0, 127))
}
throw err
}
}
export const decrypt = cipher => {
if (!cipher) {
throw new Error('ciper cannot be null')
}
let rtn = ''
const buffer = Buffer.from(cipher, 'base64')
const blocks = Math.ceil(buffer.length / 128)
for (let i = 0; i < blocks; i++) {
rtn += blockDecrypt(buffer.slice(i * 128, (i + 1) * 128))
}
return decodeURI(rtn)
}
公钥私钥可以自己随意生成,只要配对就好,这里着重提下,解密时blockDecrypt中的catch,在实际的操作中经常碰到,密文最后一个字符为0,这种情况下,解密就会失败,所以采用catch处理这一情形,保证解密的正常进行。(具体这个最后的0,出现的原因现在还没有很明白)