;(function () { 'use strict'; var crypto = require('crypto'); var OAUTH3 = require('./oauth3.core.js').OAUTH3; var ec = require('elliptic').ec('p256'); function randomBytes(size) { return new OAUTH3.PromiseA(function (resolve, reject) { crypto.randomBytes(size, function (err, buf) { if (err) { reject(err); } else { resolve(buf); } }); }); } function sha256(buf) { return crypto.createHash('sha256').update(buf).digest(); } function pbkdf2(password, salt) { // Derived AES key is 128 bit, and the function takes a size in bytes. return crypto.pbkdf2Sync(password, Buffer(salt), 8192, 16, 'sha256'); } function encrypt(key, iv, data) { var cipher = crypto.createCipheriv('aes-128-gcm', Buffer(key), Buffer(iv)); return Buffer.concat([cipher.update(Buffer(data)), cipher.final(), cipher.getAuthTag()]); } function decrypt(key, iv, data) { var decipher = crypto.createDecipheriv('aes-128-gcm', Buffer(key), Buffer(iv)); decipher.setAuthTag(Buffer(data.slice(-16))); return Buffer.concat([decipher.update(Buffer(data.slice(0, -16))), decipher.final()]); } function bnToBuffer(bn, size) { var buf = bn.toArrayLike(Buffer); if (!size || buf.length === size) { return buf; } else if (buf.length < size) { return Buffer.concat([Buffer(size-buf.length).fill(0), buf]); } else if (buf.length > size) { throw new Error('EC signature number bigger than expected'); } throw new Error('invalid size "'+size+'" converting BigNumber to Buffer'); } function bnToB64(bn) { var b64 = bnToBuffer(bn).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: bnToB64(key.getPublic().getX()) , y: bnToB64(key.getPublic().getY()) }; var privJwk = JSON.parse(JSON.stringify(pubJwk)); privJwk.key_ops = ['sign']; privJwk.d = bnToB64(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([bnToBuffer(sig.r, 32), bnToBuffer(sig.s, 32)]); } 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); } function promiseWrap(func) { return function() { var args = arguments; return new OAUTH3.PromiseA(function (resolve) { resolve(func.apply(null, args)); }); }; } exports.sha256 = promiseWrap(sha256); exports.pbkdf2 = promiseWrap(pbkdf2); exports.encrypt = promiseWrap(encrypt); exports.decrypt = promiseWrap(decrypt); exports.sign = promiseWrap(sign); exports.verify = promiseWrap(verify); exports.genEcdsaKeyPair = promiseWrap(genEcdsaKeyPair); exports.randomBytes = randomBytes; }());