Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 30 additions & 10 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4481,13 +4481,13 @@ bool SSLCtxPointer::setCipherSuites(const char* ciphers) {

// ============================================================================

#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
#if OPENSSL_WITH_FETCHED_CIPHERS
Cipher::Cipher(DeleteFnPtr<EVP_CIPHER, EVP_CIPHER_free> cipher)
: cipher_(cipher.get()), fetched_cipher_(std::move(cipher)) {}
#endif

Cipher::Cipher(const Cipher& other) : cipher_(other.cipher_) {
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
#if OPENSSL_WITH_FETCHED_CIPHERS
if (other.fetched_cipher_ != nullptr) {
if (EVP_CIPHER_up_ref(other.fetched_cipher_.get()) == 1) {
fetched_cipher_.reset(other.fetched_cipher_.get());
Expand All @@ -4500,7 +4500,7 @@ Cipher::Cipher(const Cipher& other) : cipher_(other.cipher_) {

Cipher& Cipher::operator=(const Cipher& other) {
if (this == &other) return *this;
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
#if OPENSSL_WITH_FETCHED_CIPHERS
if (other.fetched_cipher_ != nullptr) {
if (EVP_CIPHER_up_ref(other.fetched_cipher_.get()) == 1) {
fetched_cipher_.reset(other.fetched_cipher_.get());
Expand All @@ -4521,7 +4521,7 @@ const Cipher Cipher::FromName(const char* name) {
const EVP_CIPHER* cipher = EVP_get_cipherbyname(name);
if (cipher != nullptr) return Cipher(cipher);

#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
#if OPENSSL_WITH_FETCHED_CIPHERS
MarkPopErrorOnReturn mark_pop_error_on_return;
DeleteFnPtr<EVP_CIPHER, EVP_CIPHER_free> fetched(
EVP_CIPHER_fetch(nullptr, name, nullptr));
Expand All @@ -4536,7 +4536,14 @@ const Cipher Cipher::FromName(const char* name) {
mode == EVP_CIPH_GCM_SIV_MODE ||
#endif
false;
if (is_siv_mode) return Cipher(std::move(fetched));
const bool is_sm4_cipher =
#if OPENSSL_WITH_SM4_PROVIDER_CIPHERS
EVP_CIPHER_is_a(fetched.get(), "SM4-GCM") ||
EVP_CIPHER_is_a(fetched.get(), "SM4-CCM") ||
EVP_CIPHER_is_a(fetched.get(), "SM4-XTS") ||
#endif
false;
if (is_siv_mode || is_sm4_cipher) return Cipher(std::move(fetched));

return Cipher();
#else
Expand All @@ -4548,7 +4555,7 @@ const Cipher Cipher::FromNid(int nid) {
const EVP_CIPHER* cipher = EVP_get_cipherbynid(nid);
if (cipher != nullptr) return Cipher(cipher);

#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
#if OPENSSL_WITH_FETCHED_CIPHERS
const char* name = OBJ_nid2sn(nid);
if (name != nullptr) return FromName(name);
#endif
Expand Down Expand Up @@ -4706,7 +4713,7 @@ const char* Cipher::getName() const {
const char* name = OBJ_nid2sn(nid);
if (name != nullptr) return name;
}
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
#if OPENSSL_WITH_FETCHED_CIPHERS
return EVP_CIPHER_get0_name(cipher_);
#else
return {};
Expand Down Expand Up @@ -6320,6 +6327,14 @@ constexpr const char* kProviderOnlyAesGcmSivCiphers[] = {
};
#endif

#if OPENSSL_WITH_SM4_PROVIDER_CIPHERS
constexpr const char* kProviderOnlySm4Ciphers[] = {
"sm4-gcm",
"sm4-ccm",
"sm4-xts",
};
#endif

#if OPENSSL_VERSION_MAJOR >= 3
template <class TypeName,
TypeName* fetch_type(OSSL_LIB_CTX*, const char*, const char*),
Expand Down Expand Up @@ -6386,11 +6401,11 @@ void Cipher::ForEach(Cipher::CipherNameCallback callback) {
array_push_back<EVP_CIPHER>,
#endif
&context);
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
#if OPENSSL_WITH_FETCHED_CIPHERS
auto maybe_push_provider_only_cipher = [&](const char* name) {
EVP_CIPHER* cipher = EVP_CIPHER_fetch(nullptr, name, nullptr);
DeleteFnPtr<EVP_CIPHER, EVP_CIPHER_free> cipher(
EVP_CIPHER_fetch(nullptr, name, nullptr));
if (cipher == nullptr) return;
EVP_CIPHER_free(cipher);
context.cb(name);
};
#endif
Expand All @@ -6404,6 +6419,11 @@ void Cipher::ForEach(Cipher::CipherNameCallback callback) {
maybe_push_provider_only_cipher(name);
}
#endif
#if OPENSSL_WITH_SM4_PROVIDER_CIPHERS
for (const char* name : kProviderOnlySm4Ciphers) {
maybe_push_provider_only_cipher(name);
}
#endif
#endif
}

Expand Down
17 changes: 15 additions & 2 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@
#define OPENSSL_WITH_AES_GCM_SIV 0
#endif

#if !defined(OPENSSL_IS_BORINGSSL) && OPENSSL_VERSION_PREREQ(3, 0)
#define OPENSSL_WITH_SM4_PROVIDER_CIPHERS 1
#else
#define OPENSSL_WITH_SM4_PROVIDER_CIPHERS 0
#endif

#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV || \
OPENSSL_WITH_SM4_PROVIDER_CIPHERS
#define OPENSSL_WITH_FETCHED_CIPHERS 1
#else
#define OPENSSL_WITH_FETCHED_CIPHERS 0
#endif

#if defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_PREREQ(3, 2)
#define OPENSSL_WITH_SIGNATURE_CONTEXT_STRING 1
#else
Expand Down Expand Up @@ -452,7 +465,7 @@ class Cipher final {
Cipher(const Cipher& other);
Cipher& operator=(const Cipher& other);
inline Cipher& operator=(const EVP_CIPHER* cipher) {
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
#if OPENSSL_WITH_FETCHED_CIPHERS
fetched_cipher_.reset();
#endif
cipher_ = cipher;
Expand Down Expand Up @@ -550,7 +563,7 @@ class Cipher final {

private:
const EVP_CIPHER* cipher_ = nullptr;
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
#if OPENSSL_WITH_FETCHED_CIPHERS
explicit Cipher(DeleteFnPtr<EVP_CIPHER, EVP_CIPHER_free> cipher);
DeleteFnPtr<EVP_CIPHER, EVP_CIPHER_free> fetched_cipher_;
#endif
Expand Down
6 changes: 6 additions & 0 deletions doc/api/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -3566,6 +3566,9 @@ operations. The specific constants currently defined are described in
<!-- YAML
added: v0.1.94
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/65480
description: SM4-GCM, SM4-CCM, and SM4-XTS ciphers are now supported.
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/63411
description: Ciphers in SIV and GCM-SIV modes are now supported.
Expand Down Expand Up @@ -3651,6 +3654,9 @@ given IV will be.
<!-- YAML
added: v0.1.94
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/65480
description: SM4-GCM, SM4-CCM, and SM4-XTS ciphers are now supported.
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/63411
description: Ciphers in SIV and GCM-SIV modes are now supported.
Expand Down
32 changes: 32 additions & 0 deletions test/fixtures/aead-vectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,38 @@ module.exports = [
ct: '0eaccb',
tag: '93da9bb81333aee0c785b240d319719d', tampered: false },

// RFC 8998, Appendix A.1
{ algo: 'sm4-gcm',
key: '0123456789abcdeffedcba9876543210',
iv: '00001234567800000000abcd',
plain: 'aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb' +
'ccccccccccccccccdddddddddddddddd' +
'eeeeeeeeeeeeeeeeffffffffffffffff' +
'eeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaa',
plainIsHex: true,
aad: 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
ct: '17f399f08c67d5ee19d0dc9969c4bb7d' +
'5fd46fd3756489069157b282bb200735' +
'd82710ca5c22f0ccfa7cbf93d496ac15' +
'a56834cbcf98c397b4024a2691233b8d',
tag: '83de3541e4c2b58177e065a9bf7b62ec', tampered: false },

// RFC 8998, Appendix A.2
{ algo: 'sm4-ccm',
key: '0123456789abcdeffedcba9876543210',
iv: '00001234567800000000abcd',
plain: 'aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb' +
'ccccccccccccccccdddddddddddddddd' +
'eeeeeeeeeeeeeeeeffffffffffffffff' +
'eeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaa',
plainIsHex: true,
aad: 'feedfacedeadbeeffeedfacedeadbeefabaddad2',
ct: '48af93501fa62adbcd414cce6034d895' +
'dda1bf8f132f042098661572e7483094' +
'fd12e518ce062c98acee28d95df4416b' +
'ed31a2f04476c18bb40c84a74b97dc5b',
tag: '16842d4fa186f56ab33256971fa110f4', tampered: false },

{ algo: 'aes-128-gcm',
key: '6970787039613669314d623455536234',
iv: '583673497131313748307652', plain: 'Hello World!',
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-crypto-authenticated.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ for (const test of TEST_CASES) {
continue;
}

const isCCM = /^aes-(128|192|256)-ccm$/.test(test.algo);
const isCCM = /^(?:aes-(?:128|192|256)|sm4)-ccm$/.test(test.algo);
const isOCB = /^aes-(128|192|256)-ocb$/.test(test.algo);
const isSIV = /^aes-(128|192|256)-siv$/.test(test.algo);

Expand Down
38 changes: 38 additions & 0 deletions test/parallel/test-crypto-cipheriv-decipheriv.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,43 @@ function testCipher3(key, iv) {
`encryption/decryption with key ${key} and iv ${iv}`);
}

function testSm4Xts() {
if (!crypto.getCiphers().includes('sm4-xts')) {
common.printSkipMessage('unsupported sm4-xts test');
return;
}

// GB/T 17964-2021
const key = Buffer.from(
'2B7E151628AED2A6ABF7158809CF4F3C' +
'000102030405060708090A0B0C0D0E0F', 'hex');
const iv = Buffer.from('F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF', 'hex');
const plaintext = Buffer.from(
'6BC1BEE22E409F96E93D7E117393172A' +
'AE2D8A571E03AC9C9EB76FAC45AF8E51' +
'30C81C46A35CE411E5FBC1191A0A52EF' +
'F69F2445DF4F9B17', 'hex');
const expected = Buffer.from(
'E9538251C71D7B80BBE4483FEF497BD1' +
'2C5C581BD6242FC51E08964FB4F60FDB' +
'0BA42F63499279213D318D2C11F6886E' +
'903BE7F93A1B3479', 'hex');

const cipher = crypto.createCipheriv('sm4-xts', key, iv);
const ciphertext = Buffer.concat([
cipher.update(plaintext),
cipher.final(),
]);
assert.deepStrictEqual(ciphertext, expected);

const decipher = crypto.createDecipheriv('sm4-xts', key, iv);
const decrypted = Buffer.concat([
decipher.update(ciphertext),
decipher.final(),
]);
assert.deepStrictEqual(decrypted, plaintext);
}

{
const Cipheriv = crypto.Cipheriv;
const algorithm = fips3 ? 'aes-128-cbc' : 'des-ede3-cbc';
Expand Down Expand Up @@ -167,6 +204,7 @@ if (!isFipsEnabled) {
testCipher3(Buffer.from('000102030405060708090A0B0C0D0E0F', 'hex'),
Buffer.from('A6A6A6A6A6A6A6A6', 'hex'));
}
testSm4Xts();

// Zero-sized IV or null should be accepted in ECB mode.
crypto.createCipheriv('aes-128-ecb', Buffer.alloc(16), Buffer.alloc(0));
Expand Down
17 changes: 17 additions & 0 deletions test/parallel/test-crypto-getcipherinfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,20 @@ if (ciphers.includes('aes-128-gcm-siv')) {
} else {
common.printSkipMessage('Skipping unsupported aes-128-gcm-siv test cases');
}

for (const [name, mode, keyLength, ivLength] of [
['sm4-gcm', 'gcm', 16, 12],
['sm4-ccm', 'ccm', 16, 12],
['sm4-xts', 'xts', 32, 16],
]) {
if (ciphers.includes(name)) {
const info = getCipherInfo(name);
assert.strictEqual(info.name, name);
assert.strictEqual(info.mode, mode);
assert.strictEqual(info.nid, undefined);
assert.strictEqual(info.keyLength, keyLength);
assert.strictEqual(info.ivLength, ivLength);
} else {
common.printSkipMessage(`Skipping unsupported ${name} test cases`);
}
}
Loading