[Pkg-javascript-commits] [node-browserify-aes] 23/92: truly streaming

Bastien Roucariès rouca at moszumanska.debian.org
Sun Jun 4 09:35:16 UTC 2017


This is an automated email from the git hooks/post-receive script.

rouca pushed a commit to branch master
in repository node-browserify-aes.

commit ba5f9cc12aa663495f0f93eb5ebc8d5fa395f780
Author: Calvin Metcalf <cmetcalf at appgeo.com>
Date:   Tue Oct 28 15:37:37 2014 -0400

    truly streaming
---
 cipherBase.js   | 32 +++++++++++++++++++++++++++++
 decrypter.js    | 30 +++++----------------------
 encrypter.js    | 30 +++++----------------------
 modes.js        | 45 ++++++++++++++++++++++++++--------------
 modes/cfb.js    | 35 ++++++++++++++++++++++---------
 modes/ctr.js    | 12 +++++++++--
 modes/ofb.js    | 12 +++++++++--
 streamCipher.js | 26 +++++++++++++++++++++++
 test/index.js   | 64 +++++++++++++++++++++++++++++++++++++++------------------
 9 files changed, 187 insertions(+), 99 deletions(-)

diff --git a/cipherBase.js b/cipherBase.js
new file mode 100644
index 0000000..e580048
--- /dev/null
+++ b/cipherBase.js
@@ -0,0 +1,32 @@
+var Transform = require('stream').Transform;
+var inherits = require('inherits');
+
+module.exports = CipherBase;
+inherits(CipherBase, Transform);
+function CipherBase() {
+  Transform.call(this);
+}
+CipherBase.prototype.update = function (data, inputEnd, outputEnc) {
+  this.write(data, inputEnd);
+  var outData = new Buffer('');
+  var chunk;
+  while ((chunk = this.read())) {
+    outData = Buffer.concat([outData, chunk]);
+  }
+  if (outputEnc) {
+    outData = outData.toString(outputEnc);
+  }
+  return outData;
+};
+CipherBase.prototype.final = function (outputEnc) {
+  this.end();
+  var outData = new Buffer('');
+  var chunk;
+  while ((chunk = this.read())) {
+    outData = Buffer.concat([outData, chunk]);
+  }
+  if (outputEnc) {
+    outData = outData.toString(outputEnc);
+  }
+  return outData;
+};
\ No newline at end of file
diff --git a/decrypter.js b/decrypter.js
index e3888d5..5d840d2 100644
--- a/decrypter.js
+++ b/decrypter.js
@@ -1,7 +1,8 @@
 var aes = require('./aes');
-var Transform = require('stream').Transform;
+var Transform = require('./cipherBase');
 var inherits = require('inherits');
 var modes = require('./modes');
+var StreamCipher = require('./streamCipher');
 var ebtk = require('./EVP_BytesToKey');
 
 inherits(Decipher, Transform);
@@ -44,30 +45,6 @@ Decipher.prototype._flush = function (next) {
   }
   next();
 };
