int r = cipher->CipherFinal(&out_value, &out_len);
- assert(out_value != NULL);
- assert(out_len != -1 || r == 0);
-
- if (out_len == 0 || r == 0) {
- // out_value always get allocated.
+ if (out_len <= 0 || r == 0) {
delete[] out_value;
- if (r == 0) {
- Local<Value> exception = Exception::TypeError(
- String::New("CipherFinal fail"));
- return ThrowException(exception);
- } else {
- return scope.Close(String::New(""));
- }
+ out_value = NULL;
+ if (r == 0) return ThrowCryptoTypeError(ERR_get_error());
}
- enum encoding enc = ParseEncoding(args[0], BINARY);
- if (enc == HEX) {
- // Hex encoding
- HexEncode(out_value, out_len, &out_hexdigest, &out_hex_len);
- outString = Encode(out_hexdigest, out_hex_len, BINARY);
- delete [] out_hexdigest;
- } else if (enc == BASE64) {
- // Check to see if we need to add in previous base64 overhang
- if (cipher->incomplete_base64!=NULL){
- unsigned char* complete_base64 = new unsigned char[out_len+cipher->incomplete_base64_len+1];
- memcpy(complete_base64, cipher->incomplete_base64, cipher->incomplete_base64_len);
- memcpy(&complete_base64[cipher->incomplete_base64_len], out_value, out_len);
- delete [] out_value;
-
- delete [] cipher->incomplete_base64;
- cipher->incomplete_base64=NULL;
-
- out_value=complete_base64;
- out_len += cipher->incomplete_base64_len;
- }
- base64(out_value, out_len, &out_hexdigest, &out_hex_len);
- outString = Encode(out_hexdigest, out_hex_len, BINARY);
- delete [] out_hexdigest;
- } else if (enc == BINARY) {
- outString = Encode(out_value, out_len, BINARY);
- } else {
- fprintf(stderr, "node-crypto : Cipher .final encoding "
- "can be binary, hex or base64\n");
- }
+ outString = Encode(out_value, out_len, BUFFER);
delete [] out_value;
return scope.Close(outString);
int out_len = -1;
Local<Value> outString;
- int r = cipher->DecipherFinal<TOLERATE_PADDING>(&out_value, &out_len);
+ int r = cipher->DecipherFinal(&out_value, &out_len);
- assert(out_value != NULL);
- assert(out_len != -1);
-
- if (out_len == 0 || r == 0) {
+ if (out_len <= 0 || r == 0) {
delete [] out_value; // allocated even if out_len == 0
- if (r == 0) {
- Local<Value> exception = Exception::TypeError(
- String::New("DecipherFinal fail"));
- return ThrowException(exception);
- } else {
- return scope.Close(String::New(""));
- }
+ out_value = NULL;
+ if (r == 0) return ThrowCryptoTypeError(ERR_get_error());
}
- if (args.Length() == 0 || !args[0]->IsString()) {
- outString = Encode(out_value, out_len, BINARY);
- } else {
- enum encoding enc = ParseEncoding(args[0]);
- if (enc == UTF8) {
- // See if we have any overhang from last utf8 partial ending
- if (cipher->incomplete_utf8!=NULL) {
- char* complete_out = new char[cipher->incomplete_utf8_len + out_len];
- memcpy(complete_out, cipher->incomplete_utf8, cipher->incomplete_utf8_len);
- memcpy((char *)complete_out+cipher->incomplete_utf8_len, out_value, out_len);
-
- delete [] cipher->incomplete_utf8;
- cipher->incomplete_utf8=NULL;
-
- outString = Encode(complete_out, cipher->incomplete_utf8_len+out_len, enc);
- delete [] complete_out;
- } else {
- outString = Encode(out_value, out_len, enc);
- }
- } else {
- outString = Encode(out_value, out_len, enc);
- }
- }
+ outString = Encode(out_value, out_len, BUFFER);
delete [] out_value;
return scope.Close(outString);
}
//
// Test PBKDF2 with RFC 6070 test vectors (except #4)
//
-crypto.pbkdf2('password', 'salt', 1, 20, function(err, result) {
- assert.equal(result,
- '\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24' +
- '\xaf\x60\x12\x06\x2f\xe0\x37\xa6',
- 'pbkdf1 test vector 1');
-});
+function testPBKDF2(password, salt, iterations, keylen, expected) {
+ var actual = crypto.pbkdf2Sync(password, salt, iterations, keylen);
+ assert.equal(actual.toString('binary'), expected);
-crypto.pbkdf2('password', 'salt', 2, 20, function(err, result) {
- assert.equal(result,
- '\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a' +
- '\xce\x1d\x41\xf0\xd8\xde\x89\x57',
- 'pbkdf1 test vector 2');
-});
+ crypto.pbkdf2(password, salt, iterations, keylen, function(err, actual) {
+ assert.equal(actual.toString('binary'), expected);
+ });
+}
-crypto.pbkdf2('password', 'salt', 4096, 20, function(err, result) {
- assert.equal(result,
- '\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26' +
- '\xf7\x21\xd0\x65\xa4\x29\xc1',
- 'pbkdf1 test vector 3');
-});
-crypto.pbkdf2(
- 'passwordPASSWORDpassword',
- 'saltSALTsaltSALTsaltSALTsaltSALTsalt',
- 4096,
- 25, function(err, result) {
- assert.equal(result,
- '\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62' +
- '\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38',
- 'pbkdf1 test vector 5');
- });
-
-crypto.pbkdf2('pass\0word', 'sa\0lt', 4096, 16, function(err, result) {
- assert.equal(result,
- '\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34' +
- '\x25\xe0\xc3',
- 'pbkdf1 test vector 6');
-});
+testPBKDF2('password', 'salt', 1, 20,
+ '\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24' +
+ '\xaf\x60\x12\x06\x2f\xe0\x37\xa6');
+
+testPBKDF2('password', 'salt', 2, 20,
+ '\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a' +
+ '\xce\x1d\x41\xf0\xd8\xde\x89\x57');
+
+testPBKDF2('password', 'salt', 4096, 20,
+ '\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26' +
+ '\xf7\x21\xd0\x65\xa4\x29\xc1');
+
+testPBKDF2('passwordPASSWORDpassword',
+ 'saltSALTsaltSALTsaltSALTsaltSALTsalt',
+ 4096,
+ 25,
+ '\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62' +
+ '\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38');
+
+testPBKDF2('pass\0word', 'sa\0lt', 4096, 16,
+ '\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34' +
+ '\x25\xe0\xc3');
+
+function assertSorted(list) {
+ for (var i = 0, k = list.length - 1; i < k; ++i) {
+ var a = list[i + 0];
+ var b = list[i + 1];
+ assert(a <= b);
+ }
+}
+
+// Assume that we have at least AES256-SHA.
+assert.notEqual(0, crypto.getCiphers());
+assert.notEqual(-1, crypto.getCiphers().indexOf('AES256-SHA'));
+assertSorted(crypto.getCiphers());
+
+// Assert that we have sha and sha1 but not SHA and SHA1.
+assert.notEqual(0, crypto.getHashes());
+assert.notEqual(-1, crypto.getHashes().indexOf('sha1'));
+assert.notEqual(-1, crypto.getHashes().indexOf('sha'));
+assert.equal(-1, crypto.getHashes().indexOf('SHA1'));
+assert.equal(-1, crypto.getHashes().indexOf('SHA'));
+assertSorted(crypto.getHashes());
+
+(function() {
+ var c = crypto.createDecipher('aes-128-ecb', '');
+ assert.throws(function() { c.final('utf8') }, /invalid public key/);
+})();
+
+// Base64 padding regression test, see #4837.
+(function() {
+ var c = crypto.createCipher('aes-256-cbc', 'secret');
+ var s = c.update('test', 'utf8', 'base64') + c.final('base64');
+ assert.equal(s, '375oxUQCIocvxmC5At+rvA==');
+})();
+
+ // Error path should not leak memory (check with valgrind).
+ assert.throws(function() {
+ crypto.pbkdf2('password', 'salt', 1, 20, null);
+ });
+
+ // Calling Cipher.final() or Decipher.final() twice should error but
+ // not assert. See #4886.
+ (function() {
+ var c = crypto.createCipher('aes-256-cbc', 'secret');
+ try { c.final('xxx') } catch (e) { /* Ignore. */ }
+ try { c.final('xxx') } catch (e) { /* Ignore. */ }
+ try { c.final('xxx') } catch (e) { /* Ignore. */ }
+ var d = crypto.createDecipher('aes-256-cbc', 'secret');
+ try { d.final('xxx') } catch (e) { /* Ignore. */ }
+ try { d.final('xxx') } catch (e) { /* Ignore. */ }
+ try { d.final('xxx') } catch (e) { /* Ignore. */ }
+ })();