RSA算法实现

实现RSA算法及其依赖算法,UTF8<->Unicode;Base64;GCD;LCD;扩展欧几里得算法;快速积;快速幂;快速幂模;费马小定理;二次探测定理;埃氏筛法;米勒拉宾算法;RSA算法。

nodejs v12.14.0运行

"use strict";

// unicode <-> utf8
class UTF8 {
    static native2utf8(codes) {
        let r = [];
        for (let i=0; i<codes.length; i++) {
            let code = codes[i];

            if (code <= 0x7f) {
                r.push(code);
            }
            else if (code <= 0x7ff) {
                r.push( (code >> 6) | 0xc0);
                r.push( (code & 0x3f) | 0x80);
            }
            else if (code <= 0xffff) {
                r.push( (code >> 12) | 0xe0);
                r.push( ((code >> 6) & 0x3f) | 0x80);
                r.push( (code & 0x3f) | 0x80);
            }
            else if (code <= 0x10FFFF) {
                r.push( (code >> 18) | 0xf0);
                r.push( (code >> 12) | 0xe0);
                r.push( ((code >> 6) & 0x3f) | 0x80);
                r.push( (code & 0x3f) | 0x80);
            }
            else 
                throw "Unsupport code : " + code;
        }
        return r;
    }

    static utf82native(bytes) {
        let r = [];
        let i = 0;
        while (i<bytes.length) {
            if ((bytes[i] & 0xf0) == 0xf0) {
                r.push( (((bytes[i] & 0x7) << 18) | ((bytes[i+1] & 0x3f) << 12) | ((bytes[i+2] & 0x3f) << 6) | (bytes[i+3] & 0x3f) ));
                i += 4;
            }
            else if ((bytes[i] & 0xe0) == 0xe0) {
                r.push( ((bytes[i] & 0x0f) << 12) | ((bytes[i+1] & 0x3f) << 6) | (bytes[i+2] & 0x3f) );
                i += 3;
            }
            else if ((bytes[i] & 0xc0) == 0xc0) {
                r.push( ((bytes[i] & 0x3f) << 6) | (bytes[i+1] & 0x3f) );
                i += 2;
            }
            else if ((bytes[i] & 0x7f) == bytes[i]) {
                r.push( bytes[i] & 0x7f );
                i += 1;
            }
            else 
                throw "error :" + bytes[i];
            
        }
        return r;
    }
}


// Base64 encode & decode
class Base64 {

    static TABLE = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'];

	static encode(_arr) {
        let arr = UTF8.native2utf8(_arr);
		var div = Math.floor(arr.length / 3);
		var mod = arr.length % 3; 
		
		var result = [];
		var t = new Array();
		
		for (var i=0; i<div; i++) {
			t[0] = arr[i * 3];
			t[1] = arr[i * 3 + 1];
			t[2] = arr[i * 3 + 2];
			
			result.push( this.TABLE[ t[0] >> 2 ] );
			result.push( this.TABLE[ (t[0] << 6 & 0xff) >> 2 | (t[1] >> 4) ] );
			result.push( this.TABLE[ (t[1] << 4 & 0xff) >> 2 | (t[2] >> 6) ] );
			result.push( this.TABLE[ (t[2] << 2 & 0xff) >> 2 ] );
		}
		
		if (mod == 1) {
			t[0] = arr[i * 3];
			result.push( this.TABLE[ t[0] >> 2 ] );
			result.push( this.TABLE[ (t[0] << 6 & 0xff) >> 2 ] );
			result.push( '=' );
			result.push( '=' );
		}
		else if (mod == 2) {
			t[0] = arr[i * 3];
			t[1] = arr[i * 3 + 1];
			
			result.push( this.TABLE[ t[0] >> 2 ] );
			result.push( this.TABLE[ (t[0] << 6 & 0xff) >> 2 | (t[1] >> 4) ] );
			result.push( this.TABLE[ (t[1] << 4 & 0xff) >> 2 ] );
			result.push( '=' );
		}
		return result.join("");
	}

	static decode(str) {
		var result = [];
		
		for (var i=0; i<Math.floor(str.length / 4); i++) {
			var t = new Array();
			t[0] = this.TABLE.indexOf( str.charAt(i * 4) );
			t[1] = this.TABLE.indexOf( str.charAt(i * 4 + 1) );
			t[2] = this.TABLE.indexOf( str.charAt(i * 4 + 2) );
			t[3] = this.TABLE.indexOf( str.charAt(i * 4 + 3) );
						
			result.push( (t[0] << 2 & 0xff) | t[1] >> 4 );
			
			if (t[1] != -1 && t[2] != -1)
				result.push( (t[1] << 4 & 0xff) | t[2] >> 2 );
			
			if (t[2] != -1 && t[3] != -1) 
				result.push( (t[2] << 6 & 0xff) | t[3] ) ;
        }

		return UTF8.utf82native(result);
	}
	

}

// 欧几里得算法 Greatest Common Divisor
function Euclidean(a, b) {
    if (a < b) {
        a = a + b;
        b = a - b;
        a = a - b;
    }
    let c = a % b;
    while (c > 0) {
        a = b;
        b = c;
        c = a % b;
    }
    return b;
}

// 扩展欧几里得算法
function ExtendedEuclidean(a, b) {
    if (b == 0) {
        return {a: a, b: b, x: 1, y: 0, r: a };
    }
    else {
        let f = ExtendedEuclidean(b, a % b);
        let y = f.x - parseInt(a/b) * f.y;
        let x = f.y;
        return {a: a, b: b, x: x, y: y, r: f.r };
    }
}