-Decipher.prototype.update = function (data, inputEnd, outputEnc) {
-  this.write(data, inputEnd);
-  var outData = new Buffer('');
-  var chunk;
-  while ((chunk = this.read())) {
-    outData = Buffer.concat([outData, chunk]);
-  }
-  if (outputEnc) {
-    outData = outData.toString(outputEnc);
-  }
-  return outData;
-};
-Decipher.prototype.final = function (outputEnc) {
-  this.end();
-  var outData = new Buffer('');
-  var chunk;
-  while ((chunk = this.read())) {
-    outData = Buffer.concat([outData, chunk]);
-  }
-  if (outputEnc) {
-    outData = outData.toString(outputEnc);
-  }
-  return outData;
-};
 
 function Splitter() {
    if (!(this instanceof Splitter)) {
@@ -126,6 +103,9 @@ module.exports = function (crypto) {
     if (iv.length !== config.iv) {
       throw new TypeError('invalid iv length ' + iv.length);
     }
+    if (config.type === 'stream') {
+      return new StreamCipher(modelist[config.mode], password, iv, true);
+    }
     return new Decipher(config.padding, modelist[config.mode], password, iv);
   }
 
diff --git a/encrypter.js b/encrypter.js
index d14ebac..d05fe64 100644
--- a/encrypter.js
+++ b/encrypter.js
@@ -1,8 +1,9 @@
 var aes = require('./aes');
-var Transform = require('stream').Transform;
+var Transform = require('./cipherBase');
 var inherits = require('inherits');
 var modes = require('./modes');
 var ebtk = require('./EVP_BytesToKey');
+var StreamCipher = require('./streamCipher');
 inherits(Cipher, Transform);
 function Cipher(padding, mode, key, iv) {
   if (!(this instanceof Cipher)) {
@@ -32,30 +33,6 @@ Cipher.prototype._flush = function (next) {
   next();
 };
 
-Cipher.prototype.update = function (data, inputEnd, outputEnc) {
-  this.write(data, inputEnd);
-  var outData = new Buffer('');
-  var chunk;
-  while ((chunk = this.read())) {
-    outData = Buffer.concat([outData, chunk]);
-  }
-  if (outputEnc) {
-    outData = outData.toString(outputEnc);
-  }
-  return outData;
-};
-Cipher.prototype.final = function (outputEnc) {
-  this.end();
-  var outData = new Buffer('');
-  var chunk;
-  while ((chunk = this.read())) {
-    outData = Buffer.concat([outData, chunk]);
-  }
-  if (outputEnc) {
-    outData = outData.toString(outputEnc);
-  }
-  return outData;
-};
 
 function Splitter(padding) {
    if (!(this instanceof Splitter)) {
@@ -119,6 +96,9 @@ module.exports = function (crypto) {
     if (iv.length !== config.iv) {
       throw new TypeError('invalid iv length ' + iv.length);
     }
+    if (config.type === 'stream') {
+      return new StreamCipher(modelist[config.mode], password, iv);
+    }
     return new Cipher(config.padding, modelist[config.mode], password, iv);
   }
   function createCipher (suite, password) {
diff --git a/modes.js b/modes.js
index bef542c..10f6321 100644
--- a/modes.js
+++ b/modes.js
@@ -2,37 +2,43 @@ exports['aes-128-ecb'] = {
   cipher: 'AES',
   key: 128,
   iv: 0,
-  mode: 'ECB'
+  mode: 'ECB',
+  type: 'block'
 };
 exports['aes-192-ecb'] = {
   cipher: 'AES',
   key: 192,
   iv: 0,
-  mode: 'ECB'
+  mode: 'ECB',
+  type: 'block'
 };
 exports['aes-256-ecb'] = {
   cipher: 'AES',
   key: 256,
   iv: 0,
-  mode: 'ECB'
+  mode: 'ECB',
+  type: 'block'
 };
 exports['aes-128-cbc'] = {
   cipher: 'AES',
   key: 128,
   iv: 16,
-  mode: 'CBC'
+  mode: 'CBC',
+  type: 'block'
 };
 exports['aes-192-cbc'] = {
   cipher: 'AES',
   key: 192,
   iv: 16,
-  mode: 'CBC'
+  mode: 'CBC',
+  type: 'block'
 };
 exports['aes-256-cbc'] = {
   cipher: 'AES',
   key: 256,
   iv: 16,
-  mode: 'CBC'
+  mode: 'CBC',
+  type: 'block'
 };
 exports['aes128'] = exports['aes-128-cbc'];
 exports['aes192'] = exports['aes-192-cbc'];
@@ -42,61 +48,70 @@ exports['aes-128-cfb'] = {
   key: 128,
   iv: 16,
   mode: 'CFB',
-  padding: false
+  padding: false,
+  type: 'stream'
 };
 exports['aes-192-cfb'] = {
   cipher: 'AES',
   key: 192,
   iv: 16,
   mode: 'CFB',
-  padding: false
+  padding: false,
+  type: 'stream'
 };
 exports['aes-256-cfb'] = {
   cipher: 'AES',
   key: 256,
   iv: 16,
   mode: 'CFB',
-  padding: false
+  padding: false,
+  type: 'stream'
 };
 exports['aes-128-ofb'] = {
   cipher: 'AES',
   key: 128,
   iv: 16,
   mode: 'OFB',
-  padding: false
+  padding: false,
+  type: 'stream'
 };
 exports['aes-192-ofb'] = {
   cipher: 'AES',
   key: 192,
   iv: 16,
   mode: 'OFB',
-  padding: false
+  padding: false,
+  type: 'stream'
 };
 exports['aes-256-ofb'] = {
   cipher: 'AES',
   key: 256,
   iv: 16,
   mode: 'OFB',
-  padding: false
+  padding: false,
+  type: 'stream'
 };
 exports['aes-128-ctr'] = {
   cipher: 'AES',
   key: 128,
   iv: 16,
   mode: 'CTR',
-  padding: false
+  padding: false,
+  type: 'stream'
 };
 exports['aes-192-ctr'] = {
   cipher: 'AES',
   key: 192,
   iv: 16,
   mode: 'CTR',
-  padding: false
+  padding: false,
+  type: 'stream'
 };
 exports['aes-256-ctr'] = {
   cipher: 'AES',
   key: 256,
   iv: 16,
   mode: 'CTR',
-  padding: false
+  padding: false,
+  type: 'stream'
 };
\ No newline at end of file
diff --git a/modes/cfb.js b/modes/cfb.js
index 978b637..13712b4 100644
--- a/modes/cfb.js
+++ b/modes/cfb.js
@@ -1,12 +1,27 @@
 var xor = require('../xor');
-exports.encrypt = function (self, block) {
-  var pad = self._cipher.encryptBlock(self._prev);
-  self._prev = xor(block, pad);
-  return self._prev;
+exports.encrypt = function (self, data, decrypt) {
+  var out = new Buffer('');
+  var len;
+  while (data.length) {
+    if (self._cache.length === 0) {
+      self._cache = self._cipher.encryptBlock(self._prev);
+      self._prev = new Buffer('');
+    }
+    if (self._cache.length <= data.length) {
+      len = self._cache.length;
+      out = Buffer.concat([out, encryptStart(self, data.slice(0, len), decrypt)]);
+      data = data.slice(len);
+    } else {
+      out = Buffer.concat([out, encryptStart(self, data, decrypt)]);
+      break;
+    }
+  }
+  return out;
 };
-exports.decrypt = function (self, block) {
-  // yes encrypt
-  var pad = self._cipher.encryptBlock(self._prev);
-  self._prev = block;
-  return xor(pad, block);
-};
\ No newline at end of file
+function encryptStart(self, data, decrypt) {
+  var len = data.length;
+  var out = xor(data, self._cache);
+  self._cache = self._cache.slice(len);
+  self._prev = Buffer.concat([self._prev, decrypt?data:out]);
+  return out;
+}
\ No newline at end of file
diff --git a/modes/ctr.js b/modes/ctr.js
index cbf3fe0..b345b0e 100644
--- a/modes/ctr.js
+++ b/modes/ctr.js
@@ -1,8 +1,16 @@
 var xor = require('../xor');
-exports.encrypt = exports.decrypt = function (self, block) {
-  var out = xor(block, self._cipher.encryptBlock(self._prev));
+function getBlock(self) {
+  var out = self._cipher.encryptBlock(self._prev);
   incr32(self._prev);
   return out;
+}
+exports.encrypt = function (self, chunk) {
+  while (self._cache.length < chunk.length) {
+    self._cache = Buffer.concat([self._cache, getBlock(self)]);
+  }
+  var pad = self._cache.slice(0, chunk.length);
+  self._cache = self._cache.slice(chunk.length);
+  return xor(chunk, pad);
 };
 function incr32(iv) {
   var len = iv.length;
diff --git a/modes/ofb.js b/modes/ofb.js
index 49d49b2..43efc5a 100644
--- a/modes/ofb.js
+++ b/modes/ofb.js
@@ -1,5 +1,13 @@
 var xor = require('../xor');
-exports.encrypt = exports.decrypt = function (self, block) {
+function getBlock(self) {
   self._prev = self._cipher.encryptBlock(self._prev);
-  return xor(block, self._prev);
+  return self._prev;
+}
+exports.encrypt = function (self, chunk) {
+  while (self._cache.length < chunk.length) {
+    self._cache = Buffer.concat([self._cache, getBlock(self)]);
+  }
+  var pad = self._cache.slice(0, chunk.length);
+  self._cache = self._cache.slice(chunk.length);
+  return xor(chunk, pad);
 };
\ No newline at end of file
diff --git a/streamCipher.js b/streamCipher.js
new file mode 100644
index 0000000..1c5c9c5
--- /dev/null
+++ b/streamCipher.js
@@ -0,0 +1,26 @@
+var aes = require('./aes');
+var Transform = require('./cipherBase');
+var inherits = require('inherits');
+
+inherits(StreamCipher, Transform);
+module.exports = StreamCipher;
+function StreamCipher(mode, key, iv, decrypt) {
+  if (!(this instanceof StreamCipher)) {
+    return new StreamCipher(mode, key, iv);
+  }
+  Transform.call(this);
+  this._cipher = new aes.AES(key);
+  this._prev = new Buffer(iv.length);
+  this._cache = new Buffer('');
+  this._secCache = new Buffer('');
+  this._decrypt = decrypt;
+  iv.copy(this._prev);
+  this._mode = mode;
+}
+StreamCipher.prototype._transform = function (chunk, _, next) {
+  next(null, this._mode.encrypt(this, chunk, this._decrypt));
+};
+StreamCipher.prototype._flush = function (next) {
+  this._cipher.scrub();
+  next();
+};
\ No newline at end of file
diff --git a/test/index.js b/test/index.js
index 26be14f..85fac24 100644
--- a/test/index.js
+++ b/test/index.js
@@ -44,16 +44,22 @@ fixtures.forEach(function (fixture, i) {
       suite.end();
     });
     test('fixture ' + i + ' ' + cipher + '-legacy', function (t) {
-      t.plan(1);
+      t.plan(3);
       var suite = crypto.createCipher(cipher, new Buffer(fixture.password));
       var buf = new Buffer('');
-      buf = Buffer.concat([buf, suite.update(new Buffer(fixture.text))]);
-      buf = Buffer.concat([buf, suite.final()]);
       var suite2 = _crypto.createCipher(cipher, new Buffer(fixture.password));
       var buf2 = new Buffer('');
-      buf2 = Buffer.concat([buf2, suite2.update(new Buffer(fixture.text))]);
+      var inbuf = new Buffer(fixture.text);
+      var mid = ~~inbuf.length;
+      buf = Buffer.concat([buf, suite.update(inbuf.slice(0, mid))]);
+      buf2 = Buffer.concat([buf2, suite2.update(inbuf.slice(0, mid))]);
+      t.equals(buf.toString('hex'), buf2.toString('hex'), 'intermediate');
+      buf = Buffer.concat([buf, suite.update(inbuf.slice(mid))]);
+      buf2 = Buffer.concat([buf2, suite2.update(inbuf.slice(mid))]);
+      t.equals(buf.toString('hex'), buf2.toString('hex'), 'intermediate 2');
+      buf = Buffer.concat([buf, suite.final()]);
       buf2 = Buffer.concat([buf2, suite2.final()]);
-      t.equals(buf.toString('hex'), buf2.toString('hex'));
+      t.equals(buf.toString('hex'), buf2.toString('hex'), 'final');
     });
     test('fixture ' + i + ' ' + cipher + '-decrypt', function (t) {
       t.plan(1);
@@ -75,17 +81,23 @@ fixtures.forEach(function (fixture, i) {
       suite.end();
     });
     test('fixture ' + i + ' ' + cipher + '-decrypt-legacy', function (t) {
-      t.plan(2);
+      t.plan(4);
       var suite = crypto.createDecipher(cipher, new Buffer(fixture.password));
       var buf = new Buffer('');
-      buf = Buffer.concat([buf, suite.update(new Buffer(fixture.results.ciphers[cipher], 'hex'))]);
-      buf = Buffer.concat([buf, suite.final()]);
       var suite2 = _crypto.createDecipher(cipher, new Buffer(fixture.password));
       var buf2 = new Buffer('');
-      buf2 = Buffer.concat([buf2, suite2.update(new Buffer(fixture.results.ciphers[cipher], 'hex'))]);
+      var inbuf = new Buffer(fixture.results.ciphers[cipher], 'hex');
+      var mid = ~~inbuf.length;
+      buf = Buffer.concat([buf, suite.update(inbuf.slice(0, mid))]);
+      buf2 = Buffer.concat([buf2, suite2.update(inbuf.slice(0, mid))]);
+      t.equals(buf.toString('utf8'), buf2.toString('utf8'), 'intermediate');
+      buf = Buffer.concat([buf, suite.update(inbuf.slice(mid))]);
+      buf2 = Buffer.concat([buf2, suite2.update(inbuf.slice(mid))]);
+      t.equals(buf.toString('utf8'), buf2.toString('utf8'), 'intermediate 2');
+      buf = Buffer.concat([buf, suite.final()]);
       buf2 = Buffer.concat([buf2, suite2.final()]);
       t.equals(buf.toString('utf8'), fixture.text);
-      t.equals(buf.toString('utf8'), buf2.toString('utf8'));
+      t.equals(buf.toString('utf8'), buf2.toString('utf8'), 'final');
     });
     //var cipherivs = fixture.results.cipherivs = {};
     types.forEach(function (cipher) {
@@ -109,17 +121,23 @@ fixtures.forEach(function (fixture, i) {
         suite.end();
       });
       test('fixture ' + i + ' ' + cipher + '-legacy-iv', function (t) {
-        t.plan(2);
+        t.plan(4);
         var suite = crypto.createCipheriv(cipher, ebtk(_crypto, fixture.password, modes[cipher].key).key, new Buffer(fixture.iv, 'hex'));
         var buf = new Buffer('');
-        buf = Buffer.concat([buf, suite.update(new Buffer(fixture.text))]);
-        buf = Buffer.concat([buf, suite.final()]);
         var suite2 = _crypto.createCipheriv(cipher, ebtk(_crypto, fixture.password, modes[cipher].key).key, new Buffer(fixture.iv, 'hex'));
         var buf2 = new Buffer('');
-        buf2 = Buffer.concat([buf2, suite2.update(new Buffer(fixture.text))]);
+        var inbuf = new Buffer(fixture.text);
+        var mid = ~~inbuf.length;
+        buf = Buffer.concat([buf, suite.update(inbuf.slice(0, mid))]);
+        buf2 = Buffer.concat([buf2, suite2.update(inbuf.slice(0, mid))]);
+        t.equals(buf.toString('hex'), buf2.toString('hex'), 'intermediate');
+        buf = Buffer.concat([buf, suite.update(inbuf.slice(mid))]);
+        buf2 = Buffer.concat([buf2, suite2.update(inbuf.slice(mid))]);
+        t.equals(buf.toString('hex'), buf2.toString('hex'), 'intermediate 2');
+        buf = Buffer.concat([buf, suite.final()]);
         buf2 = Buffer.concat([buf2, suite2.final()]);
         t.equals(buf.toString('hex'), fixture.results.cipherivs[cipher]);
-        t.equals(buf.toString('hex'), buf2.toString('hex'));
+        t.equals(buf.toString('hex'), buf2.toString('hex'), 'final');
       });
       test('fixture ' + i + ' ' + cipher + '-iv-decrypt', function (t) {
         t.plan(1);
@@ -138,17 +156,23 @@ fixtures.forEach(function (fixture, i) {
         suite.end();
       });
       test('fixture ' + i + ' ' + cipher + '-decrypt-legacy', function (t) {
-        t.plan(2);
+        t.plan(4);
         var suite = crypto.createDecipheriv(cipher, ebtk(_crypto, fixture.password, modes[cipher].key).key, new Buffer(fixture.iv, 'hex'));
         var buf = new Buffer('');
-        buf = Buffer.concat([buf, suite.update(new Buffer(fixture.results.cipherivs[cipher], 'hex'))]);
-        buf = Buffer.concat([buf, suite.final()]);
         var suite2 = _crypto.createDecipheriv(cipher, ebtk(_crypto, fixture.password, modes[cipher].key).key, new Buffer(fixture.iv, 'hex'));
         var buf2 = new Buffer('');
-        buf2 = Buffer.concat([buf2, suite2.update(new Buffer(fixture.results.cipherivs[cipher], 'hex'))]);
+        var inbuf = new Buffer(fixture.results.cipherivs[cipher], 'hex');
+        var mid = ~~inbuf.length;
+        buf = Buffer.concat([buf, suite.update(inbuf.slice(0, mid))]);
+        buf2 = Buffer.concat([buf2, suite2.update(inbuf.slice(0, mid))]);
+        t.equals(buf.toString('utf8'), buf2.toString('utf8'), 'intermediate');
+        buf = Buffer.concat([buf, suite.update(inbuf.slice(mid))]);
+        buf2 = Buffer.concat([buf2, suite2.update(inbuf.slice(mid))]);
+        t.equals(buf.toString('utf8'), buf2.toString('utf8'), 'intermediate 2');
+        buf = Buffer.concat([buf, suite.final()]);
         buf2 = Buffer.concat([buf2, suite2.final()]);
         t.equals(buf.toString('utf8'), fixture.text);
-        t.equals(buf.toString('utf8'), buf2.toString('utf8'));
+        t.equals(buf.toString('utf8'), buf2.toString('utf8'), 'final');
       });
     });
   });

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-browserify-aes.git



More information about the Pkg-javascript-commits mailing list