oidc-client
Version:
OpenID Connect (OIDC) & OAuth2 client library
213 lines (183 loc) • 5.87 kB
JavaScript
/*! (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.<br/>
* 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";