[Pkg-javascript-commits] [node-browserify-aes] 01/10: fix variable length iv issue in gcm

Bastien Roucariès rouca at moszumanska.debian.org
Thu Nov 9 12:42:42 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 a5680e9c464771b086ed8b44b11f26993cdc66ea
Author: Calvin Metcalf <cmetcalf at appgeo.com>
Date:   Tue Oct 10 13:32:55 2017 -0400

    fix variable length iv issue in gcm
---
 authCipher.js | 33 +++++++++++++++++++++++++++++----
 decrypter.js  |  2 +-
 encrypter.js  |  2 +-
 incr32.js     | 15 +++++++++++++++
 modes/ctr.js  | 15 +--------------
 test/index.js | 43 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 90 insertions(+), 20 deletions(-)

diff --git a/authCipher.js b/authCipher.js
index 2a7affc..c6e8a76 100644
--- a/authCipher.js
+++ b/authCipher.js
@@ -4,6 +4,7 @@ var Transform = require('cipher-base')
 var inherits = require('inherits')
 var GHASH = require('./ghash')
 var xor = require('buffer-xor')
+var incr32 = require('./incr32')
 
 function xorTest (a, b) {
   var out = 0
@@ -17,13 +18,39 @@ function xorTest (a, b) {
   return out
 }
 
+function calcIv (self, iv, ck) {
+  if (iv.length === 12) {
+    self._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])])
+    return Buffer.concat([iv, Buffer.from([0, 0, 0, 2])])
+  }
+  var ghash = new GHASH(ck)
+  var len = iv.length
+  var toPad = len % 16
+  ghash.update(iv)
+  if (toPad) {
+    toPad = 16 - toPad
+    ghash.update(Buffer.alloc(toPad, 0))
+  }
+  ghash.update(Buffer.alloc(8, 0))
+  var ivBits = len * 8
+  var tail = Buffer.alloc(8)
+  tail.writeUIntBE(ivBits, 0, 8)
+  ghash.update(tail)
+  self._finID = ghash.state
+  var out = Buffer.from(self._finID)
+  incr32(out)
+  return out
+}
 function StreamCipher (mode, key, iv, decrypt) {
   Transform.call(this)
 
-  this._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])])
-  iv = Buffer.concat([iv, Buffer.from([0, 0, 0, 2])])
+  var h = Buffer.alloc(4, 0)
 
   this._cipher = new aes.AES(key)
+  var ck = this._cipher.encryptBlock(h)
+  this._ghash = new GHASH(ck)
+  iv = calcIv(this, iv, ck)
+
   this._prev = Buffer.from(iv)
   this._cache = Buffer.allocUnsafe(0)
   this._secCache = Buffer.allocUnsafe(0)
@@ -32,8 +59,6 @@ function StreamCipher (mode, key, iv, decrypt) {
   this._len = 0
   this._mode = mode
 
-  var h = Buffer.alloc(4, 0)
-  this._ghash = new GHASH(this._cipher.encryptBlock(h))
   this._authTag = null
   this._called = false
 }
diff --git a/decrypter.js b/decrypter.js
index a2f596b..d752033 100644
--- a/decrypter.js
+++ b/decrypter.js
@@ -95,7 +95,7 @@ function createDecipheriv (suite, password, iv) {
   if (!config) throw new TypeError('invalid suite type')
 
   if (typeof iv === 'string') iv = Buffer.from(iv)
-  if (iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length)
+  if (config.mode !== 'GCM' && iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length)
 
   if (typeof password === 'string') password = Buffer.from(password)
   if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length)
diff --git a/encrypter.js b/encrypter.js
index df2eab8..0c4c58b 100644
--- a/encrypter.js
+++ b/encrypter.js
@@ -91,7 +91,7 @@ function createCipheriv (suite, password, iv) {
   if (password.length !== config.key / 8) throw new TypeError('invalid key length ' + password.length)
 
   if (typeof iv === 'string') iv = Buffer.from(iv)
-  if (iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length)
+  if (config.mode !== 'GCM' && iv.length !== config.iv) throw new TypeError('invalid iv length ' + iv.length)
 
   if (config.type === 'stream') {
     return new StreamCipher(config.module, password, iv)
diff --git a/incr32.js b/incr32.js
new file mode 100644
index 0000000..c1a9089
--- /dev/null
+++ b/incr32.js
@@ -0,0 +1,15 @@
+function incr32 (iv) {
+  var len = iv.length
+  var item
+  while (len--) {
+    item = iv.readUInt8(len)
+    if (item === 255) {
+      iv.writeUInt8(0, len)
+    } else {
+      item++
+      iv.writeUInt8(item, len)
+      break
+    }
+  }
+}
+module.exports = incr32
diff --git a/modes/ctr.js b/modes/ctr.js
index ca282fb..4a84e1b 100644
--- a/modes/ctr.js
+++ b/modes/ctr.js
@@ -1,19 +1,6 @@
 var xor = require('buffer-xor')
 
-function incr32 (iv) {
-  var len = iv.length
-  var item
-  while (len--) {
-    item = iv.readUInt8(len)
-    if (item === 255) {
-      iv.writeUInt8(0, len)
-    } else {
-      item++
-      iv.writeUInt8(item, len)
-      break
-    }
-  }
-}
+var incr32 = require('../incr32')
 
 function getBlock (self) {
   var out = self._cipher.encryptBlockRaw(self._prev)
diff --git a/test/index.js b/test/index.js
index edf4dfa..a356477 100644
--- a/test/index.js
+++ b/test/index.js
@@ -431,6 +431,49 @@ test('correctly handle incremental base64 output', function (t) {
   t.equals(data, decrypted, 'round trips')
 })
 
+var gcmTest = [
+  {
+    length: 8,
+    answer: 'f0714f44',
+    tag: 'a5814f7c3d8e7eee899d260fb91784bf'
+  },
+  {
+    length: 16,
+    answer: 'b93caf62',
+    tag: '58fd9623495ac556f0d26cbc9fa4384c'
+  },
+  {
+    length: 21,
+    answer: '4534b74d',
+    tag: '5299c9c1011f32b17db796745239298a'
+  },
+  {
+    length: 43,
+    answer: 'b16a634b',
+    tag: 'd9274cb14b01e8e6a8fe3866b0e17f65'
+  }
+]
+function testIV (t, length, answer, tag) {
+  t.test('key length ' + length, function (t) {
+    t.plan(3)
+    var key = Buffer.alloc(32, 0)
+    var iv = Buffer.alloc(length, 0)
+    var cipher = crypto.createCipheriv('aes-256-gcm', key, iv)
+    var out = cipher.update('fooo').toString('hex')
+    t.equals(out, answer)
+    cipher.final()
+    t.equals(tag, cipher.getAuthTag().toString('hex'))
+    var decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)
+    decipher.setAuthTag(Buffer.from(tag, 'hex'))
+    var decrypted = decipher.update(Buffer.from(answer, 'hex'))
+    t.equals(decrypted.toString(), 'fooo')
+  })
+}
+test('different IV lengths work for GCM', function (t) {
+  gcmTest.forEach(function (item) {
+    testIV(t, item.length, item.answer, item.tag)
+  })
+})
 test('handle long uft8 plaintexts', function (t) {
   t.plan(1)
   var salt = Buffer.alloc(32, 0)

-- 
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