From e8465350fc2d1f4c09f25f18118bfb8fdf7fb1b4 Mon Sep 17 00:00:00 2001 From: Bart Butler Date: Sat, 28 Feb 2015 03:43:39 -0800 Subject: [PATCH] Support for crypto API keygen in IE11 on Windows 7 and 8 --- src/crypto/public_key/rsa.js | 58 +++++++++++++++++++++++++----------- src/util.js | 9 ++++-- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/crypto/public_key/rsa.js b/src/crypto/public_key/rsa.js index fe293897..1d92216e 100644 --- a/src/crypto/public_key/rsa.js +++ b/src/crypto/public_key/rsa.js @@ -140,12 +140,33 @@ function RSA() { // Native RSA keygen using Web Crypto // + function convertKeyOperation(keyop, errmsg) { + return new Promise(function(resolve, reject) { + keyop.onerror = function (err) { + reject(new Error(errmsg)); + } + keyop.oncomplete = function (e) { + resolve(e.target.result); + } + }); + } + if (webCrypto) { var Euint32 = new Uint32Array([parseInt(E, 16)]); // get integer of exponent var Euint8 = new Uint8Array(Euint32.buffer); // get bytes of exponent var keyGenOpt; - if (window.crypto.subtle) { + var keys; + if (window.crypto && window.crypto.webkitSubtle) { + // outdated spec implemented by Webkit + keyGenOpt = { + name: 'RSA-OAEP', + modulusLength: B, // the specified keysize in bits + publicExponent: Euint8.subarray(0, 3), // take three bytes (max 65537) + }; + keys = webCrypto.generateKey(keyGenOpt, true, ['encrypt', 'decrypt']); + } + else { // current standard spec keyGenOpt = { name: 'RSASSA-PKCS1-v1_5', @@ -155,29 +176,30 @@ function RSA() { name: 'SHA-1' // not required for actual RSA keys, but for crypto api 'sign' and 'verify' } }; - return webCrypto.generateKey(keyGenOpt, true, ['sign', 'verify']).then(exportKey).then(decodeKey); - - } else if (window.crypto.webkitSubtle) { - // outdated spec implemented by Webkit - keyGenOpt = { - name: 'RSA-OAEP', - modulusLength: B, // the specified keysize in bits - publicExponent: Euint8.subarray(0, 3), // take three bytes (max 65537) - }; - return webCrypto.generateKey(keyGenOpt, true, ['encrypt', 'decrypt']).then(exportKey).then(function(key) { - if (key instanceof ArrayBuffer) { - // parse raw ArrayBuffer bytes to jwk/json (WebKit/Safari quirk) - return decodeKey(JSON.parse(String.fromCharCode.apply(null, new Uint8Array(key)))); - } - return decodeKey(key); - }); + + keys = webCrypto.generateKey(keyGenOpt, true, ['sign', 'verify']); + if(!(keys instanceof Promise)) { // IE11 KeyOperation + keys = convertKeyOperation(keys, 'Error generating RSA key pair.'); + } } + + return keys.then(exportKey).then(function(key) { + if (key instanceof ArrayBuffer) { + // parse raw ArrayBuffer bytes to jwk/json (WebKit/Safari/IE11 quirk) + return decodeKey(JSON.parse(String.fromCharCode.apply(null, new Uint8Array(key)))); + } + return decodeKey(key); + }); } function exportKey(keypair) { // export the generated keys as JsonWebKey (JWK) // https://tools.ietf.org/html/draft-ietf-jose-json-web-key-33 - return webCrypto.exportKey('jwk', keypair.privateKey); + key = webCrypto.exportKey('jwk', keypair.privateKey); + if(!(key instanceof Promise)) { // IE11 KeyOperation + key = convertKeyOperation(key, 'Error exporting RSA key pair.'); + } + return key; } function decodeKey(jwk) { diff --git a/src/util.js b/src/util.js index 89a08387..c2f9c386 100644 --- a/src/util.js +++ b/src/util.js @@ -320,8 +320,13 @@ module.exports = { return; } - if (typeof window !== 'undefined' && window.crypto) { - return window.crypto.subtle || window.crypto.webkitSubtle; + if (typeof window !== 'undefined') { + if(window.crypto) { + return window.crypto.subtle || window.crypto.webkitSubtle; + } + if(window.msCrypto) { + return window.msCrypto.subtle; + } } } };