From 12f29a9b5286e14fd5c5969ad22a77aaba6fa825 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Mon, 25 Aug 2014 16:25:01 -0700 Subject: [PATCH] CBC encryption --- lib/expmt/cbc.js | 47 ++++++++++++++++++++++++ test/test.cbc.js | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/lib/expmt/cbc.js b/lib/expmt/cbc.js index cf95d85..47c4c5f 100644 --- a/lib/expmt/cbc.js +++ b/lib/expmt/cbc.js @@ -1,13 +1,60 @@ var Random = require('../random'); +// http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29 var CBC = function CBC(blockcipherf, keybuf, ivbuf) { if (!(this instanceof CBC)) return new CBC(blockcipherf, keybuf, ivbuf); + this.blockcipherf = blockcipherf; this.keybuf = keybuf; 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.encrypt = function(messagebuf, ivbuf, blockcipherf, keybuf) { + var blocksize = ivbuf.length * 8; + var blockbufs = CBC.buf2blockbufs(messagebuf, blocksize); + var encbufs = CBC.encryptblocks(blockbufs, ivbuf, blockcipherf, keybuf); + var enc = Buffer.concat(encbufs); + return enc; +}; + +CBC.encryptblock = function(blockbuf, ivbuf, blockcipherf, keybuf) { + var xorbuf = CBC.xorbufs(blockbuf, ivbuf); + var encbuf = blockcipherf(xorbuf, keybuf); + return encbuf; +}; + +CBC.encryptblocks = function(blockbufs, ivbuf, blockcipherf, keybuf) { + var encbufs = []; + + for (var i = 0; i < blockbufs.length; i++) { + var blockbuf = blockbufs[i]; + var encbuf = CBC.encryptblock(blockbuf, ivbuf, blockcipherf, keybuf); + + encbufs.push(encbuf); + + ivbuf = encbuf; + } + + return encbufs; +}; + CBC.pkcs7pad = function(buf, blocksize) { var bytesize = blocksize / 8; var padbytesize = bytesize - buf.length; diff --git a/test/test.cbc.js b/test/test.cbc.js index 2489131..75a757a 100644 --- a/test/test.cbc.js +++ b/test/test.cbc.js @@ -12,6 +12,101 @@ describe('CBC', function() { var cbc = new CBC(); should.exist(cbc); }); + + describe('@buf2blockbufs', function() { + + it('should convert this buffer into one block', function() { + var buf = new Buffer(16 - 1); + buf.fill(0); + var blockbufs = CBC.buf2blockbufs(buf, 16 * 8); + blockbufs.length.should.equal(1); + blockbufs[0].toString('hex').should.equal('00000000000000000000000000000001'); + }); + + it('should convert this buffer into two blocks', function() { + var buf = new Buffer(16); + buf.fill(0); + var blockbufs = CBC.buf2blockbufs(buf, 16 * 8); + blockbufs.length.should.equal(2); + blockbufs[0].toString('hex').should.equal('00000000000000000000000000000000'); + blockbufs[1].toString('hex').should.equal('10101010101010101010101010101010'); + }); + + }); + + describe('@encrypt', function() { + + it('should return this known value', function() { + var messagebuf1 = new Buffer(128 / 8); + messagebuf1.fill(0); + var messagebuf2 = new Buffer(128 / 8); + messagebuf2.fill(0x10); + var messagebuf = Buffer.concat([messagebuf1, messagebuf2]); + var ivbuf = new Buffer(128 / 8); + ivbuf.fill(0x10); + var keybuf = new Buffer(128 / 8); + keybuf.fill(0); + var blockcipherf = function(messagebuf, keybuf) { + return messagebuf; + }; + var encbuf = CBC.encrypt(messagebuf, ivbuf, blockcipherf, keybuf); + encbuf.toString('hex').should.equal('101010101010101010101010101010100000000000000000000000000000000010101010101010101010101010101010'); + }); + + }); + + describe('@encryptblock', function() { + + it('should return this known value', function() { + var messagebuf = new Buffer(128 / 8); + messagebuf.fill(0); + var ivbuf = new Buffer(128 / 8); + ivbuf.fill(0x10); + var keybuf = new Buffer(128 / 8); + keybuf.fill(0); + var blockcipherf = function(messagebuf, keybuf) { + return messagebuf; + }; + var enc = CBC.encryptblock(messagebuf, ivbuf, blockcipherf, keybuf); + enc.toString('hex').should.equal(ivbuf.toString('hex')); + }); + + it('should return this other known value', function() { + var messagebuf = new Buffer(128 / 8); + messagebuf.fill(0x10); + var ivbuf = new Buffer(128 / 8); + ivbuf.fill(0x10); + var keybuf = new Buffer(128 / 8); + keybuf.fill(0); + var blockcipherf = function(messagebuf, keybuf) { + return messagebuf; + }; + var enc = CBC.encryptblock(messagebuf, ivbuf, blockcipherf, keybuf); + enc.toString('hex').should.equal('00000000000000000000000000000000'); + }); + + }); + + describe('@encryptblocks', function() { + + it('should return this known value', function() { + var messagebuf1 = new Buffer(128 / 8); + messagebuf1.fill(0); + var messagebuf2 = new Buffer(128 / 8); + messagebuf2.fill(0x10); + var ivbuf = new Buffer(128 / 8); + ivbuf.fill(0x10); + var keybuf = new Buffer(128 / 8); + keybuf.fill(0); + var blockcipherf = function(messagebuf, keybuf) { + return messagebuf; + }; + var encbufs = CBC.encryptblocks([messagebuf1, messagebuf2], ivbuf, blockcipherf, keybuf); + encbufs[0].toString('hex').should.equal('10101010101010101010101010101010'); + encbufs[1].toString('hex').should.equal('00000000000000000000000000000000'); + }); + + }); describe('@pkcs7pad', function() {