forked from rachanon/stdbWeb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
195 lines
4.5 KiB
195 lines
4.5 KiB
/*! (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 |
|
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); |
|
} |
|
|
|
// 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 |
|
function oaep_pad(s, n, hash, hashLen) |
|
{ |
|
if (!hash) |
|
{ |
|
hash = rstr_sha1; |
|
hashLen = 20; |
|
} |
|
|
|
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; |
|
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 |
|
alert("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";
|
|
|