// Depends on jsbn.js and rng.js 
 | 
// Version 1.1: support utf-8 encoding in pkcs1pad2 
 | 
// convert a (hex) string to a bignum object 
 | 
import { BigInteger, nbi, parseBigInt } from "./jsbn"; 
 | 
import { SecureRandom } from "./rng"; 
 | 
// function linebrk(s,n) { 
 | 
//   var ret = ""; 
 | 
//   var i = 0; 
 | 
//   while(i + n < s.length) { 
 | 
//     ret += s.substring(i,i+n) + "\n"; 
 | 
//     i += n; 
 | 
//   } 
 | 
//   return ret + s.substring(i,s.length); 
 | 
// } 
 | 
// function byte2Hex(b) { 
 | 
//   if(b < 0x10) 
 | 
//     return "0" + b.toString(16); 
 | 
//   else 
 | 
//     return b.toString(16); 
 | 
// } 
 | 
function pkcs1pad1(s, n) { 
 | 
    if (n < s.length + 22) { 
 | 
        console.error("Message too long for RSA"); 
 | 
        return null; 
 | 
    } 
 | 
    var len = n - s.length - 6; 
 | 
    var filler = ""; 
 | 
    for (var f = 0; f < len; f += 2) { 
 | 
        filler += "ff"; 
 | 
    } 
 | 
    var m = "0001" + filler + "00" + s; 
 | 
    return parseBigInt(m, 16); 
 | 
} 
 | 
// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint 
 | 
function pkcs1pad2(s, n) { 
 | 
    if (n < s.length + 11) { // TODO: fix for utf-8 
 | 
        console.error("Message too long for RSA"); 
 | 
        return null; 
 | 
    } 
 | 
    var ba = []; 
 | 
    var i = s.length - 1; 
 | 
    while (i >= 0 && n > 0) { 
 | 
        var c = s.charCodeAt(i--); 
 | 
        if (c < 128) { // encode using utf-8 
 | 
            ba[--n] = c; 
 | 
        } 
 | 
        else if ((c > 127) && (c < 2048)) { 
 | 
            ba[--n] = (c & 63) | 128; 
 | 
            ba[--n] = (c >> 6) | 192; 
 | 
        } 
 | 
        else { 
 | 
            ba[--n] = (c & 63) | 128; 
 | 
            ba[--n] = ((c >> 6) & 63) | 128; 
 | 
            ba[--n] = (c >> 12) | 224; 
 | 
        } 
 | 
    } 
 | 
    ba[--n] = 0; 
 | 
    var rng = new SecureRandom(); 
 | 
    var x = []; 
 | 
    while (n > 2) { // random non-zero pad 
 | 
        x[0] = 0; 
 | 
        while (x[0] == 0) { 
 | 
            rng.nextBytes(x); 
 | 
        } 
 | 
        ba[--n] = x[0]; 
 | 
    } 
 | 
    ba[--n] = 2; 
 | 
    ba[--n] = 0; 
 | 
    return new BigInteger(ba); 
 | 
} 
 | 
// "empty" RSA key constructor 
 | 
