Skip to content

Commit a1ea9b7

Browse files
committed
crypto: enable SIV and GCM-SIV modes in Cipher/Decipher APIs
Closes #63393 Signed-off-by: Filip Skokan <panva.ip@gmail.com>
1 parent 550f195 commit a1ea9b7

7 files changed

Lines changed: 351 additions & 58 deletions

File tree

deps/ncrypto/ncrypto.cc

Lines changed: 124 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3165,12 +3165,51 @@ bool SSLCtxPointer::setCipherSuites(const char* ciphers) {
31653165

31663166
// ============================================================================
31673167

3168+
#if OPENSSL_VERSION_MAJOR >= 3
3169+
Cipher::Cipher(EVP_CIPHER* cipher)
3170+
: cipher_(cipher),
3171+
fetched_cipher_(cipher, EVP_CIPHER_free) {}
3172+
#else
3173+
Cipher::Cipher(EVP_CIPHER* cipher)
3174+
: cipher_(cipher) {}
3175+
#endif
3176+
31683177
const Cipher Cipher::FromName(const char* name) {
3169-
return Cipher(EVP_get_cipherbyname(name));
3178+
const EVP_CIPHER* cipher = EVP_get_cipherbyname(name);
3179+
if (cipher != nullptr) return Cipher(cipher);
3180+
3181+
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
3182+
EVP_CIPHER* fetched = EVP_CIPHER_fetch(nullptr, name, nullptr);
3183+
if (fetched == nullptr) return Cipher();
3184+
3185+
const int mode = EVP_CIPHER_mode(fetched);
3186+
const bool is_siv_mode =
3187+
#if OPENSSL_WITH_AES_SIV
3188+
mode == EVP_CIPH_SIV_MODE ||
3189+
#endif
3190+
#if OPENSSL_WITH_AES_GCM_SIV
3191+
mode == EVP_CIPH_GCM_SIV_MODE ||
3192+
#endif
3193+
false;
3194+
if (is_siv_mode) return Cipher(fetched);
3195+
3196+
EVP_CIPHER_free(fetched);
3197+
return Cipher();
3198+
#else
3199+
return Cipher();
3200+
#endif
31703201
}
31713202

31723203
const Cipher Cipher::FromNid(int nid) {
3173-
return Cipher(EVP_get_cipherbynid(nid));
3204+
const EVP_CIPHER* cipher = EVP_get_cipherbynid(nid);
3205+
if (cipher != nullptr) return Cipher(cipher);
3206+
3207+
#if OPENSSL_VERSION_MAJOR >= 3
3208+
const char* name = OBJ_nid2sn(nid);
3209+
if (name != nullptr) return FromName(name);
3210+
#endif
3211+
3212+
return Cipher();
31743213
}
31753214

31763215
const Cipher Cipher::FromCtx(const CipherCtxPointer& ctx) {
@@ -3224,6 +3263,24 @@ bool Cipher::isOcbMode() const {
32243263
return getMode() == EVP_CIPH_OCB_MODE;
32253264
}
32263265

3266+
bool Cipher::isSivMode() const {
3267+
if (!cipher_) return false;
3268+
#if OPENSSL_WITH_AES_SIV
3269+
return getMode() == EVP_CIPH_SIV_MODE;
3270+
#else
3271+
return false;
3272+
#endif
3273+
}
3274+
3275+
bool Cipher::isGcmSivMode() const {
3276+
if (!cipher_) return false;
3277+
#if OPENSSL_WITH_AES_GCM_SIV
3278+
return getMode() == EVP_CIPH_GCM_SIV_MODE;
3279+
#else
3280+
return false;
3281+
#endif
3282+
}
3283+
32273284
bool Cipher::isStreamMode() const {
32283285
if (!cipher_) return false;
32293286
return getMode() == EVP_CIPH_STREAM_CIPHER;
@@ -3278,6 +3335,14 @@ std::string_view Cipher::getModeLabel() const {
32783335
return "ocb";
32793336
case EVP_CIPH_OFB_MODE:
32803337
return "ofb";
3338+
#if OPENSSL_WITH_AES_SIV
3339+
case EVP_CIPH_SIV_MODE:
3340+
return "siv";
3341+
#endif
3342+
#if OPENSSL_WITH_AES_GCM_SIV
3343+
case EVP_CIPH_GCM_SIV_MODE:
3344+
return "gcm-siv";
3345+
#endif
32813346
case EVP_CIPH_WRAP_MODE:
32823347
return "wrap";
32833348
case EVP_CIPH_XTS_MODE:
@@ -3292,7 +3357,16 @@ const char* Cipher::getName() const {
32923357
if (!cipher_) return {};
32933358
// OBJ_nid2sn(EVP_CIPHER_nid(cipher)) is used here instead of
32943359
// EVP_CIPHER_name(cipher) for compatibility with BoringSSL.
3295-
return OBJ_nid2sn(getNid());
3360+
const int nid = getNid();
3361+
if (nid != NID_undef) {
3362+
const char* name = OBJ_nid2sn(nid);
3363+
if (name != nullptr) return name;
3364+
}
3365+
#if OPENSSL_VERSION_MAJOR >= 3
3366+
return EVP_CIPHER_get0_name(cipher_);
3367+
#else
3368+
return {};
3369+
#endif
32963370
}
32973371

32983372
bool Cipher::isSupportedAuthenticatedMode() const {
@@ -3301,6 +3375,12 @@ bool Cipher::isSupportedAuthenticatedMode() const {
33013375
case EVP_CIPH_GCM_MODE:
33023376
#ifndef OPENSSL_NO_OCB
33033377
case EVP_CIPH_OCB_MODE:
3378+
#endif
3379+
#if OPENSSL_WITH_AES_SIV
3380+
case EVP_CIPH_SIV_MODE:
3381+
#endif
3382+
#if OPENSSL_WITH_AES_GCM_SIV
3383+
case EVP_CIPH_GCM_SIV_MODE:
33043384
#endif
33053385
return true;
33063386
case EVP_CIPH_STREAM_CIPHER:
@@ -3414,6 +3494,24 @@ bool CipherCtxPointer::isWrapMode() const {
34143494
return getMode() == EVP_CIPH_WRAP_MODE;
34153495
}
34163496

3497+
bool CipherCtxPointer::isSivMode() const {
3498+
if (!ctx_) return false;
3499+
#if OPENSSL_WITH_AES_SIV
3500+
return getMode() == EVP_CIPH_SIV_MODE;
3501+
#else
3502+
return false;
3503+
#endif
3504+
}
3505+
3506+
bool CipherCtxPointer::isGcmSivMode() const {
3507+
if (!ctx_) return false;
3508+
#if OPENSSL_WITH_AES_GCM_SIV
3509+
return getMode() == EVP_CIPH_GCM_SIV_MODE;
3510+
#else
3511+
return false;
3512+
#endif
3513+
}
3514+
34173515
bool CipherCtxPointer::isChaCha20Poly1305() const {
34183516
if (!ctx_) return false;
34193517
return getNid() == NID_chacha20_poly1305;
@@ -4242,6 +4340,21 @@ struct CipherCallbackContext {
42424340
void operator()(const char* name) { cb(name); }
42434341
};
42444342

4343+
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
4344+
constexpr const char* kProviderOnlyCiphers[] = {
4345+
#if OPENSSL_WITH_AES_SIV
4346+
"aes-128-siv",
4347+
"aes-192-siv",
4348+
"aes-256-siv",
4349+
#endif
4350+
#if OPENSSL_WITH_AES_GCM_SIV
4351+
"aes-128-gcm-siv",
4352+
"aes-192-gcm-siv",
4353+
"aes-256-gcm-siv",
4354+
#endif
4355+
};
4356+
#endif
4357+
42454358
#if OPENSSL_VERSION_MAJOR >= 3
42464359
template <class TypeName,
42474360
TypeName* fetch_type(OSSL_LIB_CTX*, const char*, const char*),
@@ -4308,6 +4421,14 @@ void Cipher::ForEach(Cipher::CipherNameCallback callback) {
43084421
array_push_back<EVP_CIPHER>,
43094422
#endif
43104423
&context);
4424+
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
4425+
for (const char* name : kProviderOnlyCiphers) {
4426+
EVP_CIPHER* cipher = EVP_CIPHER_fetch(nullptr, name, nullptr);
4427+
if (cipher == nullptr) continue;
4428+
EVP_CIPHER_free(cipher);
4429+
context.cb(name);
4430+
}
4431+
#endif
43114432
#endif
43124433
}
43134434

deps/ncrypto/ncrypto.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@
7070
#define OPENSSL_WITH_KMAC 0
7171
#endif
7272

73+
#if !defined(OPENSSL_IS_BORINGSSL) && OPENSSL_VERSION_PREREQ(3, 0)
74+
#define OPENSSL_WITH_AES_SIV 1
75+
#else
76+
#define OPENSSL_WITH_AES_SIV 0
77+
#endif
78+
79+
#if !defined(OPENSSL_IS_BORINGSSL) && OPENSSL_VERSION_PREREQ(3, 2)
80+
#define OPENSSL_WITH_AES_GCM_SIV 1
81+
#else
82+
#define OPENSSL_WITH_AES_GCM_SIV 0
83+
#endif
84+
7385
#if defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_PREREQ(3, 2)
7486
#define OPENSSL_WITH_SIGNATURE_CONTEXT_STRING 1
7587
#else
@@ -402,6 +414,7 @@ class Cipher final {
402414
Cipher(const Cipher&) = default;
403415
Cipher& operator=(const Cipher&) = default;
404416
inline Cipher& operator=(const EVP_CIPHER* cipher) {
417+
fetched_cipher_.reset();
405418
cipher_ = cipher;
406419
return *this;
407420
}
@@ -424,6 +437,8 @@ class Cipher final {
424437
bool isCtrMode() const;
425438
bool isCcmMode() const;
426439
bool isOcbMode() const;
440+
bool isSivMode() const;
441+
bool isGcmSivMode() const;
427442
bool isStreamMode() const;
428443
bool isChaCha20Poly1305() const;
429444

@@ -493,7 +508,10 @@ class Cipher final {
493508
}
494509

495510
private:
511+
explicit Cipher(EVP_CIPHER* cipher);
512+
496513
const EVP_CIPHER* cipher_ = nullptr;
514+
std::shared_ptr<EVP_CIPHER> fetched_cipher_;
497515
};
498516

499517
// ============================================================================
@@ -833,6 +851,8 @@ class CipherCtxPointer final {
833851
bool isOcbMode() const;
834852
bool isCcmMode() const;
835853
bool isWrapMode() const;
854+
bool isSivMode() const;
855+
bool isGcmSivMode() const;
836856
bool isChaCha20Poly1305() const;
837857

838858
bool update(const Buffer<const unsigned char>& in,

0 commit comments

Comments
 (0)