added ECDSA features to crypto fallback
This commit is contained in:
parent
e8e9b961a4
commit
740c973afc
|
@ -4,29 +4,71 @@
|
||||||
var createHash = require('create-hash');
|
var createHash = require('create-hash');
|
||||||
var pbkdf2 = require('pbkdf2');
|
var pbkdf2 = require('pbkdf2');
|
||||||
var aes = require('browserify-aes');
|
var aes = require('browserify-aes');
|
||||||
|
var ec = require('elliptic').ec('p256');
|
||||||
|
|
||||||
exports.sha256 = function (buf) {
|
function sha256(buf) {
|
||||||
var hash = createHash('sha256');
|
return createHash('sha256').update(buf).digest();
|
||||||
hash.update(buf);
|
}
|
||||||
hash.end();
|
|
||||||
return Promise.resolve(hash.read());
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.encrypt = function (data, password, salt, iv) {
|
function encrypt(data, password, salt, iv) {
|
||||||
// Derived AES key is 128 bit, and the function takes a size in bytes.
|
// Derived AES key is 128 bit, and the function takes a size in bytes.
|
||||||
var aesKey = pbkdf2.pbkdf2Sync(password, Buffer(salt), 8192, 16, 'sha256');
|
var aesKey = pbkdf2.pbkdf2Sync(password, Buffer(salt), 8192, 16, 'sha256');
|
||||||
var cipher = aes.createCipheriv('aes-128-gcm', aesKey, Buffer(iv));
|
var cipher = aes.createCipheriv('aes-128-gcm', aesKey, Buffer(iv));
|
||||||
var result = Buffer.concat([cipher.update(Buffer(data)), cipher.final(), cipher.getAuthTag()]);
|
|
||||||
return Promise.resolve(result);
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.decrypt = function (data, password, salt, iv) {
|
return Buffer.concat([cipher.update(Buffer(data)), cipher.final(), cipher.getAuthTag()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrypt(data, password, salt, iv) {
|
||||||
var aesKey = pbkdf2.pbkdf2Sync(password, Buffer(salt), 8192, 16, 'sha256');
|
var aesKey = pbkdf2.pbkdf2Sync(password, Buffer(salt), 8192, 16, 'sha256');
|
||||||
var decipher = aes.createDecipheriv('aes-128-gcm', aesKey, Buffer(iv));
|
var decipher = aes.createDecipheriv('aes-128-gcm', aesKey, Buffer(iv));
|
||||||
|
|
||||||
decipher.setAuthTag(Buffer(data.slice(-16)));
|
decipher.setAuthTag(Buffer(data.slice(-16)));
|
||||||
var result = Buffer.concat([decipher.update(Buffer(data.slice(0, -16))), decipher.final()]);
|
return Buffer.concat([decipher.update(Buffer(data.slice(0, -16))), decipher.final()]);
|
||||||
return Promise.resolve(result);
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
function convertBN(bn) {
|
||||||
|
if (bn.red) {
|
||||||
|
bn = bn.fromRed();
|
||||||
|
}
|
||||||
|
var b64 = bn.toArrayLike(Buffer).toString('base64');
|
||||||
|
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=*$/, '');
|
||||||
|
}
|
||||||
|
function genEcdsaKeyPair() {
|
||||||
|
var key = ec.genKeyPair();
|
||||||
|
var pubJwk = {
|
||||||
|
key_ops: ['verify']
|
||||||
|
, kty: 'EC'
|
||||||
|
, crv: 'P-256'
|
||||||
|
, x: convertBN(key.getPublic().x)
|
||||||
|
, y: convertBN(key.getPublic().y)
|
||||||
|
};
|
||||||
|
|
||||||
|
var privJwk = JSON.parse(JSON.stringify(pubJwk));
|
||||||
|
privJwk.key_ops = ['sign'];
|
||||||
|
privJwk.d = convertBN(key.getPrivate());
|
||||||
|
|
||||||
|
return {privateKey: privJwk, publicKey: pubJwk};
|
||||||
|
}
|
||||||
|
|
||||||
|
function sign(jwk, msg) {
|
||||||
|
var key = ec.keyFromPrivate(Buffer(jwk.d, 'base64'));
|
||||||
|
var sig = key.sign(sha256(msg));
|
||||||
|
return Buffer.concat([Buffer(sig.r, 'hex'), Buffer(sig.s, 'hex')]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function verify(jwk, msg, signature) {
|
||||||
|
var key = ec.keyFromPublic({x: Buffer(jwk.x, 'base64'), y: Buffer(jwk.y, 'base64')});
|
||||||
|
var sig = {
|
||||||
|
r: Buffer(signature.slice(0, signature.length/2))
|
||||||
|
, s: Buffer(signature.slice(signature.length/2))
|
||||||
|
};
|
||||||
|
return key.verify(sha256(msg), sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.sha256 = function () { return Promise.resolve(sha256.apply(this, arguments)); };
|
||||||
|
exports.encrypt = function () { return Promise.resolve(encrypt.apply(this, arguments)); };
|
||||||
|
exports.decrypt = function () { return Promise.resolve(decrypt.apply(this, arguments)); };
|
||||||
|
exports.sign = function () { return Promise.resolve(sign.apply(this, arguments)); };
|
||||||
|
exports.verify = function () { return Promise.resolve(verify.apply(this, arguments)); };
|
||||||
|
exports.genEcdsaKeyPair = function () { return Promise.resolve(genEcdsaKeyPair.apply(this, arguments)); };
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -18,4 +18,8 @@
|
||||||
.pipe(gulp.dest('./'))
|
.pipe(gulp.dest('./'))
|
||||||
;
|
;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task('watch', function () {
|
||||||
|
gulp.watch('browserify/*.js', [ 'default' ]);
|
||||||
|
});
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
"browserify": "^14.1.0",
|
"browserify": "^14.1.0",
|
||||||
"browserify-aes": "^1.0.6",
|
"browserify-aes": "^1.0.6",
|
||||||
"btoa": "^1.1.2",
|
"btoa": "^1.1.2",
|
||||||
|
"create-hash": "^1.1.2",
|
||||||
|
"elliptic": "^6.4.0",
|
||||||
"gulp": "^3.9.1",
|
"gulp": "^3.9.1",
|
||||||
"gulp-cli": "^1.2.2",
|
"gulp-cli": "^1.2.2",
|
||||||
"gulp-rename": "^1.2.2",
|
"gulp-rename": "^1.2.2",
|
||||||
|
|
Loading…
Reference in New Issue