diff --git a/browserify/crypto-index.js b/browserify/crypto-index.js index 9a4f4c9..652c2ee 100644 --- a/browserify/crypto-index.js +++ b/browserify/crypto-index.js @@ -4,29 +4,71 @@ var createHash = require('create-hash'); var pbkdf2 = require('pbkdf2'); var aes = require('browserify-aes'); + var ec = require('elliptic').ec('p256'); - exports.sha256 = function (buf) { - var hash = createHash('sha256'); - hash.update(buf); - hash.end(); - return Promise.resolve(hash.read()); - }; + function sha256(buf) { + return createHash('sha256').update(buf).digest(); + } - 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. var aesKey = pbkdf2.pbkdf2Sync(password, Buffer(salt), 8192, 16, 'sha256'); 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 decipher = aes.createDecipheriv('aes-128-gcm', aesKey, Buffer(iv)); decipher.setAuthTag(Buffer(data.slice(-16))); - var result = Buffer.concat([decipher.update(Buffer(data.slice(0, -16))), decipher.final()]); - return Promise.resolve(result); - }; + return Buffer.concat([decipher.update(Buffer(data.slice(0, -16))), decipher.final()]); + } + 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)); }; }()); diff --git a/gulpfile.js b/gulpfile.js index 5cdc695..f5a8966 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -18,4 +18,8 @@ .pipe(gulp.dest('./')) ; }); + + gulp.task('watch', function () { + gulp.watch('browserify/*.js', [ 'default' ]); + }); }()); diff --git a/package.json b/package.json index 6ae6ae3..192f7b7 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,8 @@ "browserify": "^14.1.0", "browserify-aes": "^1.0.6", "btoa": "^1.1.2", + "create-hash": "^1.1.2", + "elliptic": "^6.4.0", "gulp": "^3.9.1", "gulp-cli": "^1.2.2", "gulp-rename": "^1.2.2",