Skip to content

Commit f0b4423

Browse files
committed
Make aes128gcm record size include the auth tag
1 parent e36504e commit f0b4423

File tree

4 files changed

+231
-171
lines changed

4 files changed

+231
-171
lines changed

nodejs/ece.js

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,12 @@ function parseParams(params) {
258258
if (isNaN(header.rs)) {
259259
header.rs = 4096;
260260
}
261-
if (header.rs <= PAD_SIZE[header.version]) {
262-
throw new Error('The rs parameter has to be greater than ' +
263-
PAD_SIZE[header.version]);
261+
var overhead = PAD_SIZE[header.version];
262+
if (header.version === 'aes128gcm') {
263+
overhead += TAG_LENGTH;
264+
}
265+
if (header.rs <= overhead) {
266+
throw new Error('The rs parameter has to be greater than ' + overhead);
264267
}
265268

266269
if (params.salt) {
@@ -365,8 +368,13 @@ function decrypt(buffer, params) {
365368
var start = 0;
366369
var result = new Buffer(0);
367370

371+
var chunkSize = header.rs;
372+
if (header.version !== 'aes128gcm') {
373+
chunkSize += TAG_LENGTH;
374+
}
375+
368376
for (var i = 0; start < buffer.length; ++i) {
369-
var end = start + header.rs + TAG_LENGTH;
377+
var end = start + chunkSize;
370378
if (end === buffer.length) {
371379
throw new Error('Truncated payload');
372380
}
@@ -457,21 +465,25 @@ function encrypt(buffer, params) {
457465
var key = deriveKeyAndNonce(header, MODE_ENCRYPT);
458466
var start = 0;
459467
var padSize = PAD_SIZE[header.version];
468+
var overhead = padSize;
469+
if (header.version === 'aes128gcm') {
470+
overhead += TAG_LENGTH;
471+
}
460472
var pad = isNaN(parseInt(params.pad, 10)) ? 0 : parseInt(params.pad, 10);
461473

462474
// Note the <= here ensures that we write out a padding-only block at the end
463475
// of a buffer.
464476
for (var i = 0; start <= buffer.length; ++i) {
465477
// Pad so that at least one data byte is in a block.
466478
var recordPad = Math.min((1 << (padSize * 8)) - 1, // maximum padding
467-
Math.min(header.rs - padSize - 1, pad));
479+
Math.min(header.rs - overhead - 1, pad));
468480
pad -= recordPad;
469481

470-
var end = Math.min(start + header.rs - padSize - recordPad, buffer.length);
482+
var end = Math.min(start + header.rs - overhead - recordPad, buffer.length);
471483
var block = encryptRecord(key, i, buffer.slice(start, end),
472484
recordPad, padSize);
473485
result = Buffer.concat([result, block]);
474-
start += header.rs - padSize - recordPad;
486+
start += header.rs - overhead - recordPad;
475487
}
476488
if (pad) {
477489
throw new Error('Unable to pad by requested amount, ' + pad + ' remaining');

nodejs/test.js

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ var ece = require('./ece.js');
55
var base64 = require('urlsafe-base64');
66
var assert = require('assert');
77

8-
// Usage: node test.js [args]
9-
// If args contains a version (e.g., aes128gcm), filter on versions.
10-
// If args contains a test function, filter on test functions.
11-
// If args contains 'verbose' show logs.
12-
// If args contains 'text=...' set the input string to the UTF-8 encoding of that string.
13-
// If args contains 'max=<n>' set the maximum input size to that value.
14-
// If args contains 'dump[=file]' log info to ../encrypt_data.json or the specified file.
8+
function usage() {
9+
console.log('Usage: node test.js [args]');
10+
console.log(' <version> - test only the specified version(s)');
11+
console.log(' Supported: [aes128gcm,aesgcm,aesgcm128]');
12+
console.log(' <test function> - test only the specified function(s)');
13+
console.log(' "verbose" enable logging for tests (export ECE_KEYLOG=1 for more)');
14+
console.log(' "text=..." sets the input string');
15+
console.log(' "max=<n>" sets the maximum input size');
16+
console.log(' "dump[=file]" log info to ../encrypt_data.json or the specified file');
17+
}
1518
var args = process.argv.slice(2);
1619
var minLen = 3;
1720
var maxLen = 100;
@@ -33,6 +36,9 @@ args.forEach(function(arg) {
3336
dumpFile = '../encrypt_data.json';
3437
} else if (arg.substring(0, 5) === 'dump=') {
3538
dumpFile = arg.substring(5);
39+
} else if (arg.charAt(0) === '-') {
40+
usage();
41+
process.exit(2);
3642
}
3743
});
3844

@@ -78,26 +84,37 @@ function validate() {
7884
});
7985
}
8086

81-
function generateInput(len) {
87+
function generateInput(min) {
8288
var input;
89+
min = Math.max(minLen, min || 0);
8390
if (plaintext) {
84-
if (plaintext.length < minLen) {
91+
if (plaintext.length < min) {
8592
throw new Error('Plaintext is too short');
8693
}
8794
input = plaintext;
8895
} else {
89-
if (typeof len === 'undefined') {
90-
len = Math.floor((Math.random() * (maxLen - minLen) + minLen));
91-
}
92-
input = crypto.randomBytes(Math.max(minLen, Math.min(len, maxLen)));
96+
var len = Math.floor((Math.random() * (maxLen - min) + min));
97+
input = crypto.randomBytes(len);
9398
}
9499
logbuf('Input', input);
95100
return input;
96101
}
97102

103+
function rsoverhead(version) {
104+
if (version === 'aesgcm128') {
105+
return 1;
106+
}
107+
if (version === 'aesgcm') {
108+
return 2;
109+
}
110+
return 18;
111+
}
112+
98113
function encryptDecrypt(input, encryptParams, decryptParams, keys) {
99114
// Fill out a default rs.
100-
encryptParams.rs = encryptParams.rs || (input.length + minLen);
115+
if (!encryptParams.rs) {
116+
encryptParams.rs = input.length + rsoverhead(encryptParams.version) + 1;
117+
}
101118
if (decryptParams.version === 'aes128gcm') {
102119
delete decryptParams.rs;
103120
} else {
@@ -160,7 +177,7 @@ function exactlyOneRecord(version) {
160177
var params = {
161178
version: version,
162179
key: base64.encode(crypto.randomBytes(16)),
163-
rs: input.length + 2 // add exactly the padding
180+
rs: input.length + rsoverhead(version)
164181
};
165182
encryptDecrypt(input, params, params);
166183
}
@@ -170,11 +187,14 @@ function detectTruncation(version) {
170187
var params = {
171188
version: version,
172189
key: base64.encode(crypto.randomBytes(16)),
173-
rs: input.length + 1 // so we get two records
190+
rs: input.length + rsoverhead(version) - 1
174191
};
175192
var headerLen = (version === 'aes128gcm') ? 21 : 0;
176193
var encrypted = ece.encrypt(input, params);
177-
var chunkLen = headerLen + params.rs + 16;
194+
var chunkLen = headerLen + params.rs;
195+
if (version != 'aes128gcm') {
196+
chunkLen += 16;
197+
}
178198
assert.ok(chunkLen < encrypted.length);
179199
encrypted = encrypted.slice(0, chunkLen);
180200
logbuf('Encrypted', encrypted);
@@ -282,11 +302,11 @@ function checkExamples() {
282302
key: base64.decode('BO3ZVPxUlnLORbVGMpbT1Q'),
283303
keyid: 'a1',
284304
salt: base64.decode('uNCkWiNYzKTnBN9ji3-qWA'),
285-
rs: 10,
305+
rs: 26,
286306
pad: 1
287307
},
288308
plaintext: Buffer.from('I am the walrus'),
289-
ciphertext: base64.decode('uNCkWiNYzKTnBN9ji3-qWAAAAAoCYTGH' +
309+
ciphertext: base64.decode('uNCkWiNYzKTnBN9ji3-qWAAAABoCYTGH' +
290310
'OqYFz-0in3dpb-VE2GfBngkaPy6bZus_' +
291311
'qLF79s6zQyTSsA0iLOKyd3JqVIwprNzV' +
292312
'atRCWZGUx_qsFbJBCQu62RqQuR2d')

0 commit comments

Comments
 (0)