Skip to content

Commit 63de2ad

Browse files
chux0519BethGriggs
authored andcommittedOct 21, 2019
crypto: add support for chacha20-poly1305 for AEAD
openSSL supports AEAD_CHACHA20_POLY1305(rfc7539) since 1.1. PR-URL: #24081 Fixes: #24080 Refs: https://tools.ietf.org/html/rfc7539 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Sam Roberts <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
1 parent e53dbba commit 63de2ad

File tree

4 files changed

+75
-26
lines changed

4 files changed

+75
-26
lines changed
 

‎doc/api/crypto.md

+6
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,9 @@ Adversaries][] for details.
14441444
<!-- YAML
14451445
added: v0.1.94
14461446
changes:
1447+
- version: REPLACEME
1448+
pr-url: https://github.com/nodejs/node/pull/24081
1449+
description: The cipher `chacha20-poly1305` is now supported.
14471450
- version: v10.10.0
14481451
pr-url: https://github.com/nodejs/node/pull/21447
14491452
description: Ciphers in OCB mode are now supported.
@@ -1549,6 +1552,9 @@ to create the `Decipher` object.
15491552
<!-- YAML
15501553
added: v0.1.94
15511554
changes:
1555+
- version: REPLACEME
1556+
pr-url: https://github.com/nodejs/node/pull/24081
1557+
description: The cipher `chacha20-poly1305` is now supported.
15521558
- version: v10.10.0
15531559
pr-url: https://github.com/nodejs/node/pull/21447
15541560
description: Ciphers in OCB mode are now supported.

‎src/node_crypto.cc

+30-25
Original file line numberDiff line numberDiff line change
@@ -2557,12 +2557,21 @@ int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
25572557
return 1;
25582558
}
25592559

