Skip to content

Commit

Permalink
Add native keygen support for IE.
Browse files Browse the repository at this point in the history
- Use 'pkcs8' export format.
  • Loading branch information
dlongley committed Jun 28, 2016
1 parent 4970af5 commit 7609279
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 11 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -772,10 +772,14 @@ __Examples__
var rsa = forge.pki.rsa;

// generate an RSA key pair synchronously
// *NOT RECOMMENDED* -- can be significantly slower than async and will not
// use native APIs if available.
var keypair = rsa.generateKeyPair({bits: 2048, e: 0x10001});

// generate an RSA key pair asynchronously (uses web workers if available)
// use workers: -1 to run a fast core estimator to optimize # of workers
// *RECOMMENDED* - can be significantly faster than sync -- and will use
// native APIs if available.
rsa.generateKeyPair({bits: 2048, workers: 2}, function(err, keypair) {
// keypair.privateKey, keypair.publicKey
});
Expand Down
52 changes: 41 additions & 11 deletions js/rsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -880,8 +880,9 @@ pki.rsa.generateKeyPair = function(bits, e, options, callback) {
}

// if native code is permitted and a callback is given, use native
// key generation code if available
if(!forge.disableNativeCode && callback) {
// key generation code if available and if parameters are acceptable
if(!forge.disableNativeCode && callback &&
bits >= 256 && bits <= 16384 && (e === 0x10001 || e === 3)) {
if(_detectSubtleCrypto('generateKey') && _detectSubtleCrypto('exportKey')) {
// use standard native generateKey
return window.crypto.subtle.generateKey({
Expand All @@ -891,21 +892,49 @@ pki.rsa.generateKeyPair = function(bits, e, options, callback) {
hash: {name: 'SHA-256'}
}, true /* key can be exported*/, ['sign', 'verify'])
.then(function(pair) {
return window.crypto.subtle.exportKey('jwk', pair.privateKey);
return window.crypto.subtle.exportKey('pkcs8', pair.privateKey);
}).catch(function(err) {
callback(err);
}).then(function(jwk) {
if(jwk) {
}).then(function(pkcs8) {
if(pkcs8) {
var privateKey = pki.privateKeyFromAsn1(
asn1.fromDer(forge.util.createBuffer(pkcs8)));
callback(null, {
privateKey: _privateKeyFromJwk(jwk),
publicKey: _publicKeyFromJwk(jwk)
privateKey: privateKey,
publicKey: pki.setRsaPublicKey(privateKey.n, privateKey.e)
});
}
});
}
if(_detectSubtleMsCrypto('generateKey')) {
// TODO: use deprecated MS native generateKey
//return;
if(_detectSubtleMsCrypto('generateKey') &&
_detectSubtleMsCrypto('exportKey')) {
var genOp = window.msCrypto.subtle.generateKey({
name: 'RSASSA-PKCS1-v1_5',
modulusLength: bits,
publicExponent: _intToUint8Array(e),
hash: {name: 'SHA-256'}
}, true /* key can be exported*/, ['sign', 'verify']);
genOp.oncomplete = function(e) {
var pair = e.target.result;
var exportOp = window.msCrypto.subtle.exportKey(
'pkcs8', pair.privateKey);
exportOp.oncomplete = function(e) {
var pkcs8 = e.target.result;
var privateKey = pki.privateKeyFromAsn1(
asn1.fromDer(forge.util.createBuffer(pkcs8)));
callback(null, {
privateKey: privateKey,
publicKey: pki.setRsaPublicKey(privateKey.n, privateKey.e)
});
};
exportOp.onerror = function(err) {
callback(err);
};
};
genOp.onerror = function(err) {
callback(err);
};
return;
}
}

Expand Down Expand Up @@ -1722,7 +1751,8 @@ function _intToUint8Array(x) {

function _privateKeyFromJwk(jwk) {
if(jwk.kty !== 'RSA') {
throw new Error('Key algorithm must be "RSA".');
throw new Error(
'Unsupported key algorithm "' + jwk.kty + '"; algorithm must be "RSA".');
}
return pki.setRsaPrivateKey(
_base64ToBigInt(jwk.n),
Expand Down

0 comments on commit 7609279

Please sign in to comment.