| // Depends on jsbn.js and rng.js |
| |
| // Version 1.1: support utf-8 encoding in pkcs1pad2 |
| |
| // convert a (hex) string to a bignum object |
| function parseBigInt(str,r) { |
| return new BigInteger(str,r); |
| } |
| |
| 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); |
| } |
| |
| /** |
| * PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint |
| * @param s: the string to encode |
| * @param n: the size in byte |
| */ |
| function pkcs1pad2(s,n) { |
| if(n < s.length + 11) { // TODO: fix for utf-8 |
| alert("Message too long for RSA"); |
| return null; |
| } |
| var ba = new Array(); |
| 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 = new Array(); |
| 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 |
| * @returns {RSAKey} |
| */ |
| 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; |
| } |
| |
| /** |
| * Set the public key fields N and e from hex strings |
| * @param N |
| * @param E |
| * @returns {RSASetPublic} |
| */ |
| function RSASetPublic(N,E) { |
| if(N != null && E != null && N.length > 0 && E.length > 0) { |
| this.n = parseBigInt(N,16); |
| this.e = parseInt(E,16); |
| } |
| else |
| alert("Invalid RSA public key"); |
| } |
| |
| /** |
| * Perform raw public operation on "x": return x^e (mod n) |
| * @param x |
| * @returns x^e (mod n) |
| */ |
| function RSADoPublic(x) { |
| return x.modPowInt(this.e, this.n); |
| } |
| |
| /** |
| * Return the PKCS#1 RSA encryption of "text" as an even-length hex string |
| */ |
| function RSAEncrypt(text) { |
| var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3); |
| if(m == null) return null; |
| var c = this.doPublic(m); |
| if(c == null) return null; |
| var h = c.toString(16); |
| if((h.length & 1) == 0) return h; else return "0" + h; |
| } |
| |
| // 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; |
| //} |
| |
| // protected |
| RSAKey.prototype.doPublic = RSADoPublic; |
| |
| // public |
| RSAKey.prototype.setPublic = RSASetPublic; |
| RSAKey.prototype.encrypt = RSAEncrypt; |
| //RSAKey.prototype.encrypt_b64 = RSAEncryptB64; |