node-forge 0.6.29 → 0.6.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.npmignore CHANGED
@@ -19,4 +19,5 @@ dist
19
19
  js/forge.bundle.js
20
20
  js/forge.min.js
21
21
  node_modules
22
+ nodejs/coverage
22
23
  tests/forge
package/.travis.yml CHANGED
@@ -1,6 +1,8 @@
1
1
  language: node_js
2
2
  node_js:
3
3
  - "0.10"
4
+ - "0.12"
5
+ - iojs
4
6
  install: (cd nodejs && npm install)
5
7
  script:
6
8
  - (cd nodejs && npm test)
package/README.md CHANGED
@@ -553,6 +553,7 @@ of operation: [ECB][], [CBC][], [CFB][], [OFB][], [CTR][], and [GCM][].
553
553
 
554
554
  These algorithms are currently supported:
555
555
 
556
+ * AES-ECB
556
557
  * AES-CBC
557
558
  * AES-CFB
558
559
  * AES-OFB
@@ -582,7 +583,7 @@ var key = forge.pkcs5.pbkdf2('password', salt, numIterations, 16);
582
583
  */
583
584
 
584
585
  // encrypt some bytes using CBC mode
585
- // (other modes include: CFB, OFB, CTR, and GCM)
586
+ // (other modes include: ECB, CFB, OFB, CTR, and GCM)
586
587
  var cipher = forge.cipher.createCipher('AES-CBC', key);
587
588
  cipher.start({iv: iv});
588
589
  cipher.update(forge.util.createBuffer(someBytes));
package/bower.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "forge",
3
- "version": "0.6.29",
3
+ "version": "0.6.33",
4
4
  "description": "JavaScript implementations of network transports, cryptography, ciphers, PKI, message digests, and various utilities.",
5
+ "moduleType": ["amd"],
5
6
  "authors": [
6
7
  "Digital Bazaar, Inc."
7
8
  ],
package/js/aes.js CHANGED
@@ -251,6 +251,7 @@ forge.aes._updateBlock = _updateBlock;
251
251
 
252
252
  /** Register AES algorithms **/
253
253
 
254
+ registerAlgorithm('AES-ECB', forge.cipher.modes.ecb);
254
255
  registerAlgorithm('AES-CBC', forge.cipher.modes.cbc);
255
256
  registerAlgorithm('AES-CFB', forge.cipher.modes.cfb);
256
257
  registerAlgorithm('AES-OFB', forge.cipher.modes.ofb);
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @author Dave Longley
5
5
  *
6
- * Copyright (c) 2009-2014 Digital Bazaar, Inc.
6
+ * Copyright (c) 2009-2015 Digital Bazaar, Inc.
7
7
  *
8
8
  */