// Least Common Multiple
function lcm(a , b) {
    return a * b / Euclidean(a,b);
}

// 快速积算法
function mul(a, b) {
    let r = 0, i = 1;
    while (b > 0) {
        let t = i;
        if (b & 1 == 1) {
            t *= a;
            r += t;
        }
        i <<= 1;
        b >>= 1;
    }
    return r;
}

// 快速幂算法
function pow(a, b) {
    let binaryBitsLength = 0, t = b;
    while (t != 0) {
        t = Math.floor(t / 2);
        binaryBitsLength ++;
    }

    let r = 1;
    for (let i=1; i<=binaryBitsLength; i++) {
        r = r * r;
        if ( (b & (1 << binaryBitsLength-i)) != 0 )
            r = r * a;
    }
    return r;
}

/*
    蒙哥马利幂模运算 
    a ^ b % n => a ^ (b1+b2+bn) %n => (a^b1 * a^b2 * a^bn) % n => (a^b1 % n) * (a^b2 %n) * (a^bn %n)
*/
function Montgomery(a, b, n) {  // Math.pow(a,b) % n
    let binaryLength = 0, t = b;
    while (t != 0) {
        t = Math.floor(t / 2);
        binaryLength ++;
    }

    let r = 1;
    for (let i=1; i<=binaryLength; i++) {
        r = r * r % n;
        if ( (b & (1 << binaryLength-i)) != 0 )
            r = r * a % n;
    }
    return r;
}

// 费马小定理
function Fermat(a, p) {
    return Montgomery(a, p-1, p) == 1;
}

/*
    二次探测定理
    a^(p-1) = a^(m • 2^q) ≡ 1 (mod p) => a^(p-1) = (a^m)^(2^q) ≡ 1 (mod p) => (a^m)^2 = [(a^m)^2]^2 = [((a^m)^2)^2]^2 = X^2 ≡ 1 (mod p)
*/
function twice(a, p) {
    let q = 0, m = p - 1;
    while (m & 1 == 0) { // 2^q * m
        q ++ ;
        m >>= 1;
    }

    a = Montgomery(a, m, p);

    for (let i=q; i>=1; i--) {
        let r = a*a % p ;
        if (r == 1 &&  a != 1 && a != p-1) 
            return false;
        a = r;

    }
    return true;
}

// 埃氏筛法
function Eratosthenes(n) {
    let bits = new Array(n);
    bits.fill(1);
    bits[1] = 0;

    let i = 2;
    while (i<n/2) {
        if (bits[i] == 1) 
            for (let j=i+1; j<n;j++)
                if (j % i == 0) 
                    bits[j] = 0;

        i++;
    }

    let out = [];
    for (let i=1; i<n; i++) {
        if (bits[i] == 1)
            out.push(i);
    }
    return out;
}

/*
 米勒-拉宾算法
*/
function MillerRabin(n) {
    const basePrime = [2,3,5,7,11,13,17,19];
    const carmichael = [561, 1105, 1729, 2465,2821,6601, 8911, 10585, 15841,29341,41041, 46657, 52633,62745, 63973, 75361 ];

    let bits = new Array(n+1);
    bits.fill(0); 
    basePrime.map(i=>{ bits[i] = 1 });


    for (let i = 21; i<=n; i+=2 ) {
        if (i & 1 == 0) // 是偶数
            continue ;

        if (carmichael.includes(i) )
            continue ;

        let b = true;

        for (let j of basePrime) {

            if (j >= i)
                break ;
            
            b = Fermat(j, i);
            if (b == false) {
                break;
            }

            b = twice(j, i);
            if (b == false)
                break ;
        }

        bits[i] = b ? 1 : 0;
        
    }
    
    let out = [];
    for (let i=1; i<n; i++) {
        if (bits[i] == 1)
            out.push(i);
    }
    return out;
}

// RSA算法
class RSA {
    constructor() {
        let primes = Eratosthenes(Math.pow(2, 8));
        let p = primes[ 2+parseInt(Math.random() * (primes.length-2))];
        let q = primes[ 2+parseInt(Math.random() * (primes.length-2))];
        while (p == q) 
            q = primes[ 2+parseInt(Math.random() * (primes.length-2))];
        this.n = p * q;
        let o = (p-1) * (q-1);
        primes = MillerRabin(o);
        this.key1 =  primes[ 2+parseInt(Math.random() * (primes.length-2))];
        console.debug("p=%d,q=%d,n=%d,φ=%d",p,q,this.n,o);
        let r = ExtendedEuclidean(this.key1, o);
        r.x2 = r.x;
        while (r.x2 < 0) {
            r.x2 += o;
        }
        console.debug("%dx+%dy=1 (%dx' mod %d=1) : x=%d, x'=%d, y=%d",r.a, r.b, r.a, o, r.x, r.x2, r.y);
        this.key2 = r.x2;
        console.debug("Key-1: ", this.key1, this.n);
        console.debug("Key-2: ", this.key2, this.n);

        if (this.key1 == this.key2) {
            throw "key same";
        }
    }

    encryption(s) {
        let secret = [];
        for (let i=0; i<s.length; i++) {
            let code = s.charCodeAt(i); 
            secret.push( Montgomery(code, this.key1,this.n) );
        }
        return secret ;
    }

    decryption(secret) {
        let plain = "";
        for (let i=0; i<secret.length; i++) {
            let code = secret[i];
            plain += String.fromCharCode(Montgomery(code, this.key2, this.n));
        }
    
        return plain;
    
    }
}

执行结果:

RSA Key1、Key2,Test

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值