NodeJS自定义RSA实现解密结果异常问题排查
RSA解密结果不符的问题排查与修复
我来帮你搞定这个问题——你的解密环节出错的核心原因是JavaScript的Math.pow()处理大整数幂运算时会丢失精度,下面详细拆解问题并给出可行的修复方案:
问题根源:大数幂运算的精度限制
JavaScript里的Number类型是64位双精度浮点数,它只能精确表示小于2^53的整数。当你用Math.pow(char, d)计算加密后数值的高次幂时(比如8^29,这个数远大于2^53),Math.pow()返回的是一个近似值,而非精确的整数,后续取模%n自然会得到错误的结果,导致解密出的字符和原消息不符。
举个例子:8^29的精确值是154742504910672534362390528,但Math.pow(8,29)返回的是近似值,丢失了末尾的精确数位,这就直接导致解密取模出错。
修复方案:使用快速幂取模算法
解决这个问题的关键是避免直接计算完整的大幂值,改用快速幂取模(模幂运算)——在计算过程中不断对结果取模,让数值始终保持在较小的范围内,从而避免精度丢失。
修改后的完整代码
const p = 7; // 选择的质数 const q = 13; // 选择的质数 const n = p * q; const e = 5; // 公钥指数 const publicKey = [e, n]; // 公钥(注:你原代码里的密钥注释写反了) const d = 29; // 私钥指数 const privateKey = [d, n]; // 私钥 // 快速幂取模函数:安全计算 (base^exponent) % mod function modPow(base, exponent, mod) { let result = 1; base = base % mod; // 确保基数先落在mod范围内 while (exponent > 0) { // 如果指数是奇数,将当前基数乘入结果并取模 if (exponent % 2 === 1) { result = (result * base) % mod; } // 指数折半,基数平方后取模 exponent = Math.floor(exponent / 2); base = (base * base) % mod; } return result; } let message = 'hello'; let encrypted = []; message = message.toUpperCase(); // 加密流程 for (let i = 0; i < message.length; i++) { const charCode = message.charCodeAt(i) - 64; // 转换为A=1, B=2...Z=26的数值 const cipher = modPow(charCode, e, n); // 用快速幂取模计算加密值 encrypted.push(cipher); } // 解密流程 console.log('解密结果:'); encrypted.forEach(cipher => { const originalCharCode = modPow(cipher, d, n); // 用快速幂取模计算明文数值 console.log(String.fromCharCode(originalCharCode + 64)); });
额外注意事项
- 密钥注释修正:你原代码里把公钥和私钥的注释写反了——
[e, n]是公钥(用于加密),[d, n]是私钥(用于解密),别搞混哦。 - 密钥合法性验证:你的密钥是符合RSA要求的:φ(n)=(p-1)(q-1)=612=72,
e*d=5*29=145,145%72=1,满足(e*d) % φ(n) = 1的核心条件,所以密钥本身是没问题的。
运行修改后的代码,解密结果就会正确输出HELLO啦!
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

