|
|
@ -8,6 +8,9 @@ |
|
|
|
OAUTH3.crypto.core = require('./oauth3.node.crypto'); |
|
|
|
} catch (error) { |
|
|
|
OAUTH3.crypto.core = {}; |
|
|
|
OAUTH3.crypto.core.ready = false; |
|
|
|
var finishBeforeReady = []; |
|
|
|
var deferedCalls = []; |
|
|
|
|
|
|
|
// We don't currently have a fallback method for this function, so we assign
|
|
|
|
// it directly to the core object instead of the webCrypto object.
|
|
|
@ -17,10 +20,31 @@ |
|
|
|
}; |
|
|
|
|
|
|
|
var webCrypto = {}; |
|
|
|
|
|
|
|
var deferCryptoCall = function(name) { |
|
|
|
return function() { |
|
|
|
var args = arguments; |
|
|
|
return new OAUTH3.PromiseA(function(resolve, reject) { |
|
|
|
deferedCalls.push(function(){ |
|
|
|
try { |
|
|
|
webCrypto[name].apply(webCrypto, args) |
|
|
|
.then(function(result){ |
|
|
|
resolve(result); |
|
|
|
}); |
|
|
|
} catch(e) { |
|
|
|
reject(e); |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
OAUTH3.crypto.core.sha256 = deferCryptoCall("sha256"); |
|
|
|
webCrypto.sha256 = function (buf) { |
|
|
|
return OAUTH3._browser.window.crypto.subtle.digest({name: 'SHA-256'}, buf); |
|
|
|
}; |
|
|
|
|
|
|
|
OAUTH3.crypto.core.pbkdf2 = deferCryptoCall("pbkdf2"); |
|
|
|
webCrypto.pbkdf2 = function (password, salt) { |
|
|
|
return OAUTH3._browser.window.crypto.subtle.importKey('raw', OAUTH3._binStr.binStrToBuffer(password), {name: 'PBKDF2'}, false, ['deriveKey']) |
|
|
|
.then(function (key) { |
|
|
@ -32,12 +56,15 @@ |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
OAUTH3.crypto.core.encrypt = deferCryptoCall("encrypt"); |
|
|
|
webCrypto.encrypt = function (rawKey, iv, data) { |
|
|
|
return OAUTH3._browser.window.crypto.subtle.importKey('raw', rawKey, {name: 'AES-GCM'}, false, ['encrypt']) |
|
|
|
.then(function (key) { |
|
|
|
return OAUTH3._browser.window.crypto.subtle.encrypt({name: 'AES-GCM', iv: iv}, key, data); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
OAUTH3.crypto.core.decrypt = deferCryptoCall("decrypt"); |
|
|
|
webCrypto.decrypt = function (rawKey, iv, data) { |
|
|
|
return OAUTH3._browser.window.crypto.subtle.importKey('raw', rawKey, {name: 'AES-GCM'}, false, ['decrypt']) |
|
|
|
.then(function (key) { |
|
|
@ -45,6 +72,7 @@ |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
OAUTH3.crypto.core.genEcdsaKeyPair = deferCryptoCall("genEcdsaKeyPair"); |
|
|
|
webCrypto.genEcdsaKeyPair = function () { |
|
|
|
return OAUTH3._browser.window.crypto.subtle.generateKey({name: 'ECDSA', namedCurve: 'P-256'}, true, ['sign', 'verify']) |
|
|
|
.then(function (keyPair) { |
|
|
@ -57,6 +85,7 @@ |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
OAUTH3.crypto.core.sign = deferCryptoCall("sign"); |
|
|
|
webCrypto.sign = function (jwk, msg) { |
|
|
|
return OAUTH3._browser.window.crypto.subtle.importKey('jwk', jwk, {name: 'ECDSA', namedCurve: jwk.crv}, false, ['sign']) |
|
|
|
.then(function (key) { |
|
|
@ -66,6 +95,8 @@ |
|
|
|
return new Uint8Array(sig); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
OAUTH3.crypto.core.verify = deferCryptoCall("verify"); |
|
|
|
webCrypto.verify = function (jwk, msg, signature) { |
|
|
|
// If the JWK has properties that should only exist on the private key or is missing
|
|
|
|
// "verify" in the key_ops, importing in as a public key won't work.
|
|
|
@ -103,18 +134,19 @@ |
|
|
|
return prom; |
|
|
|
}; |
|
|
|
function checkException(name, func) { |
|
|
|
OAUTH3.PromiseA.resolve().then(func) |
|
|
|
return OAUTH3.PromiseA.resolve().then(func) |
|
|
|
.then(function () { |
|
|
|
OAUTH3.crypto.core[name] = webCrypto[name]; |
|
|
|
}, function (err) { |
|
|
|
console.warn('error with WebCrypto', name, '- using fallback', err); |
|
|
|
loadFallback().then(function () { |
|
|
|
return loadFallback().then(function () { |
|
|
|
OAUTH3.crypto.core[name] = OAUTH3_crypto_fallback[name]; |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
function checkResult(name, expected, func) { |
|
|
|
checkException(name, function () { |
|
|
|
|
|
|
|
finishBeforeReady.push(checkException(name, function () { |
|
|
|
return func() |
|
|
|
.then(function (result) { |
|
|
|
if (typeof expected === typeof result) { |
|
|
@ -127,7 +159,7 @@ |
|
|
|
throw new Error("result ("+result+") doesn't match expectation ("+expected+")"); |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
})); |
|
|
|
} |
|
|
|
|
|
|
|
var zeroBuf = new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]); |
|
|
@ -159,12 +191,20 @@ |
|
|
|
return webCrypto.verify(jwk, dataBuf, sig); |
|
|
|
}); |
|
|
|
// The results of these functions are less predictable, so we can't check their return value.
|
|
|
|
checkException('genEcdsaKeyPair', function () { |
|
|
|
finishBeforeReady.push(checkException('genEcdsaKeyPair', function () { |
|
|
|
return webCrypto.genEcdsaKeyPair(); |
|
|
|
}); |
|
|
|
checkException('sign', function () { |
|
|
|
})); |
|
|
|
finishBeforeReady.push(checkException('sign', function () { |
|
|
|
return webCrypto.sign(jwk, dataBuf); |
|
|
|
}); |
|
|
|
})); |
|
|
|
|
|
|
|
OAUTH3.PromiseA.all(finishBeforeReady) |
|
|
|
.then(function(results) { |
|
|
|
OAUTH3.crypto.core.ready = true; |
|
|
|
deferedCalls.forEach(function(request) { |
|
|
|
request(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
checkWebCrypto(); |
|
|
|
} |
|
|
|