var RSAKey = /** @class */ (function () { 
 | 
    function RSAKey() { 
 | 
        this.n = null; 
 | 
        this.e = 0; 
 | 
        this.d = null; 
 | 
        this.p = null; 
 | 
        this.q = null; 
 | 
        this.dmp1 = null; 
 | 
        this.dmq1 = null; 
 | 
        this.coeff = null; 
 | 
    } 
 | 
    //#region PROTECTED 
 | 
    // protected 
 | 
    // RSAKey.prototype.doPublic = RSADoPublic; 
 | 
    // Perform raw public operation on "x": return x^e (mod n) 
 | 
    RSAKey.prototype.doPublic = function (x) { 
 | 
        return x.modPowInt(this.e, this.n); 
 | 
    }; 
 | 
    // RSAKey.prototype.doPrivate = RSADoPrivate; 
 | 
    // Perform raw private operation on "x": return x^d (mod n) 
 | 
    RSAKey.prototype.doPrivate = function (x) { 
 | 
        if (this.p == null || this.q == null) { 
 | 
            return x.modPow(this.d, this.n); 
 | 
        } 
 | 
        // TODO: re-calculate any missing CRT params 
 | 
        var xp = x.mod(this.p).modPow(this.dmp1, this.p); 
 | 
        var xq = x.mod(this.q).modPow(this.dmq1, this.q); 
 | 
        while (xp.compareTo(xq) < 0) { 
 | 
            xp = xp.add(this.p); 
 | 
        } 
 | 
        return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq); 
 | 
    }; 
 | 
    //#endregion PROTECTED 
 | 
    //#region PUBLIC 
 | 
    // RSAKey.prototype.setPublic = RSASetPublic; 
 | 
    // Set the public key fields N and e from hex strings 
 | 
    RSAKey.prototype.setPublic = function (N, E) { 
 | 
        if (N != null && E != null && N.length > 0 && E.length > 0) { 
 | 
            this.n = parseBigInt(N, 16); 
 | 
            this.e = parseInt(E, 16); 
 | 
        } 
 | 
        else { 
 | 
            console.error("Invalid RSA public key"); 
 | 
        } 
 | 
    }; 
 | 
    // RSAKey.prototype.encrypt = RSAEncrypt; 
 | 
    // Return the PKCS#1 RSA encryption of "text" as an even-length hex string 
 | 
    RSAKey.prototype.encrypt = function (text) { 
 | 
        var maxLength = (this.n.bitLength() + 7) >> 3; 
 | 
        var m = pkcs1pad2(text, maxLength); 
 | 
        if (m == null) { 
 | 
            return null; 
 | 
        } 
 | 
        var c = this.doPublic(m); 
 | 
        if (c == null) { 
 | 
            return null; 
 | 
        } 
 | 
        var h = c.toString(16); 
 | 
        var length = h.length; 
 | 
        // fix zero before result 
 | 
        for (var i = 0; i < maxLength * 2 - length; i++) { 
 | 
            h = "0" + h; 
 | 
        } 
 | 
        return h; 
 | 
    }; 
 | 
    // RSAKey.prototype.setPrivate = RSASetPrivate; 
 | 
    // Set the private key fields N, e, and d from hex strings 
 | 
    RSAKey.prototype.setPrivate = function (N, E, D) { 
 | 
        if (N != null && E != null && N.length > 0 && E.length > 0) { 
 | 
            this.n = parseBigInt(N, 16); 
 | 
            this.e = parseInt(E, 16); 
 | 
            this.d = parseBigInt(D, 16); 
 | 
        } 
 | 
        else { 
 | 
            console.error("Invalid RSA private key"); 
 | 
        } 
 | 
    }; 
 | 
    // RSAKey.prototype.setPrivateEx = RSASetPrivateEx; 
 | 
    // Set the private key fields N, e, d and CRT params from hex strings 
 | 
    RSAKey.prototype.setPrivateEx = function (N, E, D, P, Q, DP, DQ, C) { 
 | 
        if (N != null && E != null && N.length > 0 && E.length > 0) { 
 | 
            this.n = parseBigInt(N, 16); 
 | 
            this.e = parseInt(E, 16); 
 | 
            this.d = parseBigInt(D, 16); 
 | 
            this.p = parseBigInt(P, 16); 
 | 
            this.q = parseBigInt(Q, 16); 
 | 
            this.dmp1 = parseBigInt(DP, 16); 
 | 
            this.dmq1 = parseBigInt(DQ, 16); 
 | 
            this.coeff = parseBigInt(C, 16); 
 | 
        } 
 | 
        else { 
 | 
            console.error("Invalid RSA private key"); 
 | 
        } 
 | 
    }; 
 | 
    // RSAKey.prototype.generate = RSAGenerate; 
 | 
    // Generate a new random private key B bits long, using public expt E 
 | 
    RSAKey.prototype.generate = function (B, E) { 
 | 
        var rng = new SecureRandom(); 
 | 
        var qs = B >> 1; 
 | 
        this.e = parseInt(E, 16); 
 | 
        var ee = new BigInteger(E, 16); 
 | 
        for (;;) { 
 | 
            for (;;) { 
 | 
                this.p = new BigInteger(B - qs, 1, rng); 
 | 
                if (this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) { 
 | 
                    break; 
 | 
                } 
 | 
            } 
 | 
            for (;;) { 
 | 
                this.q = new BigInteger(qs, 1, rng); 
 | 
                if (this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) { 
 | 
                    break; 
 | 
                } 
 | 
            } 
 | 
            if (this.p.compareTo(this.q) <= 0) { 
 | 
                var t = this.p; 
 | 
                this.p = this.q; 
 | 
                this.q = t; 
 | 
            } 
 | 
            var p1 = this.p.subtract(BigInteger.ONE); 
 | 
            var q1 = this.q.subtract(BigInteger.ONE); 
 | 
            var phi = p1.multiply(q1); 
 | 
            if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { 
 | 
                this.n = this.p.multiply(this.q); 
 | 
                this.d = ee.modInverse(phi); 
 | 
                this.dmp1 = this.d.mod(p1); 
 | 
                this.dmq1 = this.d.mod(q1); 
 | 
                this.coeff = this.q.modInverse(this.p); 
 | 
                break; 
 | 
            } 
 | 
        } 
 | 
    }; 
 | 
    // RSAKey.prototype.decrypt = RSADecrypt; 
 | 
    // Return the PKCS#1 RSA decryption of "ctext". 
 | 
    // "ctext" is an even-length hex string and the output is a plain string. 
 | 
    RSAKey.prototype.decrypt = function (ctext) { 
 | 
        var c = parseBigInt(ctext, 16); 
 | 
        var m = this.doPrivate(c); 
 | 
        if (m == null) { 
 | 
            return null; 
 | 
        } 
 | 
        return pkcs1unpad2(m, (this.n.bitLength() + 7) >> 3); 
 | 
    }; 
 | 
    // Generate a new random private key B bits long, using public expt E 
 | 
    RSAKey.prototype.generateAsync = function (B, E, callback) { 
 | 
        var rng = new SecureRandom(); 
 | 
        var qs = B >> 1; 
 | 
        this.e = parseInt(E, 16); 
 | 
        var ee = new BigInteger(E, 16); 
 | 
        var rsa = this; 
 | 
        // These functions have non-descript names because they were originally for(;;) loops. 
 | 
        // I don't know about cryptography to give them better names than loop1-4. 
 | 
        var loop1 = function () { 
 | 
            var loop4 = function () { 
 | 
                if (rsa.p.compareTo(rsa.q) <= 0) { 
 | 
                    var t = rsa.p; 
 | 
                    rsa.p = rsa.q; 
 | 
                    rsa.q = t; 
 | 
                } 
 | 
                var p1 = rsa.p.subtract(BigInteger.ONE); 
 | 
                var q1 = rsa.q.subtract(BigInteger.ONE); 
 | 
                var phi = p1.multiply(q1); 
 | 
                if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) { 
 | 
                    rsa.n = rsa.p.multiply(rsa.q); 
 | 
                    rsa.d = ee.modInverse(phi); 
 | 
                    rsa.dmp1 = rsa.d.mod(p1); 
 | 
                    rsa.dmq1 = rsa.d.mod(q1); 
 | 
                    rsa.coeff = rsa.q.modInverse(rsa.p); 
 | 
                    setTimeout(function () { callback(); }, 0); // escape 
 | 
                } 
 | 
                else { 
 | 
                    setTimeout(loop1, 0); 
 | 
                } 
 | 
            }; 
 | 
            var loop3 = function () { 
 | 
                rsa.q = nbi(); 
 | 
                rsa.q.fromNumberAsync(qs, 1, rng, function () { 
 | 
                    rsa.q.subtract(BigInteger.ONE).gcda(ee, function (r) { 
 | 
                        if (r.compareTo(BigInteger.ONE) == 0 && rsa.q.isProbablePrime(10)) { 
 | 
                            setTimeout(loop4, 0); 
 | 
                        } 
 | 
                        else { 
 | 
                            setTimeout(loop3, 0); 
 | 
                        } 
 | 
                    }); 
 | 
                }); 
 | 
            }; 
 | 
            var loop2 = function () { 
 | 
                rsa.p = nbi(); 
 | 
                rsa.p.fromNumberAsync(B - qs, 1, rng, function () { 
 | 
                    rsa.p.subtract(BigInteger.ONE).gcda(ee, function (r) { 
 | 
                        if (r.compareTo(BigInteger.ONE) == 0 && rsa.p.isProbablePrime(10)) { 
 | 
                            setTimeout(loop3, 0); 
 | 
                        } 
 | 
                        else { 
 | 
                            setTimeout(loop2, 0); 
 | 
                        } 
 | 
                    }); 
 | 
                }); 
 | 
            }; 
 | 
            setTimeout(loop2, 0); 
 | 
        }; 
 | 
        setTimeout(loop1, 0); 
 | 
    }; 
 | 
    RSAKey.prototype.sign = function (text, digestMethod, digestName) { 
 | 
        var header = getDigestHeader(digestName); 
 | 
        var digest = header + digestMethod(text).toString(); 
 | 
        var m = pkcs1pad1(digest, this.n.bitLength() / 4); 
 | 
        if (m == null) { 
 | 
            return null; 
 | 
        } 
 | 
        var c = this.doPrivate(m); 
 | 
        if (c == null) { 
 | 
            return null; 
 | 
        } 
 | 
        var h = c.toString(16); 
 | 
        if ((h.length & 1) == 0) { 
 | 
            return h; 
 | 
        } 
 | 
        else { 
 | 
            return "0" + h; 
 | 
        } 
 | 
    }; 
 | 
    RSAKey.prototype.verify = function (text, signature, digestMethod) { 
 | 
        var c = parseBigInt(signature, 16); 
 | 
        var m = this.doPublic(c); 
 | 
        if (m == null) { 
 | 
            return null; 
 | 
        } 
 | 
        var unpadded = m.toString(16).replace(/^1f+00/, ""); 
 | 
        var digest = removeDigestHeader(unpadded); 
 | 
        return digest == digestMethod(text).toString(); 
 | 
    }; 
 | 
    return RSAKey; 
 | 
}()); 
 | 
