Skip to content

Commit dfb0511

Browse files
committed
crypto: Disable crypto.createCipher in FIPS mode
FIPS 140-2 disallows use of MD5, which is used to derive the initialization vector and key for createCipher(). Modify all tests to expect exceptions in FIPS mode when disallowed API is used, or to avoid testing such API in FIPS Mode.
1 parent df9c4a6 commit dfb0511

File tree

7 files changed

+117
-88
lines changed

7 files changed

+117
-88
lines changed

src/node_crypto.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3027,6 +3027,11 @@ void CipherBase::Init(const char* cipher_type,
30273027
int key_buf_len) {
30283028
HandleScope scope(env()->isolate());
30293029

3030+
#ifdef NODE_FIPS_MODE
3031+
return env()->ThrowError(
3032+
"crypto.createCipher() is not supported in FIPS mode.");
3033+
#endif // NODE_FIPS_MODE
3034+
30303035
CHECK_EQ(cipher_, nullptr);
30313036
cipher_ = EVP_get_cipherbyname(cipher_type);
30323037
if (cipher_ == nullptr) {

test/parallel/test-crypto-authenticated.js

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -93,32 +93,44 @@ for (var i in TEST_CASES) {
9393

9494
(function() {
9595
if (!test.password) return;
96-
var encrypt = crypto.createCipher(test.algo, test.password);
97-
if (test.aad)
98-
encrypt.setAAD(new Buffer(test.aad, 'hex'));
99-
var hex = encrypt.update(test.plain, 'ascii', 'hex');
100-
hex += encrypt.final('hex');
101-
var auth_tag = encrypt.getAuthTag();
102-
// only test basic encryption run if output is marked as tampered.
103-
if (!test.tampered) {
104-
assert.equal(hex.toUpperCase(), test.ct);
105-
assert.equal(auth_tag.toString('hex').toUpperCase(), test.tag);
96+
if (common.hasFipsCrypto) {
97+
assert.throws(function()
98+
{ crypto.createCipher(test.algo, test.password); },
99+
/not supported in FIPS mode/);
100+
} else {
101+
var encrypt = crypto.createCipher(test.algo, test.password);
102+
if (test.aad)
103+
encrypt.setAAD(new Buffer(test.aad, 'hex'));
104+
var hex = encrypt.update(test.plain, 'ascii', 'hex');
105+
hex += encrypt.final('hex');
106+
var auth_tag = encrypt.getAuthTag();
107+
// only test basic encryption run if output is marked as tampered.
108+
if (!test.tampered) {
109+
assert.equal(hex.toUpperCase(), test.ct);
110+
assert.equal(auth_tag.toString('hex').toUpperCase(), test.tag);
111+
}
106112
}
107113
})();
108114

109115
(function() {
110116
if (!test.password) return;
111-
var decrypt = crypto.createDecipher(test.algo, test.password);
112-
decrypt.setAuthTag(new Buffer(test.tag, 'hex'));
113-
if (test.aad)
114-
decrypt.setAAD(new Buffer(test.aad, 'hex'));
115-
var msg = decrypt.update(test.ct, 'hex', 'ascii');
116-
if (!test.tampered) {
117-
msg += decrypt.final('ascii');
118-
assert.equal(msg, test.plain);
117+
if (common.hasFipsCrypto) {
118+
assert.throws(function()
119+
{ crypto.createDecipher(test.algo, test.password); },
120+
/not supported in FIPS mode/);
119121
} else {
120-
// assert that final throws if input data could not be verified!
121-
assert.throws(function() { decrypt.final('ascii'); }, / auth/);
122+
var decrypt = crypto.createDecipher(test.algo, test.password);
123+
decrypt.setAuthTag(new Buffer(test.tag, 'hex'));
124+
if (test.aad)
125+
decrypt.setAAD(new Buffer(test.aad, 'hex'));
126+
var msg = decrypt.update(test.ct, 'hex', 'ascii');
127+
if (!test.tampered) {
128+
msg += decrypt.final('ascii');
129+
assert.equal(msg, test.plain);
130+
} else {
131+
// assert that final throws if input data could not be verified!
132+
assert.throws(function() { decrypt.final('ascii'); }, / auth/);
133+
}
122134
}
123135
})();
124136

test/parallel/test-crypto-binary-default.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -490,12 +490,13 @@ function testCipher4(key, iv) {
490490
assert.equal(txt, plaintext, 'encryption and decryption with key and iv');
491491
}
492492

493+
if (!common.hasFipsCrypto) {
494+
testCipher1('MySecretKey123');
495+
testCipher1(new Buffer('MySecretKey123'));
493496

494-
testCipher1('MySecretKey123');
495-
testCipher1(new Buffer('MySecretKey123'));
496-
497-
testCipher2('0123456789abcdef');
498-
testCipher2(new Buffer('0123456789abcdef'));
497+
testCipher2('0123456789abcdef');
498+
testCipher2(new Buffer('0123456789abcdef'));
499+
}
499500

500501
testCipher3('0123456789abcd0123456789', '12345678');
501502
testCipher3('0123456789abcd0123456789', new Buffer('12345678'));

test/parallel/test-crypto-cipher-decipher.js

Lines changed: 4 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ if (!common.hasCrypto) {
66
console.log('1..0 # Skipped: missing crypto');
77
return;
88
}
9+
if (common.hasFipsCrypto) {
10+
console.log('1..0 # Skipped: not supported in FIPS mode');
11+
return;
12+
}
913
var crypto = require('crypto');
1014

1115
function testCipher1(key) {
@@ -62,71 +66,12 @@ function testCipher2(key) {
6266
assert.equal(txt, plaintext, 'encryption and decryption with Base64');
6367
}
6468

65-
66-
function testCipher3(key, iv) {
67-
// Test encyrption and decryption with explicit key and iv
68-
var plaintext =
69-
'32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' +
70-
'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' +
71-
'jAfaFg**';
72-
var cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
73-
var ciph = cipher.update(plaintext, 'utf8', 'hex');
74-
ciph += cipher.final('hex');
75-
76-
var decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv);
77-
var txt = decipher.update(ciph, 'hex', 'utf8');
78-
txt += decipher.final('utf8');
79-
80-
assert.equal(txt, plaintext, 'encryption and decryption with key and iv');
81-
82-
// streaming cipher interface
83-
// NB: In real life, it's not guaranteed that you can get all of it
84-
// in a single read() like this. But in this case, we know it's
85-
// quite small, so there's no harm.
86-
var cStream = crypto.createCipheriv('des-ede3-cbc', key, iv);
87-
cStream.end(plaintext);
88-
ciph = cStream.read();
89-
90-
var dStream = crypto.createDecipheriv('des-ede3-cbc', key, iv);
91-
dStream.end(ciph);
92-
txt = dStream.read().toString('utf8');
93-
94-
assert.equal(txt, plaintext, 'streaming cipher iv');
95-
}
96-
97-
98-
function testCipher4(key, iv) {
99-
// Test encyrption and decryption with explicit key and iv
100-
var plaintext =
101-
'32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' +
102-
'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' +
103-
'jAfaFg**';
104-
var cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
105-
var ciph = cipher.update(plaintext, 'utf8', 'buffer');
106-
ciph = Buffer.concat([ciph, cipher.final('buffer')]);
107-
108-
var decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv);
109-
var txt = decipher.update(ciph, 'buffer', 'utf8');
110-
txt += decipher.final('utf8');
111-
112-
assert.equal(txt, plaintext, 'encryption and decryption with key and iv');
113-
}
114-
115-
11669
testCipher1('MySecretKey123');
11770
testCipher1(new Buffer('MySecretKey123'));
11871

11972
testCipher2('0123456789abcdef');
12073
testCipher2(new Buffer('0123456789abcdef'));
12174

122-
testCipher3('0123456789abcd0123456789', '12345678');
123-
testCipher3('0123456789abcd0123456789', new Buffer('12345678'));
124-
testCipher3(new Buffer('0123456789abcd0123456789'), '12345678');
125-
testCipher3(new Buffer('0123456789abcd0123456789'), new Buffer('12345678'));
126-
127-
testCipher4(new Buffer('0123456789abcd0123456789'), new Buffer('12345678'));
128-
129-
13075
// Base64 padding regression test, see #4837.
13176
(function() {
13277
var c = crypto.createCipher('aes-256-cbc', 'secret');
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'use strict';
2+
var common = require('../common');
3+
var assert = require('assert');
4+
5+
if (!common.hasCrypto) {
6+
console.log('1..0 # Skipped: missing crypto');
7+
return;
8+
}
9+
var crypto = require('crypto');
10+
11+
function testCipher1(key, iv) {
12+
// Test encyrption and decryption with explicit key and iv
13+
var plaintext =
14+
'32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' +
15+
'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' +
16+
'jAfaFg**';
17+
var cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
18+
var ciph = cipher.update(plaintext, 'utf8', 'hex');
19+
ciph += cipher.final('hex');
20+
21+
var decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv);
22+
var txt = decipher.update(ciph, 'hex', 'utf8');
23+
txt += decipher.final('utf8');
24+
25+
assert.equal(txt, plaintext, 'encryption and decryption with key and iv');
26+
27+
// streaming cipher interface
28+
// NB: In real life, it's not guaranteed that you can get all of it
29+
// in a single read() like this. But in this case, we know it's
30+
// quite small, so there's no harm.
31+
var cStream = crypto.createCipheriv('des-ede3-cbc', key, iv);
32+
cStream.end(plaintext);
33+
ciph = cStream.read();
34+
35+
var dStream = crypto.createDecipheriv('des-ede3-cbc', key, iv);
36+
dStream.end(ciph);
37+
txt = dStream.read().toString('utf8');
38+
39+
assert.equal(txt, plaintext, 'streaming cipher iv');
40+
}
41+
42+
43+
function testCipher2(key, iv) {
44+
// Test encyrption and decryption with explicit key and iv
45+
var plaintext =
46+
'32|RmVZZkFUVmpRRkp0TmJaUm56ZU9qcnJkaXNNWVNpTTU*|iXmckfRWZBGWWELw' +
47+
'eCBsThSsfUHLeRe0KCsK8ooHgxie0zOINpXxfZi/oNG7uq9JWFVCk70gfzQH8ZUJ' +
48+
'jAfaFg**';
49+
var cipher = crypto.createCipheriv('des-ede3-cbc', key, iv);
50+
var ciph = cipher.update(plaintext, 'utf8', 'buffer');
51+
ciph = Buffer.concat([ciph, cipher.final('buffer')]);
52+
53+
var decipher = crypto.createDecipheriv('des-ede3-cbc', key, iv);
54+
var txt = decipher.update(ciph, 'buffer', 'utf8');
55+
txt += decipher.final('utf8');
56+
57+
assert.equal(txt, plaintext, 'encryption and decryption with key and iv');
58+
}
59+
60+
testCipher1('0123456789abcd0123456789', '12345678');
61+
testCipher1('0123456789abcd0123456789', new Buffer('12345678'));
62+
testCipher1(new Buffer('0123456789abcd0123456789'), '12345678');
63+
testCipher1(new Buffer('0123456789abcd0123456789'), new Buffer('12345678'));
64+
65+
testCipher2(new Buffer('0123456789abcd0123456789'), new Buffer('12345678'));
66+

test/parallel/test-crypto-dh.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ assert.equal(secret1, secret3);
5858

5959
// Run this one twice to make sure that the dh3 clears its error properly
6060
(function() {
61-
var c = crypto.createDecipher('aes-128-ecb', '');
61+
var c = crypto.createDecipheriv('aes-128-ecb', crypto.randomBytes(16), '');
6262
assert.throws(function() { c.final('utf8'); }, /wrong final block length/);
6363
})();
6464

@@ -67,7 +67,7 @@ assert.throws(function() {
6767
}, /key is too small/i);
6868

6969
(function() {
70-
var c = crypto.createDecipher('aes-128-ecb', '');
70+
var c = crypto.createDecipheriv('aes-128-ecb', crypto.randomBytes(16), '');
7171
assert.throws(function() { c.final('utf8'); }, /wrong final block length/);
7272
})();
7373

test/parallel/test-crypto.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,11 @@ assertSorted(crypto.getCurves());
9393
// throw, not assert in C++ land.
9494
assert.throws(function() {
9595
crypto.createCipher('aes192', 'test').update('0', 'hex');
96-
}, /Bad input string/);
96+
}, common.hasFipsCrypto ? /not supported in FIPS mode/ : /Bad input string/);
9797

9898
assert.throws(function() {
9999
crypto.createDecipher('aes192', 'test').update('0', 'hex');
100-
}, /Bad input string/);
100+
}, common.hasFipsCrypto ? /not supported in FIPS mode/ : /Bad input string/);
101101

102102
assert.throws(function() {
103103
crypto.createHash('sha1').update('0', 'hex');

0 commit comments

Comments
 (0)