/*! (c) Tom Wu | http://www-cs-students.stanford.edu/~tjw/jsbn/ */ // 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 function pkcs1pad2(s,n) { if(n < s.length + 11) { // TODO: fix for utf-8 throw "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); } // PKCS#1 (OAEP) mask generation function function oaep_mgf1_arr(seed, len, hash) { var mask = '', i = 0; while (mask.length < len) { mask += hash(String.fromCharCode.apply(String, seed.concat([ (i & 0xff000000) >> 24, (i & 0x00ff0000) >> 16, (i & 0x0000ff00) >> 8, i & 0x000000ff]))); i += 1; } return mask; } /** * PKCS#1 (OAEP) pad input string s to n bytes, and return a bigint * @name oaep_pad * @param s raw string of message * @param n key length of RSA key * @param hash JavaScript function to calculate raw hash value from raw string or algorithm name (ex. "SHA1") * @param hashLen byte length of resulted hash value (ex. 20 for SHA1) * @return {BigInteger} BigInteger object of resulted PKCS#1 OAEP padded message * @description * This function calculates OAEP padded message from original message.
* NOTE: Since jsrsasign 6.2.0, 'hash' argument can accept an algorithm name such as "sha1". * @example * oaep_pad("aaa", 128) → big integer object // SHA-1 by default * oaep_pad("aaa", 128, function(s) {...}, 20); * oaep_pad("aaa", 128, "sha1"); */ function oaep_pad(s, n, hash, hashLen) { var MD = KJUR.crypto.MessageDigest; var Util = KJUR.crypto.Util; var algName = null; if (!hash) hash = "sha1"; if (typeof hash === "string") { algName = MD.getCanonicalAlgName(hash); hashLen = MD.getHashLength(algName); hash = function(s) { return hextorstr(Util.hashHex(rstrtohex(s), algName)); }; } if (s.length + 2 * hashLen + 2 > n) { throw "Message too long for RSA"; } var PS = '', i; for (i = 0; i < n - s.length - 2 * hashLen - 2; i += 1) { PS += '\x00'; } var DB = hash('') + PS + '\x01' + s; var seed = new Array(hashLen); new SecureRandom().nextBytes(seed); var dbMask = oaep_mgf1_arr(seed, DB.length, hash); var maskedDB = []; for (i = 0; i < DB.length; i += 1) { maskedDB[i] = DB.charCodeAt(i) ^ dbMask.charCodeAt(i); } var seedMask = oaep_mgf1_arr(maskedDB, seed.length, hash); var maskedSeed = [0]; for (i = 0; i < seed.length; i += 1) { maskedSeed[i + 1] = seed[i] ^ seedMask.charCodeAt(i); } return new BigInteger(maskedSeed.concat(maskedDB)); } // "empty" RSA key constructor 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 function RSASetPublic(N, E) { this.isPublic = true; this.isPrivate = false; if (typeof N !== "string") { this.n = N; this.e = E; } else if(N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N,16); this.e = parseInt(E,16); } else { throw "Invalid RSA public key"; } } // Perform raw public operation on "x": return 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 OAEP RSA encryption of "text" as an even-length hex string function RSAEncryptOAEP(text, hash, hashLen) { var m = oaep_pad(text, (this.n.bitLength() + 7) >> 3, hash, hashLen); 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.encryptOAEP = RSAEncryptOAEP; //RSAKey.prototype.encrypt_b64 = RSAEncryptB64; RSAKey.prototype.type = "RSA";