export { RSAKey }; 
 | 
// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext 
 | 
function pkcs1unpad2(d, n) { 
 | 
    var b = d.toByteArray(); 
 | 
    var i = 0; 
 | 
    while (i < b.length && b[i] == 0) { 
 | 
        ++i; 
 | 
    } 
 | 
    if (b.length - i != n - 1 || b[i] != 2) { 
 | 
        return null; 
 | 
    } 
 | 
    ++i; 
 | 
    while (b[i] != 0) { 
 | 
        if (++i >= b.length) { 
 | 
            return null; 
 | 
        } 
 | 
    } 
 | 
    var ret = ""; 
 | 
    while (++i < b.length) { 
 | 
        var c = b[i] & 255; 
 | 
        if (c < 128) { // utf-8 decode 
 | 
            ret += String.fromCharCode(c); 
 | 
        } 
 | 
        else if ((c > 191) && (c < 224)) { 
 | 
            ret += String.fromCharCode(((c & 31) << 6) | (b[i + 1] & 63)); 
 | 
            ++i; 
 | 
        } 
 | 
        else { 
 | 
            ret += String.fromCharCode(((c & 15) << 12) | ((b[i + 1] & 63) << 6) | (b[i + 2] & 63)); 
 | 
            i += 2; 
 | 
        } 
 | 
    } 
 | 
    return ret; 
 | 
} 
 | 