9
9
  (function() {
@@ -232,11 +232,9 @@ function decrypt_aes_cbc_sha1(record, s) {
232
232
  // last 20 bytes = MAC
233
233
  var macLen = s.macLength;
234
234
 
235
- // create a zero'd out mac
236
- var mac = '';
237
- for(var i = 0; i < macLen; ++i) {
238
- mac += String.fromCharCode(0);
239
- }
235
+ // create a random MAC to check against should the mac length check fail
236
+ // Note: do this regardless of the failure to keep timing consistent
237
+ var mac = forge.random.getBytesSync(macLen);
240
238
 
241
239
  // get fragment and mac
242
240
  var len = cipher.output.length();
@@ -253,10 +251,38 @@ function decrypt_aes_cbc_sha1(record, s) {
253
251
  // see if data integrity checks out, update sequence number
254
252
  var mac2 = s.macFunction(s.macKey, s.sequenceNumber, record);
255
253
  s.updateSequenceNumber();
256
- rval = (mac2 === mac) && rval;
254
+ rval = compareMacs(s.macKey, mac, mac2) && rval;
257
255
  return rval;
258
256
  }
259
257
 
258
+ /**
259
+ * Safely compare two MACs. This function will compare two MACs in a way
260
+ * that protects against timing attacks.
261
+ *
262
+ * TODO: Expose elsewhere as a utility API.
263
+ *
264
+ * See: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/
265
+ *
266
+ * @param key the MAC key to use.
267
+ * @param mac1 as a binary-encoded string of bytes.
268
+ * @param mac2 as a binary-encoded string of bytes.
269
+ *
270
+ * @return true if the MACs are the same, false if not.
271
+ */
272
+ function compareMacs(key, mac1, mac2) {
273
+ var hmac = forge.hmac.create();
274
+
275
+ hmac.start('SHA1', key);
276
+ hmac.update(mac1);
277
+ mac1 = hmac.digest().getBytes();
278
+
279
+ hmac.start(null, null);
280
+ hmac.update(mac2);
281
+ mac2 = hmac.digest().getBytes();
282
+
283
+ return mac1 === mac2;
284
+ }
285
+
260
286
  } // end module implementation
261
287
 
262
288
  /* ########## Begin module wrapper ########## */
package/js/cipher.js CHANGED
@@ -128,6 +128,8 @@ var BlockCipher = forge.cipher.BlockCipher = function(options) {
128
128
  * bytes, then it must be Nb (16) bytes in length. If the IV is given in as
129
129
  * 32-bit integers, then it must be 4 integers long.
130
130
  *
131
+ * Note: an IV is not required or used in ECB mode.
132
+ *
131
133
  * For GCM-mode, the IV must be given as a binary-encoded string of bytes or
132
134
  * a byte buffer. The number of bytes should be 12 (96 bits) as recommended
133
135
  * by NIST SP-800-38D but another length may be given.
@@ -187,7 +189,7 @@ BlockCipher.prototype.update = function(input) {
187
189
  BlockCipher.prototype.finish = function(pad) {
188
190
  // backwards-compatibility w/deprecated padding API
189
191
  // Note: will overwrite padding functions even after another start() call
190
- if(pad && this.mode.name === 'CBC') {
192
+ if(pad && (this.mode.name === 'ECB' || this.mode.name === 'CBC')) {
191
193
  this.mode.pad = function(input) {
192
194
  return pad(this.blockSize, input, false);
193
195
  };
package/js/x509.js CHANGED
@@ -2092,7 +2092,7 @@ function _fillMissingExtensionFields(e, options) {
2092
2092
  }
2093
2093
 
2094
2094
  if(typeof e.value !== 'undefined') {
2095
- return;
2095
+ return e;
2096
2096
  }
2097
2097
 
2098
2098
  // handle missing value:
@@ -0,0 +1,2 @@
1
+ instrumentation:
2
+ root: ..
@@ -1,17 +1,24 @@
1
1
  {
2
- "name": "forge-nodejs-example",
3
- "version": "0.1.0",
4
- "private": true,
5
- "main": "server.js",
6
- "dependencies": {
7
- "express": "~3.1.0",
8
- "mocha": "~1.8.2",
9
- "chai": "~1.5.0",
10
- "grunt": "~0.4.1",
11
- "grunt-mocha": "~0.3.1"
12
- },
13
- "scripts": {
14
- "test": "mocha -t 20000 -R spec test/*.js",
15
- "run": "node server"
16
- }
2
+ "name": "forge-nodejs-example",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "main": "server.js",
6
+ "dependencies": {
7
+ "express": "~3.1.0",
8
+ "mocha": "~1.21.5",
9
+ "chai": "~1.10.0",
10
+ "grunt": "~0.4.5",
11
+ "grunt-mocha": "~0.4.12"
12
+ },
13
+ "scripts": {
14
+ "run": "node server",
15
+ "test": "mocha -t 30000 -R spec test/*.js",
16
+ "coverage": "rm -rf coverage && ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- -u exports -t 30000 -R spec test/*.js",
17
+ "coverage-lcov": "rm -rf coverage && ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha --report lcovonly -- -u exports -t 30000 -R spec test/*.js",
18
+ "coverage-report": "./node_modules/.bin/istanbul report"
19
+ },
20
+ "devDependencies": {
21
+ "istanbul": "^0.3.14",
22
+ "mocha-lcov-reporter": "0.0.2"
23
+ }
17
24
  }
@@ -112,6 +112,162 @@ function Tests(ASSERT, CIPHER, AES, UTIL) {
112
112
  ASSERT.equal(out.toHex(), '00112233445566778899aabbccddeeff');
113
113
  });
114
114
 
115
+ // AES-128-ECB
116
+ (function() {
117
+ var keys = [
118
+ '2b7e151628aed2a6abf7158809cf4f3c',
119
+ '2b7e151628aed2a6abf7158809cf4f3c',
120
+ '2b7e151628aed2a6abf7158809cf4f3c',
121
+ '2b7e151628aed2a6abf7158809cf4f3c'
122
+ ];
123
+
124
+ var inputs = [
125
+ '6bc1bee22e409f96e93d7e117393172a',
126
+ 'ae2d8a571e03ac9c9eb76fac45af8e51',
127
+ '30c81c46a35ce411e5fbc1191a0a52ef',
128
+ 'f69f2445df4f9b17ad2b417be66c3710'
129
+ ];
130
+
131
+ var outputs = [
132
+ '3ad77bb40d7a3660a89ecaf32466ef97',
133
+ 'f5d3d58503b9699de785895a96fdbaaf',
134
+ '43b1cd7f598ece23881b00e3ed030688',
135
+ '7b0c785e27e8ad3f8223207104725dd4'
136
+ ];
137
+
138
+ for(var i = 0; i < keys.length; ++i) {
139
+ (function(i) {
140
+ var key = UTIL.hexToBytes(keys[i]);
141
+ var input = UTIL.hexToBytes(inputs[i]);
142
+ var output = UTIL.hexToBytes(outputs[i]);
143
+
144
+ it('should aes-128-ecb encrypt: ' + inputs[i], function() {
145
+ // encrypt w/no padding
146
+ var cipher = CIPHER.createCipher('AES-ECB', key);
147
+ cipher.mode.pad = false;
148
+ cipher.start();
149
+ cipher.update(UTIL.createBuffer(input));
150
+ cipher.finish();
151
+ ASSERT.equal(cipher.output.toHex(), outputs[i]);
152
+ });
153
+
154
+ it('should aes-128-ecb decrypt: ' + outputs[i], function() {
155
+ // decrypt w/no padding
156
+ var cipher = CIPHER.createDecipher('AES-ECB', key);
157
+ cipher.mode.unpad = false;
158
+ cipher.start();
159
+ cipher.update(UTIL.createBuffer(output));
160
+ cipher.finish();
161
+ ASSERT.equal(cipher.output.toHex(), inputs[i]);
162
+ });
163
+ })(i);
164
+ }
165
+ })();
166
+
167
+ // AES-192-ECB
168
+ (function() {
169
+ var keys = [
170
+ '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b',
171
+ '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b',
172
+ '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b',
173
+ '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b'
174
+ ];
175
+
176
+ var inputs = [
177
+ '6bc1bee22e409f96e93d7e117393172a',
178
+ 'ae2d8a571e03ac9c9eb76fac45af8e51',
179
+ '30c81c46a35ce411e5fbc1191a0a52ef',
180
+ 'f69f2445df4f9b17ad2b417be66c3710'
181
+ ];
182
+
183
+ var outputs = [
184
+ 'bd334f1d6e45f25ff712a214571fa5cc',
185
+ '974104846d0ad3ad7734ecb3ecee4eef',
186
+ 'ef7afd2270e2e60adce0ba2face6444e',
187
+ '9a4b41ba738d6c72fb16691603c18e0e'
188
+ ];
189
+
190
+ for(var i = 0; i < keys.length; ++i) {
191
+ (function(i) {
192
+ var key = UTIL.hexToBytes(keys[i]);
193
+ var input = UTIL.hexToBytes(inputs[i]);
194
+ var output = UTIL.hexToBytes(outputs[i]);
195
+
196
+ it('should aes-192-ecb encrypt: ' + inputs[i], function() {
197
+ // encrypt w/no padding
198
+ var cipher = CIPHER.createCipher('AES-ECB', key);
199
+ cipher.mode.pad = false;
200
+ cipher.start();
201
+ cipher.update(UTIL.createBuffer(input));
202
+ cipher.finish();
203
+ ASSERT.equal(cipher.output.toHex(), outputs[i]);
204
+ });
205
+
206
+ it('should aes-192-ecb decrypt: ' + outputs[i], function() {
207
+ // decrypt w/no padding
208
+ var cipher = CIPHER.createDecipher('AES-ECB', key);
209
+ cipher.mode.unpad = false;
210
+ cipher.start();
211
+ cipher.update(UTIL.createBuffer(output));
212
+ cipher.finish();
213
+ ASSERT.equal(cipher.output.toHex(), inputs[i]);
214
+ });
215
+ })(i);
216
+ }
217
+ })();
218
+
219
+ // AES-256-ECB
220
+ (function() {
221
+ var keys = [
222
+ '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4',
223
+ '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4',
224
+ '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4',
225
+ '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4'
226
+ ];
227
+
228
+ var inputs = [
229
+ '6bc1bee22e409f96e93d7e117393172a',
230
+ 'ae2d8a571e03ac9c9eb76fac45af8e51',
231
+ '30c81c46a35ce411e5fbc1191a0a52ef',
232
+ 'f69f2445df4f9b17ad2b417be66c3710'
233
+ ];
234
+
235
+ var outputs = [
236
+ 'f3eed1bdb5d2a03c064b5a7e3db181f8',
237
+ '591ccb10d410ed26dc5ba74a31362870',
238
+ 'b6ed21b99ca6f4f9f153e7b1beafed1d',
239
+ '23304b7a39f9f3ff067d8d8f9e24ecc7'
240
+ ];
241
+
242
+ for(var i = 0; i < keys.length; ++i) {
243
+ (function(i) {
244
+ var key = UTIL.hexToBytes(keys[i]);
245
+ var input = UTIL.hexToBytes(inputs[i]);
246
+ var output = UTIL.hexToBytes(outputs[i]);
247
+
248
+ it('should aes-256-ecb encrypt: ' + inputs[i], function() {
249
+ // encrypt w/no padding
250
+ var cipher = CIPHER.createCipher('AES-ECB', key);
251
+ cipher.mode.pad = false;
252
+ cipher.start();
253
+ cipher.update(UTIL.createBuffer(input));
254
+ cipher.finish();
255
+ ASSERT.equal(cipher.output.toHex(), outputs[i]);
256
+ });
257
+
258
+ it('should aes-256-ecb decrypt: ' + outputs[i], function() {
259
+ // decrypt w/no padding
260
+ var cipher = CIPHER.createDecipher('AES-ECB', key);
261
+ cipher.mode.unpad = false;
262
+ cipher.start();
263
+ cipher.update(UTIL.createBuffer(output));
264
+ cipher.finish();
265
+ ASSERT.equal(cipher.output.toHex(), inputs[i]);
266
+ });
267
+ })(i);
268
+ }
269
+ })();
270
+
115
271
  // AES-128-CBC
116
272
  (function() {
117
273
  var keys = [
@@ -160,18 +316,20 @@ function Tests(ASSERT, CIPHER, AES, UTIL) {
160
316
  it('should aes-128-cbc encrypt: ' + inputs[i], function() {
161
317
  // encrypt w/no padding
162
318
  var cipher = CIPHER.createCipher('AES-CBC', key);
319
+ cipher.mode.pad = false;
163
320
  cipher.start({iv: iv});
164
321
  cipher.update(UTIL.createBuffer(input));
165
- cipher.finish(function(){return true;});
322
+ cipher.finish();
166
323
  ASSERT.equal(cipher.output.toHex(), outputs[i]);
167
324
  });
168
325
 
169
326
  it('should aes-128-cbc decrypt: ' + outputs[i], function() {
170
327
  // decrypt w/no padding
171
328
  var cipher = CIPHER.createDecipher('AES-CBC', key);
329
+ cipher.mode.unpad = false;
172
330
  cipher.start({iv: iv});
173
331
  cipher.update(UTIL.createBuffer(output));
174
- cipher.finish(function(){return true;});
332
+ cipher.finish();
175
333
  var out = (i & 1) ? cipher.output.toHex() : cipher.output.bytes();
176
334
  ASSERT.equal(out, inputs[i]);
177
335
  });
@@ -219,18 +377,20 @@ function Tests(ASSERT, CIPHER, AES, UTIL) {
219
377
  it('should aes-192-cbc encrypt: ' + inputs[i], function() {
220
378
  // encrypt w/no padding
221
379
  var cipher = CIPHER.createCipher('AES-CBC', key);
380
+ cipher.mode.pad = false;
222
381
  cipher.start({iv: iv});
223
382
  cipher.update(UTIL.createBuffer(input));
224
- cipher.finish(function(){return true;});
383
+ cipher.finish();
225
384
  ASSERT.equal(cipher.output.toHex(), outputs[i]);
226
385
  });
227
386
 
228
387
  it('should aes-192-cbc decrypt: ' + outputs[i], function() {
229
388
  // decrypt w/no padding
230
389
  var cipher = CIPHER.createDecipher('AES-CBC', key);
390
+ cipher.mode.unpad = false;
231
391
  cipher.start({iv: iv});
232
392
  cipher.update(UTIL.createBuffer(output));
233
- cipher.finish(function(){return true;});
393
+ cipher.finish();
234
394
  var out = cipher.output.toHex();
235
395
  ASSERT.equal(out, inputs[i]);
236
396
  });
@@ -278,18 +438,20 @@ function Tests(ASSERT, CIPHER, AES, UTIL) {
278
438
  it('should aes-256-cbc encrypt: ' + inputs[i], function() {
279
439
  // encrypt w/no padding
280
440
  var cipher = CIPHER.createCipher('AES-CBC', key);
441
+ cipher.mode.pad = false;
281
442
  cipher.start({iv: iv});
282
443
  cipher.update(UTIL.createBuffer(input));
283
- cipher.finish(function(){return true;});
444
+ cipher.finish();
284
445
  ASSERT.equal(cipher.output.toHex(), outputs[i]);
285
446
  });
286
447
 
287
448
  it('should aes-256-cbc decrypt: ' + outputs[i], function() {
288
449
  // decrypt w/no padding
289
450
  var cipher = CIPHER.createDecipher('AES-CBC', key);
451
+ cipher.mode.unpad = false;
290
452
  cipher.start({iv: iv});
291
453
  cipher.update(UTIL.createBuffer(output));
292
- cipher.finish(function(){return true;});
454
+ cipher.finish();
293
455
  var out = cipher.output.toHex();
294
456
  ASSERT.equal(out, inputs[i]);
295
457
  });
package/nodejs/ui/test.js CHANGED
@@ -1,7 +1,7 @@
1
1
  var ASSERT = chai.assert;
2
2
  mocha.setup({
3
3
  ui: 'bdd',
4
- timeout: 20000
4
+ timeout: 30000
5
5
  });
6
6
  requirejs.config({
7
7
  paths: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-forge",
3
- "version": "0.6.29",
3
+ "version": "0.6.33",
4
4
  "description": "JavaScript implementations of network transports, cryptography, ciphers, PKI, message digests, and various utilities.",
5
5
  "homepage": "http://github.com/digitalbazaar/forge",
6
6
  "author": {