changed the API for most of the crypto functions

thus far I don't think anyone uses those functions so this should be safe
This commit is contained in:
tigerbot 2017-07-28 13:02:36 -06:00
parent 28dbf9ab23
commit 5a5488f504
2 changed files with 75 additions and 74 deletions

View File

@ -207,12 +207,12 @@
}
, jwt: {
// decode only (no verification)
decode: function (str) {
decode: function (token, opts) {
// 'abc.qrs.xyz'
// [ 'abc', 'qrs', 'xyz' ]
// {}
var parts = str.split(/\./g);
var parts = token.split(/\./g);
var err;
if (parts.length !== 3) {
err = new Error("Invalid JWT: required 3 '.' separated components not "+parts.length);
@ -220,14 +220,55 @@
throw err;
}
return JSON.parse(OAUTH3._base64.decodeUrlSafe(parts[1]));
if (!opts || !opts.complete) {
return JSON.parse(OAUTH3._base64.decodeUrlSafe(parts[1]));
}
return {
header: JSON.parse(OAUTH3._base64.decodeUrlSafe(parts[0]))
, payload: JSON.parse(OAUTH3._base64.decodeUrlSafe(parts[1]))
};
}
, verify: function (jwk, token) {
, verify: function (token, jwk) {
if (!OAUTH3.crypto) {
return OAUTH3.PromiseA.reject(new Error("OAuth3 crypto library unavailable"));
}
jwk = jwk.publicKey || jwk;
var parts = token.split(/\./g);
var data = OAUTH3._binStr.binStrToBuffer(parts.slice(0, 2).join('.'));
var signature = OAUTH3._base64.urlSafeToBuffer(parts[2]);
return OAUTH3.crypto.core.verify(jwk, data, signature);
return OAUTH3.crypto.core.verify(jwk, data, signature).then(function () {
return OAUTH3.jwt.decode(token);
});
}
, sign: function (payload, jwk) {
if (!OAUTH3.crypto) {
return OAUTH3.PromiseA.reject(new Error("OAuth3 crypto library unavailable"));
}
jwk = jwk.privateKey || jwk;
var prom;
if (jwk.kid) {
prom = OAUTH3.PromiseA.resolve(jwk.kid);
} else {
prom = OAUTH3.crypto.thumbprintJwk(jwk);
}
return prom.then(function (kid) {
// Currently the crypto part of the OAuth3 library only supports ES256
var header = {type: 'JWT', alg: 'ES256', kid: kid};
var input = [
OAUTH3._base64.encodeUrlSafe(JSON.stringify(header, null))
, OAUTH3._base64.encodeUrlSafe(JSON.stringify(payload, null))
].join('.');
return OAUTH3.crypto.core.sign(jwk, OAUTH3._binStr.binStrToBuffer(input))
.then(OAUTH3._base64.bufferToUrlSafe)
.then(function (signature) {
return input + '.' + signature;
});
});
}
, freshness: function (tokenMeta, staletime, now) {
// If the token doesn't expire then it's always fresh.

View File

@ -1,5 +1,5 @@
;(function (exports) {
'use strict';
'use strict';
var OAUTH3 = exports.OAUTH3 = exports.OAUTH3 || require('./oauth3.core.js').OAUTH3;
@ -82,6 +82,7 @@
};
function checkWebCrypto() {
/* global OAUTH3_crypto_fallback */
var loadFallback = function() {
var prom;
loadFallback = function () { return prom; };
@ -102,11 +103,10 @@
return prom;
};
function checkException(name, func) {
new OAUTH3.PromiseA(function (resolve) { resolve(func()); })
OAUTH3.PromiseA.resolve().then(func)
.then(function () {
OAUTH3.crypto.core[name] = webCrypto[name];
})
.catch(function (err) {
}, function (err) {
console.warn('error with WebCrypto', name, '- using fallback', err);
loadFallback().then(function () {
OAUTH3.crypto.core[name] = OAUTH3_crypto_fallback[name];
@ -195,101 +195,61 @@
.then(OAUTH3._base64.bufferToUrlSafe);
};
OAUTH3.crypto._createKey = function (ppid) {
var saltProm = OAUTH3.crypto.core.randomBytes(16);
var kekProm = saltProm.then(function (salt) {
return OAUTH3.crypto.core.pbkdf2(ppid, salt);
});
var ecdsaProm = OAUTH3.crypto.core.genEcdsaKeyPair()
.then(function (keyPair) {
OAUTH3.crypto.createKeyPair = function () {
// TODO: maybe support other types of key pairs, not just ECDSA P-256
return OAUTH3.crypto.core.genEcdsaKeyPair().then(function (keyPair) {
return OAUTH3.crypto.thumbprintJwk(keyPair.publicKey).then(function (kid) {
keyPair.privateKey.alg = keyPair.publicKey.alg = 'ES256';
keyPair.privateKey.kid = keyPair.publicKey.kid = kid;
return keyPair;
});
});
};
OAUTH3.crypto.encryptKeyPair = function (keyPair, password) {
var saltProm = OAUTH3.crypto.core.randomBytes(16);
var kekProm = saltProm.then(function (salt) {
return OAUTH3.crypto.core.pbkdf2(password, salt);
});
return OAUTH3.PromiseA.all([
kekProm
, ecdsaProm
, saltProm
, OAUTH3.crypto.core.randomBytes(16)
, OAUTH3.crypto.core.randomBytes(12)
, OAUTH3.crypto.core.randomBytes(12)
]).then(function (results) {
, ]).then(function (results) {
var kek = results[0];
var keyPair = results[1];
var salt = results[2];
var userSecret = results[3];
var ecdsaIv = results[4];
var secretIv = results[5];
var salt = results[1];
var ecdsaIv = results[2];
return OAUTH3.PromiseA.all([
OAUTH3.crypto.core.encrypt(kek, ecdsaIv, OAUTH3._binStr.binStrToBuffer(JSON.stringify(keyPair.privateKey)))
, OAUTH3.crypto.core.encrypt(kek, secretIv, userSecret)
])
.then(function (encrypted) {
var privKeyBuf = OAUTH3._binStr.binStrToBuffer(JSON.stringify(keyPair.privateKey));
return OAUTH3.crypto.core.encrypt(kek, ecdsaIv, privKeyBuf).then(function (encrypted) {
return {
publicKey: keyPair.publicKey
, privateKey: OAUTH3._base64.bufferToUrlSafe(encrypted[0])
, userSecret: OAUTH3._base64.bufferToUrlSafe(encrypted[1])
, privateKey: OAUTH3._base64.bufferToUrlSafe(encrypted)
, salt: OAUTH3._base64.bufferToUrlSafe(salt)
, ecdsaIv: OAUTH3._base64.bufferToUrlSafe(ecdsaIv)
, secretIv: OAUTH3._base64.bufferToUrlSafe(secretIv)
};
, };
});
});
};
OAUTH3.crypto._decryptKey = function (ppid, storedObj) {
OAUTH3.crypto.decryptKeyPair = function (storedObj, password) {
var salt = OAUTH3._base64.urlSafeToBuffer(storedObj.salt);
var encJwk = OAUTH3._base64.urlSafeToBuffer(storedObj.privateKey);
var iv = OAUTH3._base64.urlSafeToBuffer(storedObj.ecdsaIv);
return OAUTH3.crypto.core.pbkdf2(ppid, salt)
return OAUTH3.crypto.core.pbkdf2(password, salt)
.then(function (key) {
return OAUTH3.crypto.core.decrypt(key, iv, encJwk);
})
.then(OAUTH3._binStr.bufferToBinStr)
.then(JSON.parse);
};
OAUTH3.crypto._getKey = function (ppid) {
return OAUTH3.crypto.core.sha256(OAUTH3._binStr.binStrToBuffer(ppid))
.then(function (hash) {
var name = 'kek-' + OAUTH3._base64.bufferToUrlSafe(hash);
var promise;
if (window.localStorage.getItem(name) === null) {
promise = OAUTH3.crypto._createKey(ppid).then(function (key) {
window.localStorage.setItem(name, JSON.stringify(key));
return key;
});
} else {
promise = OAUTH3.PromiseA.resolve(JSON.parse(window.localStorage.getItem(name)));
}
return promise.then(function (storedObj) {
return OAUTH3.crypto._decryptKey(ppid, storedObj);
.then(JSON.parse)
.then(function (privateKey) {
return {
privateKey: privateKey
, publicKey: storedObj.publicKey
, };
});
});
};
OAUTH3.crypto._signPayload = function (payload) {
return OAUTH3.crypto._getKey('some PPID').then(function (key) {
var header = {type: 'JWT', alg: key.alg, kid: key.kid};
var input = [
OAUTH3._base64.encodeUrlSafe(JSON.stringify(header, null))
, OAUTH3._base64.encodeUrlSafe(JSON.stringify(payload, null))
].join('.');
return OAUTH3.crypto.core.sign(key, OAUTH3._binStr.binStrToBuffer(input))
.then(OAUTH3._base64.bufferToUrlSafe)
.then(function (signature) {
return input + '.' + signature;
});
});
};
}('undefined' !== typeof exports ? exports : window));