Skip to content

Commit b5764bc

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 b5764bc

8 files changed

Lines changed: 410 additions & 65 deletions

File tree

deps/ncrypto/ncrypto.cc

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

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

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

31723201
const Cipher Cipher::FromNid(int nid) {
3173-
return Cipher(EVP_get_cipherbynid(nid));
3202+
const EVP_CIPHER* cipher = EVP_get_cipherbynid(nid);
3203+
if (cipher != nullptr) return Cipher(cipher);
3204+
3205+
#if OPENSSL_VERSION_MAJOR >= 3
3206+
const char* name = OBJ_nid2sn(nid);
3207+
if (name != nullptr) return FromName(name);
3208+
#endif
3209+
3210+
return Cipher();
31743211
}
31753212

31763213
const Cipher Cipher::FromCtx(const CipherCtxPointer& ctx) {
@@ -3224,6 +3261,24 @@ bool Cipher::isOcbMode() const {
32243261
return getMode() == EVP_CIPH_OCB_MODE;
32253262
}
32263263

3264+
bool Cipher::isSivMode() const {
3265+
if (!cipher_) return false;
3266+
#if OPENSSL_WITH_AES_SIV
3267+
return getMode() == EVP_CIPH_SIV_MODE;
3268+
#else
3269+
return false;
3270+
#endif
3271+
}
3272+
3273+
bool Cipher::isGcmSivMode() const {
3274+
if (!cipher_) return false;
3275+
#if OPENSSL_WITH_AES_GCM_SIV
3276+
return getMode() == EVP_CIPH_GCM_SIV_MODE;
3277+
#else
3278+
return false;
3279+
#endif
3280+
}
3281+
32273282
bool Cipher::isStreamMode() const {
32283283
if (!cipher_) return false;
32293284
return getMode() == EVP_CIPH_STREAM_CIPHER;
@@ -3278,6 +3333,14 @@ std::string_view Cipher::getModeLabel() const {
32783333
return "ocb";
32793334
case EVP_CIPH_OFB_MODE:
32803335
return "ofb";
3336+
#if OPENSSL_WITH_AES_SIV
3337+
case EVP_CIPH_SIV_MODE:
3338+
return "siv";
3339+
#endif
3340+
#if OPENSSL_WITH_AES_GCM_SIV
3341+
case EVP_CIPH_GCM_SIV_MODE:
3342+
return "gcm-siv";
3343+
#endif
32813344
case EVP_CIPH_WRAP_MODE:
32823345
return "wrap";
32833346
case EVP_CIPH_XTS_MODE:
@@ -3292,7 +3355,16 @@ const char* Cipher::getName() const {
32923355
if (!cipher_) return {};
32933356
// OBJ_nid2sn(EVP_CIPHER_nid(cipher)) is used here instead of
32943357
// EVP_CIPHER_name(cipher) for compatibility with BoringSSL.
3295-
return OBJ_nid2sn(getNid());
3358+
const int nid = getNid();
3359+
if (nid != NID_undef) {
3360+
const char* name = OBJ_nid2sn(nid);
3361+
if (name != nullptr) return name;
3362+
}
3363+
#if OPENSSL_VERSION_MAJOR >= 3
3364+
return EVP_CIPHER_get0_name(cipher_);
3365+
#else
3366+
return {};
3367+
#endif
32963368
}
32973369

32983370
bool Cipher::isSupportedAuthenticatedMode() const {
@@ -3301,6 +3373,12 @@ bool Cipher::isSupportedAuthenticatedMode() const {
33013373
case EVP_CIPH_GCM_MODE:
33023374
#ifndef OPENSSL_NO_OCB
33033375
case EVP_CIPH_OCB_MODE:
3376+
#endif
3377+
#if OPENSSL_WITH_AES_SIV
3378+
case EVP_CIPH_SIV_MODE:
3379+
#endif
3380+
#if OPENSSL_WITH_AES_GCM_SIV
3381+
case EVP_CIPH_GCM_SIV_MODE:
33043382
#endif
33053383
return true;
33063384
case EVP_CIPH_STREAM_CIPHER:
@@ -3414,6 +3492,24 @@ bool CipherCtxPointer::isWrapMode() const {
34143492
return getMode() == EVP_CIPH_WRAP_MODE;
34153493
}
34163494

3495+
bool CipherCtxPointer::isSivMode() const {
3496+
if (!ctx_) return false;
3497+
#if OPENSSL_WITH_AES_SIV
3498+
return getMode() == EVP_CIPH_SIV_MODE;
3499+
#else
3500+
return false;
3501+
#endif
3502+
}
3503+
3504+
bool CipherCtxPointer::isGcmSivMode() const {
3505+
if (!ctx_) return false;
3506+
#if OPENSSL_WITH_AES_GCM_SIV
3507+
return getMode() == EVP_CIPH_GCM_SIV_MODE;
3508+
#else
3509+
return false;
3510+
#endif
3511+
}
3512+
34173513
bool CipherCtxPointer::isChaCha20Poly1305() const {
34183514
if (!ctx_) return false;
34193515
return getNid() == NID_chacha20_poly1305;
@@ -4242,6 +4338,21 @@ struct CipherCallbackContext {
42424338
void operator()(const char* name) { cb(name); }
42434339
};
42444340

4341+
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
4342+
constexpr const char* kProviderOnlyCiphers[] = {
4343+
#if OPENSSL_WITH_AES_SIV
4344+
"aes-128-siv",
4345+
"aes-192-siv",
4346+
"aes-256-siv",
4347+
#endif
4348+
#if OPENSSL_WITH_AES_GCM_SIV
4349+
"aes-128-gcm-siv",
4350+
"aes-192-gcm-siv",
4351+
"aes-256-gcm-siv",
4352+
#endif
4353+
};
4354+
#endif
4355+
42454356
#if OPENSSL_VERSION_MAJOR >= 3
42464357
template <class TypeName,
42474358
TypeName* fetch_type(OSSL_LIB_CTX*, const char*, const char*),
@@ -4308,6 +4419,14 @@ void Cipher::ForEach(Cipher::CipherNameCallback callback) {
43084419
array_push_back<EVP_CIPHER>,
43094420
#endif
43104421
&context);
4422+
#if OPENSSL_WITH_AES_SIV || OPENSSL_WITH_AES_GCM_SIV
4423+
for (const char* name : kProviderOnlyCiphers) {
4424+
EVP_CIPHER* cipher = EVP_CIPHER_fetch(nullptr, name, nullptr);
4425+
if (cipher == nullptr) continue;
4426+
EVP_CIPHER_free(cipher);
4427+
context.cb(name);
4428+
}
4429+
#endif
43114430
#endif
43124431
}
43134432

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)