UNPKG

sic-ecies

Version:

ECIES implemented for Bitcore. fix to eos and easy to use

153 lines (128 loc) 4.3 kB
'use strict'; var bitcore = require('bitcore-lib'); var eosecc = require('eosjs-ecc'); var PublicKey = bitcore.PublicKey; var PrivateKey = bitcore.PrivateKey; var Hash = bitcore.crypto.Hash; var Random = bitcore.crypto.Random; var $ = bitcore.util.preconditions; var AESCBC = require('./aescbc'); // http://en.wikipedia.org/wiki/Integrated_Encryption_Scheme var ECIES = function ECIES(opts) { if (!(this instanceof ECIES)) { return new ECIES(); } this.opts = opts || {}; }; ECIES.prototype.PrivateKey = PrivateKey; ECIES.prototype.PublicKey = function(publickey) { if (publickey.startsWith('EOS')) { return PublicKey(eosecc.PublicKey(publickey).toUncompressed().toBuffer().toString('hex')); } return PublicKey(publickey); }; ECIES.prototype.privateKey = function(privateKey) { $.checkArgument(privateKey, 'no private key provided'); this._privateKey = privateKey || null; return this; }; ECIES.prototype.publicKey = function(publicKey) { $.checkArgument(publicKey, 'no public key provided'); this._publicKey = publicKey || null; return this; }; var cachedProperty = function(name, getter) { var cachedName = '_' + name; Object.defineProperty(ECIES.prototype, name, { configurable: false, enumerable: true, get: function() { var value = this[cachedName]; if (!value) { value = this[cachedName] = getter.apply(this); } return value; } }); }; cachedProperty('Rbuf', function() { return this._privateKey.publicKey.toDER(true); }); cachedProperty('kEkM', function() { var r = this._privateKey.bn; var KB = this._publicKey.point; var P = KB.mul(r); var S = P.getX(); var Sbuf = S.toBuffer({size: 32}); return Hash.sha512(Sbuf); }); cachedProperty('kE', function() { return this.kEkM.slice(0, 32); }); cachedProperty('kM', function() { return this.kEkM.slice(32,64); }); // Encrypts the message (String or Buffer). // Optional `ivbuf` contains 16-byte Buffer to be used in AES-CBC. // By default, `ivbuf` is computed deterministically from message and private key using HMAC-SHA256. // Deterministic IV enables end-to-end test vectors for alternative implementations. // Note that identical messages have identical ciphertexts. If your protocol does not include some // kind of a sequence identifier inside the message *and* it is important to not allow attacker to learn // that message is repeated, then you should use custom IV. // For random IV, pass `Random.getRandomBuffer(16)` for the second argument. ECIES.prototype.encrypt = function(message, enpublickey, ivbuf) { this.publicKey( ECIES.prototype.PublicKey(enpublickey)); if (!Buffer.isBuffer(message)) message = new Buffer(message); if (ivbuf === undefined) { this.privateKey(PrivateKey('5KMGTsffgXXq247JWX4QQ2AicRSJfepCKP7aSZsm1hk4cW8txsg')); ivbuf = Hash.sha256hmac(message, this._privateKey.toBuffer()).slice(0,16); } var c = AESCBC.encryptCipherkey(message, this.kE, ivbuf); var d = Hash.sha256hmac(c, this.kM); if(this.opts.shortTag) d = d.slice(0,4); if(this.opts.noKey) { var encbuf = Buffer.concat([c, d]); } else { var encbuf = Buffer.concat([this.Rbuf, c, d]); } return encbuf.toString('base64'); }; ECIES.prototype.decrypt = function(encbuf, deprivatekey) { var encdata = new Buffer(encbuf, 'base64'); $.checkArgument(encdata); this.privateKey(PrivateKey(deprivatekey)); var offset = 0; var tagLength = 32; if(this.opts.shortTag) { tagLength = 4; } if(!this.opts.noKey) { var pub; switch(encdata[0]) { case 4: pub = encdata.slice(0, 65); break; case 3: case 2: pub = encdata.slice(0, 33); break; default: throw new Error('Invalid type: ' + encdata[0]); } this._publicKey = PublicKey.fromDER(pub); offset += pub.length; } var c = encdata.slice(offset, encdata.length - tagLength); var d = encdata.slice(encdata.length - tagLength, encdata.length); var d2 = Hash.sha256hmac(c, this.kM); if(this.opts.shortTag) d2 = d2.slice(0,4); var equal = true; for (var i = 0; i < d.length; i++) { equal &= (d[i] === d2[i]); } if (!equal) { throw new Error('Invalid checksum'); } return AESCBC.decryptCipherkey(c, this.kE).toString(); }; module.exports = ECIES;