Cleanup RSA and util code
This commit is contained in:
parent
55bd9757e7
commit
4d325ca65c
|
@ -29,6 +29,9 @@
|
||||||
"before": true,
|
"before": true,
|
||||||
"beforeEach": true,
|
"beforeEach": true,
|
||||||
"after": true,
|
"after": true,
|
||||||
"afterEach": true
|
"afterEach": true,
|
||||||
|
"escape": true,
|
||||||
|
"unescape": true,
|
||||||
|
"asmCrypto": true
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,6 +24,8 @@
|
||||||
* @module crypto/public_key/rsa
|
* @module crypto/public_key/rsa
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
var BigInteger = require('./jsbn.js'),
|
var BigInteger = require('./jsbn.js'),
|
||||||
util = require('../../util.js'),
|
util = require('../../util.js'),
|
||||||
random = require('../random.js'),
|
random = require('../random.js'),
|
||||||
|
@ -119,7 +121,7 @@ function RSA() {
|
||||||
|
|
||||||
// "empty" RSA key constructor
|
// "empty" RSA key constructor
|
||||||
|
|
||||||
function keyObject() {
|
function KeyObject() {
|
||||||
this.n = null;
|
this.n = null;
|
||||||
this.e = 0;
|
this.e = 0;
|
||||||
this.ee = null;
|
this.ee = null;
|
||||||
|
@ -167,8 +169,8 @@ function RSA() {
|
||||||
};
|
};
|
||||||
|
|
||||||
keys = webCrypto.generateKey(keyGenOpt, true, ['sign', 'verify']);
|
keys = webCrypto.generateKey(keyGenOpt, true, ['sign', 'verify']);
|
||||||
if (!(typeof keys.then === 'function')) { // IE11 KeyOperation
|
if (typeof keys.then !== 'function') { // IE11 KeyOperation
|
||||||
keys = convertKeyOperation(keys, 'Error generating RSA key pair.');
|
keys = util.promisifyIE11Op(keys, 'Error generating RSA key pair.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,15 +187,15 @@ function RSA() {
|
||||||
// export the generated keys as JsonWebKey (JWK)
|
// export the generated keys as JsonWebKey (JWK)
|
||||||
// https://tools.ietf.org/html/draft-ietf-jose-json-web-key-33
|
// https://tools.ietf.org/html/draft-ietf-jose-json-web-key-33
|
||||||
var key = webCrypto.exportKey('jwk', keypair.privateKey);
|
var key = webCrypto.exportKey('jwk', keypair.privateKey);
|
||||||
if (!(typeof key.then === 'function')) { // IE11 KeyOperation
|
if (typeof key.then !== 'function') { // IE11 KeyOperation
|
||||||
key = convertKeyOperation(key, 'Error exporting RSA key pair.');
|
key = util.promisifyIE11Op(key, 'Error exporting RSA key pair.');
|
||||||
}
|
}
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
function decodeKey(jwk) {
|
function decodeKey(jwk) {
|
||||||
// map JWK parameters to local BigInteger type system
|
// map JWK parameters to local BigInteger type system
|
||||||
var key = new keyObject();
|
var key = new KeyObject();
|
||||||
key.n = toBigInteger(jwk.n);
|
key.n = toBigInteger(jwk.n);
|
||||||
key.ee = new BigInteger(E, 16);
|
key.ee = new BigInteger(E, 16);
|
||||||
key.d = toBigInteger(jwk.d);
|
key.d = toBigInteger(jwk.d);
|
||||||
|
@ -210,23 +212,12 @@ function RSA() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// JS code
|
// JS code
|
||||||
//
|
//
|
||||||
|
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function(resolve) {
|
||||||
var key = new keyObject();
|
var key = new KeyObject();
|
||||||
var rng = new SecureRandom();
|
var rng = new SecureRandom();
|
||||||
var qs = B >> 1;
|
var qs = B >> 1;
|
||||||
key.e = parseInt(E, 16);
|
key.e = parseInt(E, 16);
|
||||||
|
@ -235,13 +226,15 @@ function RSA() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
key.p = new BigInteger(B - qs, 1, rng);
|
key.p = new BigInteger(B - qs, 1, rng);
|
||||||
if (key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) === 0 && key.p.isProbablePrime(10))
|
if (key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) === 0 && key.p.isProbablePrime(10)) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
key.q = new BigInteger(qs, 1, rng);
|
key.q = new BigInteger(qs, 1, rng);
|
||||||
if (key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) === 0 && key.q.isProbablePrime(10))
|
if (key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) === 0 && key.q.isProbablePrime(10)) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (key.p.compareTo(key.q) <= 0) {
|
if (key.p.compareTo(key.q) <= 0) {
|
||||||
var t = key.p;
|
var t = key.p;
|
||||||
|
@ -270,7 +263,7 @@ function RSA() {
|
||||||
this.verify = verify;
|
this.verify = verify;
|
||||||
this.sign = sign;
|
this.sign = sign;
|
||||||
this.generate = generate;
|
this.generate = generate;
|
||||||
this.keyObject = keyObject;
|
this.keyObject = KeyObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = RSA;
|
module.exports = RSA;
|
||||||
|
|
72
src/util.js
72
src/util.js
|
@ -69,11 +69,14 @@ module.exports = {
|
||||||
var i = 0;
|
var i = 0;
|
||||||
while (c < e) {
|
while (c < e) {
|
||||||
h = str.charCodeAt(c++).toString(16);
|
h = str.charCodeAt(c++).toString(16);
|
||||||
while (h.length < 2) h = "0" + h;
|
while (h.length < 2) {
|
||||||
|
h = "0" + h;
|
||||||
|
}
|
||||||
r.push(" " + h);
|
r.push(" " + h);
|
||||||
i++;
|
i++;
|
||||||
if (i % 32 === 0)
|
if (i % 32 === 0) {
|
||||||
r.push("\n ");
|
r.push("\n ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return r.join('');
|
return r.join('');
|
||||||
},
|
},
|
||||||
|
@ -84,15 +87,18 @@ module.exports = {
|
||||||
* @return {String} String containing the hexadecimal values
|
* @return {String} String containing the hexadecimal values
|
||||||
*/
|
*/
|
||||||
hexstrdump: function (str) {
|
hexstrdump: function (str) {
|
||||||
if (str === null)
|
if (str === null) {
|
||||||
return "";
|
return "";
|
||||||
|
}
|
||||||
var r = [];
|
var r = [];
|
||||||
var e = str.length;
|
var e = str.length;
|
||||||
var c = 0;
|
var c = 0;
|
||||||
var h;
|
var h;
|
||||||
while (c < e) {
|
while (c < e) {
|
||||||
h = str.charCodeAt(c++).toString(16);
|
h = str.charCodeAt(c++).toString(16);
|
||||||
while (h.length < 2) h = "0" + h;
|
while (h.length < 2) {
|
||||||
|
h = "0" + h;
|
||||||
|
}
|
||||||
r.push("" + h);
|
r.push("" + h);
|
||||||
}
|
}
|
||||||
return r.join('');
|
return r.join('');
|
||||||
|
@ -105,8 +111,9 @@ module.exports = {
|
||||||
*/
|
*/
|
||||||
hex2bin: function (hex) {
|
hex2bin: function (hex) {
|
||||||
var str = '';
|
var str = '';
|
||||||
for (var i = 0; i < hex.length; i += 2)
|
for (var i = 0; i < hex.length; i += 2) {
|
||||||
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
||||||
|
}
|
||||||
return str;
|
return str;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -122,7 +129,9 @@ module.exports = {
|
||||||
var h;
|
var h;
|
||||||
while (c < e) {
|
while (c < e) {
|
||||||
h = str[c++].toString(16);
|
h = str[c++].toString(16);
|
||||||
while (h.length < 2) h = "0" + h;
|
while (h.length < 2) {
|
||||||
|
h = "0" + h;
|
||||||
|
}
|
||||||
r.push("" + h);
|
r.push("" + h);
|
||||||
}
|
}
|
||||||
return r.join('');
|
return r.join('');
|
||||||
|
@ -189,7 +198,7 @@ module.exports = {
|
||||||
str2Uint8Array: function (str) {
|
str2Uint8Array: function (str) {
|
||||||
|
|
||||||
// Uncomment for debugging
|
// Uncomment for debugging
|
||||||
if(!(typeof str === 'string') && !String.prototype.isPrototypeOf(str)) {
|
if(typeof str !== 'string' && !String.prototype.isPrototypeOf(str)) {
|
||||||
throw new Error('str2Uint8Array: Data must be in the form of a string');
|
throw new Error('str2Uint8Array: Data must be in the form of a string');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +236,7 @@ module.exports = {
|
||||||
* @param {Array<Uint8array>} Array of Uint8Arrays to concatenate
|
* @param {Array<Uint8array>} Array of Uint8Arrays to concatenate
|
||||||
* @return {Uint8array} Concatenated array
|
* @return {Uint8array} Concatenated array
|
||||||
*/
|
*/
|
||||||
concatUint8Array: function (arrays) {
|
concatUint8Array: function (arrays) {
|
||||||
|
|
||||||
var totalLength = 0;
|
var totalLength = 0;
|
||||||
arrays.forEach(function (element) {
|
arrays.forEach(function (element) {
|
||||||
|
@ -248,7 +257,7 @@ module.exports = {
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deep copy Uint8Array
|
* Deep copy Uint8Array
|
||||||
|
@ -342,8 +351,9 @@ module.exports = {
|
||||||
|
|
||||||
getLeftNBits: function (string, bitcount) {
|
getLeftNBits: function (string, bitcount) {
|
||||||
var rest = bitcount % 8;
|
var rest = bitcount % 8;
|
||||||
if (rest === 0)
|
if (rest === 0) {
|
||||||
return string.substring(0, bitcount / 8);
|
return string.substring(0, bitcount / 8);
|
||||||
|
}
|
||||||
var bytes = (bitcount - rest) / 8 + 1;
|
var bytes = (bitcount - rest) / 8 + 1;
|
||||||
var result = string.substring(0, bytes);
|
var result = string.substring(0, bytes);
|
||||||
return this.shiftRight(result, 8 - rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF);
|
return this.shiftRight(result, 8 - rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF);
|
||||||
|
@ -357,17 +367,18 @@ module.exports = {
|
||||||
* @return {String} Resulting string.
|
* @return {String} Resulting string.
|
||||||
*/
|
*/
|
||||||
shiftRight: function (value, bitcount) {
|
shiftRight: function (value, bitcount) {
|
||||||
var temp = util.str2bin(value);
|
var temp = this.str2bin(value);
|
||||||
if (bitcount % 8 !== 0) {
|
if (bitcount % 8 !== 0) {
|
||||||
for (var i = temp.length - 1; i >= 0; i--) {
|
for (var i = temp.length - 1; i >= 0; i--) {
|
||||||
temp[i] >>= bitcount % 8;
|
temp[i] >>= bitcount % 8;
|
||||||
if (i > 0)
|
if (i > 0) {
|
||||||
temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF;
|
temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
return util.bin2str(temp);
|
return this.bin2str(temp);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -413,5 +424,40 @@ module.exports = {
|
||||||
return window.msCrypto.subtle;
|
return window.msCrypto.subtle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a generic synchronous function in an ES6 Promise.
|
||||||
|
* @param {Function} fn The function to be wrapped
|
||||||
|
* @return {Function} The function wrapped in a Promise
|
||||||
|
*/
|
||||||
|
promisify: function(fn) {
|
||||||
|
return function() {
|
||||||
|
var args = arguments;
|
||||||
|
return new Promise(function(resolve) {
|
||||||
|
var result = fn.apply(null, args);
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an IE11 web crypro api result to a promise.
|
||||||
|
* This is required since IE11 implements an old version of the
|
||||||
|
* Web Crypto specification that does not use promises.
|
||||||
|
* @param {Object} cryptoOp The return value of an IE11 web cryptro api call
|
||||||
|
* @param {String} errmsg An error message for a specific operation
|
||||||
|
* @return {Promise} The resulting Promise
|
||||||
|
*/
|
||||||
|
promisifyIE11Op: function(cryptoOp, errmsg) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
cryptoOp.onerror = function () {
|
||||||
|
reject(new Error(errmsg));
|
||||||
|
};
|
||||||
|
cryptoOp.oncomplete = function (e) {
|
||||||
|
resolve(e.target.result);
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user