UNPKG

fcash-ecies

Version:
141 lines (108 loc) 3.84 kB
'use strict'; var errors = require('./errors'); var fcashBase = require('fcash-lib'); var $ = fcashBase.util.preconditions; // Cipher Block Chaining // http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29 var CBC = function CBC(blockcipher, cipherkeybuf, ivbuf) { if (!(this instanceof CBC)) { return new CBC(blockcipher, cipherkeybuf, ivbuf); } this.blockcipher = blockcipher; this.cipherkeybuf = cipherkeybuf; this.ivbuf = ivbuf; }; CBC.buf2blockbufs = function(buf, blocksize) { var bytesize = blocksize / 8; var blockbufs = []; for (var i = 0; i <= buf.length / bytesize; i++) { var blockbuf = buf.slice(i * bytesize, i * bytesize + bytesize); if (blockbuf.length < blocksize) { blockbuf = CBC.pkcs7pad(blockbuf, blocksize); } blockbufs.push(blockbuf); } return blockbufs; }; CBC.blockbufs2buf = function(blockbufs) { var last = blockbufs[blockbufs.length - 1]; last = CBC.pkcs7unpad(last); blockbufs[blockbufs.length - 1] = last; var buf = Buffer.concat(blockbufs); return buf; }; CBC.encrypt = function(messagebuf, ivbuf, blockcipher, cipherkeybuf) { var blocksize = ivbuf.length * 8; var blockbufs = CBC.buf2blockbufs(messagebuf, blocksize); var encbufs = CBC.encryptblocks(blockbufs, ivbuf, blockcipher, cipherkeybuf); var encbuf = Buffer.concat(encbufs); return encbuf; }; CBC.decrypt = function(encbuf, ivbuf, blockcipher, cipherkeybuf) { var blocksize = ivbuf.length * 8; var bytesize = ivbuf.length; var encbufs = []; for (var i = 0; i < encbuf.length / bytesize; i++) { encbufs.push(encbuf.slice(i * bytesize, i * bytesize + bytesize)); } var blockbufs = CBC.decryptblocks(encbufs, ivbuf, blockcipher, cipherkeybuf); var buf = CBC.blockbufs2buf(blockbufs, blocksize); return buf; }; CBC.encryptblock = function(blockbuf, ivbuf, blockcipher, cipherkeybuf) { var xorbuf = CBC.xorbufs(blockbuf, ivbuf); var encbuf = blockcipher.encrypt(xorbuf, cipherkeybuf); return encbuf; }; CBC.decryptblock = function(encbuf, ivbuf, blockcipher, cipherkeybuf) { var xorbuf = blockcipher.decrypt(encbuf, cipherkeybuf); var blockbuf = CBC.xorbufs(xorbuf, ivbuf); return blockbuf; }; CBC.encryptblocks = function(blockbufs, ivbuf, blockcipher, cipherkeybuf) { var encbufs = []; for (var i = 0; i < blockbufs.length; i++) { var blockbuf = blockbufs[i]; var encbuf = CBC.encryptblock(blockbuf, ivbuf, blockcipher, cipherkeybuf); encbufs.push(encbuf); ivbuf = encbuf; } return encbufs; }; CBC.decryptblocks = function(encbufs, ivbuf, blockcipher, cipherkeybuf) { var blockbufs = []; for (var i = 0; i < encbufs.length; i++) { var encbuf = encbufs[i]; var blockbuf = CBC.decryptblock(encbuf, ivbuf, blockcipher, cipherkeybuf); blockbufs.push(blockbuf); ivbuf = encbuf; } return blockbufs; }; CBC.pkcs7pad = function(buf, blocksize) { var bytesize = blocksize / 8; var padbytesize = bytesize - buf.length; var pad = new Buffer(padbytesize); pad.fill(padbytesize); var paddedbuf = Buffer.concat([buf, pad]); return paddedbuf; }; CBC.pkcs7unpad = function(paddedbuf) { var padlength = paddedbuf[paddedbuf.length - 1]; var padbuf = paddedbuf.slice(paddedbuf.length - padlength, paddedbuf.length); var padbuf2 = new Buffer(padlength); padbuf2.fill(padlength); if (padbuf.toString('hex') !== padbuf2.toString('hex')) { throw new errors.InvalidPadding(padbuf.toString()); } return paddedbuf.slice(0, paddedbuf.length - padlength); }; CBC.xorbufs = function(buf1, buf2) { $.checkArgument(buf1.length === buf2.length, 'bufs must have the same length'); var buf = new Buffer(buf1.length); for (var i = 0; i < buf1.length; i++) { buf[i] = buf1[i] ^ buf2[i]; } return buf; }; module.exports = CBC;