1. 前言
之前被面试官问了https,从CA问到密钥交换,从rsa问到ecc。怀疑是上一位面试的葛哪儿嗯卷,然后刚好我信安专业的就继续问了。毕业之后就没看过,不多说,js手撕一遍整套流程复习就完事儿了
2. RSA算法
实际上面试只需要知道四个知识点一般就够了
2.1 非对称加密算法在https中用来对 对称加密算法的密钥 进行加密
2.2 私钥加密 -〉 公钥解密 公钥加密 -〉 私钥解密
2.3 RSA是非对称加密算法
2.4 数论基础就是基于大数分解的困难度
3. 算法实现
关于对称加密非对称加密的定义以及RSA加密的整个流程,请参考阮一峰教程。此处将阮一峰教程分步解析为js代码
本文只分步编写容易理解的代码,暂不考虑代码性能
第一步,随机选择两个不相等的质数p和q
function isPrimeNumber(v) {
for (let i = 2; i < v; i++) {
if (v % i === 0) {
return false;
}
}
return true;
}
function getPrimeNumber(min, max) {
let rst = [];
for(let i = Math.max(2, min); i <= max; i++) {
if(isPrimeNumber(i)) {
rst.push(i);
}
}
return rst;
}
let primeNumberList = getPrimeNumber(10, 100);
const pIndex = Math.floor(Math.random() * 1000) % primeNumberList.length;
const p = primeNumberList[pIndex];
primeNumberList.splice(pIndex, 1);
const qIndex = Math.floor(Math.random() * 1000) % primeNumberList.length;
const q = primeNumberList[qIndex]
第二步 计算p和q的乘积n
const n = p * q;
第三步 计算n的欧拉函数φ(n)
const olaN = (p-1) * (q-1);
第四步 随机选择一个整数e,条件是1< e < φ(n),且e与φ(n) 互质(辗转相除法)
function getGCD(a, b) {
const big = a > b ? a : b;
const small = a < b ? a : b;
if (big%small===0) return small;
return getGCD(big%small, small);
}
// range: [min, max)
function getRandom(min, max) {
return Math.floor(Math.random() * (max-min)) + min;
}
primeNumberList = [];
for(let i = 1; i < olaN; i++) {
if (getGCD(i, olaN) === 1) primeNumberList.push(i);
}
const e = primeNumberList[getRandom(2, primeNumberList.length)];
第五步 计算e对于φ(n)的模反元素d(扩展欧几里得算法计算乘法逆元)
function exGetGCD(a, b, receiveObj) {
if (b === 0) { // 递归基取1, 0
receiveObj.x = 1;
receiveObj.y = 0;
return a;
}
const greatestCommonDivisor = exGetGCD(b, a%b, receiveObj);
const temp = receiveObj.y;
receiveObj.y = receiveObj.x - Math.floor(a/b) * receiveObj.y;
receiveObj.x = temp;
return greatestCommonDivisor;
}
const receiveObj = {x: null, y: null};
const testVal = exGetGCD(e, olaN, receiveObj); // testVal = 1, just for teaching
while (receiveObj.x < 0) {
receiveObj.x += olaN
}
const d = receiveObj.x;
第六步 将n和e封装成公钥,n和d封装成私钥
console.log(`public key: (${n}, ${e})`);
console.log(`private key: (${n}, ${d})`)
console.log(`p, q, olaN: ${p}, ${q}, ${olaN}`)
console.log(`n, e, d: ${n}, ${e}, ${d}`)
第七步 RSA算法的可靠性(证明过程略)
第八步 加密和解密
const BigNumber = require('big-number')
function rsaEncrypt(n, e, content) {
return BigNumber(content).pow(e).mod(n);
}
function rsaDecrypt(n, d, content) {
return BigNumber(content).pow(d).mod(n);
}
第九步 运行
const content = '69';
console.log('content: ', content);
const encryptedContent = rsaEncrypt(n, e, content)
console.log('encrypted content: ', encryptedContent.toString())
const decryptContent = rsaDecrypt(n, d, encryptedContent)
console.log('decrypted content: ', decryptContent.toString())
4. 结尾
其实什么库都不想引入的,下篇ECC写完之后把bignumber计算库撸一撸,造轮子舒服~造轮子快乐~ 随手点个👍吧