// https://tools.ietf.org/html/rfc3447#page-43 
 | 
var DIGEST_HEADERS = { 
 | 
    md2: "3020300c06082a864886f70d020205000410", 
 | 
    md5: "3020300c06082a864886f70d020505000410", 
 | 
    sha1: "3021300906052b0e03021a05000414", 
 | 
    sha224: "302d300d06096086480165030402040500041c", 
 | 
    sha256: "3031300d060960864801650304020105000420", 
 | 
    sha384: "3041300d060960864801650304020205000430", 
 | 
    sha512: "3051300d060960864801650304020305000440", 
 | 
    ripemd160: "3021300906052b2403020105000414" 
 | 
}; 
 | 
function getDigestHeader(name) { 
 | 
    return DIGEST_HEADERS[name] || ""; 
 | 
} 
 | 
function removeDigestHeader(str) { 
 | 
    for (var name_1 in DIGEST_HEADERS) { 
 | 
        if (DIGEST_HEADERS.hasOwnProperty(name_1)) { 
 | 
            var header = DIGEST_HEADERS[name_1]; 
 | 
            var len = header.length; 
 | 
            if (str.substr(0, len) == header) { 
 | 
                return str.substr(len); 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
    return str; 
 | 
} 
 | 
// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string 
 | 
// function RSAEncryptB64(text) { 
 | 
//  var h = this.encrypt(text); 
 | 
//  if(h) return hex2b64(h); else return null; 
 | 
// } 
 | 
// public 
 | 
// RSAKey.prototype.encrypt_b64 = RSAEncryptB64; 
 |