2560-
static bool IsSupportedAuthenticatedMode(int mode) {
2561-
return mode == EVP_CIPH_CCM_MODE ||
2560+
static bool IsSupportedAuthenticatedMode(const EVP_CIPHER* cipher) {
2561+
const int mode = EVP_CIPHER_mode(cipher);
2562+
// Check `chacha20-poly1305` separately, it is also an AEAD cipher,
2563+
// but its mode is 0 which doesn't indicate
2564+
return EVP_CIPHER_nid(cipher) == NID_chacha20_poly1305 ||
2565+
mode == EVP_CIPH_CCM_MODE ||
25622566
mode == EVP_CIPH_GCM_MODE ||
25632567
IS_OCB_MODE(mode);
25642568
}
25652569

2570+
static bool IsSupportedAuthenticatedMode(const EVP_CIPHER_CTX* ctx) {
2571+
const EVP_CIPHER* cipher = EVP_CIPHER_CTX_cipher(ctx);
2572+
return IsSupportedAuthenticatedMode(cipher);
2573+
}
2574+
25662575
void CipherBase::Initialize(Environment* env, Local<Object> target) {
25672576
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
25682577

@@ -2610,7 +2619,7 @@ void CipherBase::CommonInit(const char* cipher_type,
26102619
"Failed to initialize cipher");
26112620
}
26122621

2613-
if (IsSupportedAuthenticatedMode(mode)) {
2622+
if (IsSupportedAuthenticatedMode(cipher)) {
26142623
CHECK_GE(iv_len, 0);
26152624
if (!InitAuthenticated(cipher_type, iv_len, auth_tag_len))
26162625
return;
@@ -2712,8 +2721,7 @@ void CipherBase::InitIv(const char* cipher_type,
27122721
}
27132722

27142723
const int expected_iv_len = EVP_CIPHER_iv_length(cipher);
2715-
const int mode = EVP_CIPHER_mode(cipher);
2716-
const bool is_authenticated_mode = IsSupportedAuthenticatedMode(mode);
2724+
const bool is_authenticated_mode = IsSupportedAuthenticatedMode(cipher);
27172725
const bool has_iv = iv_len >= 0;
27182726

27192727
// Throw if no IV was passed and the cipher requires an IV
@@ -2785,7 +2793,20 @@ bool CipherBase::InitAuthenticated(const char* cipher_type, int iv_len,
27852793
}
27862794

27872795
const int mode = EVP_CIPHER_CTX_mode(ctx_.get());
2788-
if (mode == EVP_CIPH_CCM_MODE || IS_OCB_MODE(mode)) {
2796+
if (mode == EVP_CIPH_GCM_MODE) {
2797+
if (auth_tag_len != kNoAuthTagLength) {
2798+
if (!IsValidGCMTagLength(auth_tag_len)) {
2799+
char msg[50];
2800+
snprintf(msg, sizeof(msg),
2801+
"Invalid GCM authentication tag length: %u", auth_tag_len);
2802+
env()->ThrowError(msg);
2803+
return false;
2804+
}
2805+
2806+
// Remember the given authentication tag length for later.
2807+
auth_tag_len_ = auth_tag_len;
2808+
}
2809+
} else {
27892810
if (auth_tag_len == kNoAuthTagLength) {
27902811
char msg[128];
27912812
snprintf(msg, sizeof(msg), "authTagLength required for %s", cipher_type);
@@ -2818,21 +2839,6 @@ bool CipherBase::InitAuthenticated(const char* cipher_type, int iv_len,
28182839
if (iv_len == 12) max_message_size_ = 16777215;
28192840
if (iv_len == 13) max_message_size_ = 65535;
28202841
}
2821-
} else {
2822-
CHECK_EQ(mode, EVP_CIPH_GCM_MODE);
2823-
2824-
if (auth_tag_len != kNoAuthTagLength) {
2825-
if (!IsValidGCMTagLength(auth_tag_len)) {
2826-
char msg[50];
2827-
snprintf(msg, sizeof(msg),
2828-
"Invalid GCM authentication tag length: %u", auth_tag_len);
2829-
env()->ThrowError(msg);
2830-
return false;
2831-
}
2832-
2833-
// Remember the given authentication tag length for later.
2834-
auth_tag_len_ = auth_tag_len;
2835-
}
28362842
}
28372843

28382844
return true;
@@ -2855,8 +2861,7 @@ bool CipherBase::CheckCCMMessageLength(int message_len) {
28552861
bool CipherBase::IsAuthenticatedMode() const {
28562862
// Check if this cipher operates in an AEAD mode that we support.
28572863
CHECK(ctx_);
2858-
const int mode = EVP_CIPHER_CTX_mode(ctx_.get());
2859-
return IsSupportedAuthenticatedMode(mode);
2864+
return IsSupportedAuthenticatedMode(ctx_.get());
28602865
}
28612866

28622867

@@ -2913,7 +2918,7 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo<Value>& args) {
29132918
} else if (mode == EVP_CIPH_OCB_MODE) {
29142919
// At this point, the tag length is already known and must match the
29152920
// length of the given authentication tag.
2916-
CHECK(mode == EVP_CIPH_CCM_MODE || IS_OCB_MODE(mode));
2921+
CHECK(IsSupportedAuthenticatedMode(cipher->ctx_.get()));
29172922
CHECK_NE(cipher->auth_tag_len_, kNoAuthTagLength);
29182923
if (cipher->auth_tag_len_ != tag_len) {
29192924
char msg[50];
@@ -3120,7 +3125,7 @@ bool CipherBase::Final(unsigned char** out, int* out_len) {
31203125
*out = Malloc<unsigned char>(
31213126
static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_.get())));
31223127

3123-
if (kind_ == kDecipher && IsSupportedAuthenticatedMode(mode)) {
3128+
if (kind_ == kDecipher && IsSupportedAuthenticatedMode(ctx_.get())) {
31243129
MaybePassAuthTagToOpenSSL();
31253130
}
31263131

‎test/fixtures/aead-vectors.js

+37
Original file line numberDiff line numberDiff line change
@@ -662,5 +662,42 @@ module.exports = [
662662
'481529c76b6a',
663663
tag: 'd0c515f4d1cdd4fdac4f02ab',
664664
tampered: true
665+
},
666+
667+
// Test case from rfc7539 section 2.8.2
668+
{ algo: 'chacha20-poly1305',
669+
key: '808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f',
670+
iv: '070000004041424344454647',
671+
plain: '4c616469657320616e642047656e746c656d656e206f662074686520636c6173' +
672+
'73206f66202739393a204966204920636f756c64206f6666657220796f75206f' +
673+
'6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73' +
674+
'637265656e20776f756c642062652069742e',
675+
plainIsHex: true,
676+
aad: '50515253c0c1c2c3c4c5c6c7',
677+
ct: 'd31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5' +
678+
'a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e06' +
679+
'0b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fa' +
680+
'b324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d265' +
681+
'86cec64b6116',
682+
tag: '1ae10b594f09e26a7e902ecbd0600691',
683+
tampered: false
684+
},
685+
686+
{ algo: 'chacha20-poly1305',
687+
key: '808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f',
688+
iv: '070000004041424344454647',
689+
plain: '4c616469657320616e642047656e746c656d656e206f662074686520636c6173' +
690+
'73206f66202739393a204966204920636f756c64206f6666657220796f75206f' +
691+
'6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73' +
692+
'637265656e20776f756c642062652069742e',
693+
plainIsHex: true,
694+
aad: '50515253c0c1c2c3c4c5c6c7',
695+
ct: 'd31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5' +
696+
'a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e06' +
697+
'0b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fa' +
698+
'b324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d265' +
699+
'86cec64b6116',
700+
tag: '1ae10b594f09e26a7e902ecbd0600692',
701+
tampered: true
665702
}
666703
];

‎test/parallel/test-crypto-authenticated.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,10 @@ for (const test of TEST_CASES) {
9797

9898
const isCCM = /^aes-(128|192|256)-ccm$/.test(test.algo);
9999
const isOCB = /^aes-(128|192|256)-ocb$/.test(test.algo);
100+
const isChacha20Poly1305 = test.algo === 'chacha20-poly1305';
100101

101102
let options;
102-
if (isCCM || isOCB)
103+
if (isCCM || isOCB || isChacha20Poly1305)
103104
options = { authTagLength: test.tag.length / 2 };
104105

105106
const inputEncoding = test.plainIsHex ? 'hex' : 'ascii';

0 commit comments

Comments
 (0)
Please sign in to comment.