diff --git a/include/aead.h b/include/aead.h new file mode 100644 index 0000000..20cf4df --- /dev/null +++ b/include/aead.h @@ -0,0 +1,137 @@ +#pragma once + +#include "ncrypto.h" + +#ifdef OPENSSL_IS_BORINGSSL + +namespace ncrypto { + +class AeadCtxPointer; + +class Aead final { + private: + // BoringSSL does not keep a list of AEADs, so we need to maintain our own. + struct AeadInfo { + std::string name; + int mode; + int nid = 0; // Note: BoringSSL only defines NIDs for some AEADs + }; + + public: + Aead() = default; + Aead(const AeadInfo* info, const EVP_AEAD* aead) : info_(info), aead_(aead) {} + Aead(const Aead&) = default; + Aead& operator=(const Aead&) = default; + NCRYPTO_DISALLOW_MOVE(Aead) + + inline const EVP_AEAD* get() const { return aead_; } + std::string_view getModeLabel() const; + inline operator const EVP_AEAD*() const { return aead_; } + inline operator bool() const { return aead_ != nullptr; } + + int getMode() const; + int getNonceLength() const; + int getKeyLength() const; + int getBlockSize() const; + int getMaxOverhead() const; + int getMaxTagLength() const; + std::string_view getName() const; + + static const Aead FromName(std::string_view name); + + // TODO(npaun): BoringSSL does not define NIDs for all AEADs. + // This method is included only for implementing getCipherInfo and can't be + // used to construct an Aead instance. + int getNid() const; + // static const AEAD FromNid(int nid); + + static const Aead FromCtx(std::string_view name, const AeadCtxPointer& ctx); + + using AeadNameCallback = std::function; + + // Iterates the known ciphers if the underlying implementation + // is able to do so. + static void ForEach(AeadNameCallback callback); + + // Utilities to get various AEADs by type. + + static const Aead EMPTY; + static const Aead AES_128_GCM; + static const Aead AES_192_GCM; + static const Aead AES_256_GCM; + static const Aead CHACHA20_POLY1305; + static const Aead XCHACHA20_POLY1305; + static const Aead AES_128_CTR_HMAC_SHA256; + static const Aead AES_256_CTR_HMAC_SHA256; + static const Aead AES_128_GCM_SIV; + static const Aead AES_256_GCM_SIV; + static const Aead AES_128_GCM_RANDNONCE; + static const Aead AES_256_GCM_RANDNONCE; + static const Aead AES_128_CCM_BLUETOOTH; + static const Aead AES_128_CCM_BLUETOOTH_8; + static const Aead AES_128_CCM_MATTER; + static const Aead AES_128_EAX; + static const Aead AES_256_EAX; + + private: + const EVP_AEAD* aead_ = nullptr; + const AeadInfo* info_ = nullptr; + + using AeadConstructor = const EVP_AEAD* (*)(); + static const std::unordered_map aeadIndex; + static const Aead FromConstructor(AeadConstructor construct); +}; + +class AeadCtxPointer final { + public: + static AeadCtxPointer New( + const Aead& aead, + bool encrypt, + const unsigned char* key = nullptr, + size_t keyLen = 0, + size_t tagLen = EVP_AEAD_DEFAULT_TAG_LENGTH /* = 0 */); + + AeadCtxPointer() = default; + explicit AeadCtxPointer(EVP_AEAD_CTX* ctx); + AeadCtxPointer(AeadCtxPointer&& other) noexcept; + AeadCtxPointer& operator=(AeadCtxPointer&& other) noexcept; + NCRYPTO_DISALLOW_COPY(AeadCtxPointer) + ~AeadCtxPointer(); + + inline bool operator==(std::nullptr_t) const noexcept { + return ctx_ == nullptr; + } + inline operator bool() const { return ctx_ != nullptr; } + inline EVP_AEAD_CTX* get() const { return ctx_.get(); } + inline operator EVP_AEAD_CTX*() const { return ctx_.get(); } + void reset(EVP_AEAD_CTX* ctx = nullptr); + EVP_AEAD_CTX* release(); + + bool init(const Aead& aead, + bool encrypt, + const unsigned char* key = nullptr, + size_t keyLen = 0, + size_t tagLen = EVP_AEAD_DEFAULT_TAG_LENGTH /* = 0 */); + + // TODO(npaun): BoringSSL does not define NIDs for all AEADs. + // Decide if we will even implement this method. + // int getNid() const; + + bool encrypt(const Buffer& in, + Buffer& out, + Buffer& tag, + const Buffer& nonce, + const Buffer& aad); + + bool decrypt(const Buffer& in, + Buffer& out, + const Buffer& tag, + const Buffer& nonce, + const Buffer& aad); + + private: + DeleteFnPtr ctx_; +}; +} // namespace ncrypto + +#endif // OPENSSL_IS_BORINGSSL diff --git a/include/ncrypto.h b/include/ncrypto.h index 6a84162..7ac4691 100644 --- a/include/ncrypto.h +++ b/include/ncrypto.h @@ -81,6 +81,13 @@ namespace ncrypto { // ============================================================================ // Utility macros +inline bool EqualNoCase(const std::string_view a, const std::string_view b) { + if (a.size() != b.size()) return false; + return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { + return std::tolower(a) == std::tolower(b); + }); +} + #if NCRYPTO_DEVELOPMENT_CHECKS #define NCRYPTO_STR(x) #x #define NCRYPTO_REQUIRE(EXPR) \ @@ -1753,137 +1760,6 @@ class KEM final { #endif // OPENSSL_VERSION_MAJOR >= 3 -// ============================================================================ -// AEAD (Authenticated Encryption with Associated Data) -// Note that the underlying EVP_AEAD interface is specific to BoringSSL. AEAD -// primitives are accessed through the Cipher class instead, if using OpenSSL. - -#ifdef OPENSSL_IS_BORINGSSL -class Aead final : public ModeMixin { - private: - // BoringSSL does not keep a list of AEADs, so we need to maintain our own. - struct AeadInfo { - std::string name; - int mode; - int nid = 0; // Note: BoringSSL only defines NIDs for some AEADs - }; - - public: - Aead() = default; - Aead(const AeadInfo* info, const EVP_AEAD* aead) : info_(info), aead_(aead) {} - Aead(const Aead&) = default; - Aead& operator=(const Aead&) = default; - NCRYPTO_DISALLOW_MOVE(Aead) - - inline const EVP_AEAD* get() const { return aead_; } - inline operator const EVP_AEAD*() const { return aead_; } - inline operator bool() const { return aead_ != nullptr; } - - int getMode() const; - int getNonceLength() const; - int getKeyLength() const; - int getBlockSize() const; - int getMaxOverhead() const; - int getMaxTagLength() const; - std::string_view getName() const; - - static const Aead FromName(std::string_view name); - - // TODO(npaun): BoringSSL does not define NIDs for all AEADs. - // This method is included only for implementing getCipherInfo and can't be - // used to construct an Aead instance. - int getNid() const; - // static const AEAD FromNid(int nid); - - static const Aead FromCtx(std::string_view name, const AeadCtxPointer& ctx); - - using AeadNameCallback = std::function; - - // Iterates the known ciphers if the underlying implementation - // is able to do so. - static void ForEach(AeadNameCallback callback); - - // Utilities to get various AEADs by type. - - static const Aead EMPTY; - static const Aead AES_128_GCM; - static const Aead AES_192_GCM; - static const Aead AES_256_GCM; - static const Aead CHACHA20_POLY1305; - static const Aead XCHACHA20_POLY1305; - static const Aead AES_128_CTR_HMAC_SHA256; - static const Aead AES_256_CTR_HMAC_SHA256; - static const Aead AES_128_GCM_SIV; - static const Aead AES_256_GCM_SIV; - static const Aead AES_128_GCM_RANDNONCE; - static const Aead AES_256_GCM_RANDNONCE; - static const Aead AES_128_CCM_BLUETOOTH; - static const Aead AES_128_CCM_BLUETOOTH_8; - static const Aead AES_128_CCM_MATTER; - static const Aead AES_128_EAX; - static const Aead AES_256_EAX; - - private: - const EVP_AEAD* aead_ = nullptr; - const AeadInfo* info_ = nullptr; - - using AeadConstructor = const EVP_AEAD* (*)(); - static const std::unordered_map aeadIndex; - static const Aead FromConstructor(AeadConstructor construct); -}; - -class AeadCtxPointer final { - public: - static AeadCtxPointer New( - const Aead& aead, - bool encrypt, - const unsigned char* key = nullptr, - size_t keyLen = 0, - size_t tagLen = EVP_AEAD_DEFAULT_TAG_LENGTH /* = 0 */); - - AeadCtxPointer() = default; - explicit AeadCtxPointer(EVP_AEAD_CTX* ctx); - AeadCtxPointer(AeadCtxPointer&& other) noexcept; - AeadCtxPointer& operator=(AeadCtxPointer&& other) noexcept; - NCRYPTO_DISALLOW_COPY(AeadCtxPointer) - ~AeadCtxPointer(); - - inline bool operator==(std::nullptr_t) const noexcept { - return ctx_ == nullptr; - } - inline operator bool() const { return ctx_ != nullptr; } - inline EVP_AEAD_CTX* get() const { return ctx_.get(); } - inline operator EVP_AEAD_CTX*() const { return ctx_.get(); } - void reset(EVP_AEAD_CTX* ctx = nullptr); - EVP_AEAD_CTX* release(); - - bool init(const Aead& aead, - bool encrypt, - const unsigned char* key = nullptr, - size_t keyLen = 0, - size_t tagLen = EVP_AEAD_DEFAULT_TAG_LENGTH /* = 0 */); - - // TODO(npaun): BoringSSL does not define NIDs for all AEADs. - // Decide if we will even implement this method. - // int getNid() const; - - bool encrypt(const Buffer& in, - Buffer& out, - Buffer& tag, - const Buffer& nonce, - const Buffer& aad); - - bool decrypt(const Buffer& in, - Buffer& out, - const Buffer& tag, - const Buffer& nonce, - const Buffer& aad); - - private: - DeleteFnPtr ctx_; -}; -#endif - // ============================================================================ // Version metadata #define NCRYPTO_VERSION "0.0.1" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 87296cd..a6a733f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(ncrypto ncrypto.cpp engine.cpp) +add_library(ncrypto ncrypto.cpp engine.cpp aead.cpp) target_link_libraries(ncrypto PUBLIC ssl crypto) if (NCRYPTO_BSSL_LIBDECREPIT_MISSING) diff --git a/src/aead.cpp b/src/aead.cpp new file mode 100644 index 0000000..73ea2c7 --- /dev/null +++ b/src/aead.cpp @@ -0,0 +1,302 @@ +// ============================================================================ +// AEAD (Authenticated Encryption with Associated Data) +#include "ncrypto.h" + +#ifdef OPENSSL_IS_BORINGSSL +#include "aead.h" + +namespace ncrypto { + +const Aead Aead::FromName(std::string_view name) { + for (const auto& [construct, info] : aeadIndex) { + if (EqualNoCase(info.name, name)) { + return Aead(&info, construct()); + } + } + + return Aead(); +} + +const Aead Aead::FromCtx(std::string_view name, const AeadCtxPointer& ctx) { + for (const auto& [_, info] : aeadIndex) { + if (info.name == name) { + return Aead(&info, EVP_AEAD_CTX_aead(ctx.get())); + } + } + + return Aead(); +} + +int Aead::getMode() const { + if (!aead_) return -1; + + return info_->mode; +} + +std::string_view Aead::getModeLabel() const { + if (!aead_) return {}; + switch (getMode()) { + case EVP_CIPH_CCM_MODE: + return "ccm"; + case EVP_CIPH_CTR_MODE: + return "ctr"; + case EVP_CIPH_GCM_MODE: + return "gcm"; + case EVP_CIPH_STREAM_CIPHER: + return "stream"; + } + return "{unknown}"; +} + +int Aead::getNonceLength() const { + if (!aead_) return 0; + return EVP_AEAD_nonce_length(aead_); +} + +int Aead::getKeyLength() const { + if (!aead_) return 0; + return EVP_AEAD_key_length(aead_); +} + +int Aead::getMaxOverhead() const { + if (!aead_) return 0; + return EVP_AEAD_max_overhead(aead_); +} + +int Aead::getMaxTagLength() const { + if (!aead_) return 0; + return EVP_AEAD_max_tag_len(aead_); +} + +int Aead::getBlockSize() const { + if (!aead_) return 0; + + // EVP_CIPHER_CTX_block_size returns the block size, in bytes, of the cipher + // underlying |ctx|, or one if the cipher is a stream cipher. + return 1; +} + +std::string_view Aead::getName() const { + if (!aead_) return ""; + + return info_->name; +} + +int Aead::getNid() const { + if (!aead_) return 0; + + return info_->nid; +} + +const Aead Aead::FromConstructor(Aead::AeadConstructor construct) { + return Aead(&aeadIndex.at(construct), construct()); +} + +const std::unordered_map + Aead::aeadIndex = { + {EVP_aead_aes_128_gcm, + {.name = LN_aes_128_gcm, + .mode = EVP_CIPH_GCM_MODE, + .nid = NID_aes_128_gcm}}, + {EVP_aead_aes_192_gcm, + {.name = LN_aes_192_gcm, + .mode = EVP_CIPH_GCM_MODE, + .nid = NID_aes_192_gcm}}, + {EVP_aead_aes_256_gcm, + {.name = LN_aes_256_gcm, + .mode = EVP_CIPH_GCM_MODE, + .nid = NID_aes_256_gcm}}, + {EVP_aead_chacha20_poly1305, + {.name = LN_chacha20_poly1305, + .mode = EVP_CIPH_STREAM_CIPHER, + .nid = NID_chacha20_poly1305}}, + {EVP_aead_xchacha20_poly1305, + { + .name = "xchacha20-poly1305", + .mode = EVP_CIPH_STREAM_CIPHER, + }}, + {EVP_aead_aes_128_ctr_hmac_sha256, + { + .name = "aes-128-ctr-hmac-sha256", + .mode = EVP_CIPH_CTR_MODE, + }}, + {EVP_aead_aes_256_ctr_hmac_sha256, + { + .name = "aes-256-ctr-hmac-sha256", + .mode = EVP_CIPH_CTR_MODE, + }}, + {EVP_aead_aes_128_gcm_siv, + { + .name = "aes-128-gcm-siv", + .mode = EVP_CIPH_GCM_MODE, + }}, + {EVP_aead_aes_256_gcm_siv, + { + .name = "aes-256-gcm-siv", + .mode = EVP_CIPH_GCM_MODE, + }}, + {EVP_aead_aes_128_gcm_randnonce, + { + .name = "aes-128-gcm-randnonce", + .mode = EVP_CIPH_GCM_MODE, + }}, + {EVP_aead_aes_256_gcm_randnonce, + { + .name = "aes-256-gcm-randnonce", + .mode = EVP_CIPH_GCM_MODE, + }}, + {EVP_aead_aes_128_ccm_bluetooth, + { + .name = "aes-128-ccm-bluetooth", + .mode = EVP_CIPH_CCM_MODE, + }}, + {EVP_aead_aes_128_ccm_bluetooth_8, + { + .name = "aes-128-ccm-bluetooth-8", + .mode = EVP_CIPH_CCM_MODE, + }}, + {EVP_aead_aes_128_ccm_matter, + { + .name = "aes-128-ccm-matter", + .mode = EVP_CIPH_CCM_MODE, + }}, + {EVP_aead_aes_128_eax, + {.name = "aes-128-eax", + // BoringSSL does not define a mode constant for EAX. Using STREAM + // arbitrarily + .mode = EVP_CIPH_STREAM_CIPHER}}, + {EVP_aead_aes_256_eax, + {.name = "aes-256-eax", + // BoringSSL does not define a mode constant for EAX. Using STREAM + // arbitrarily + .mode = EVP_CIPH_STREAM_CIPHER}}, +}; + +void Aead::ForEach(AeadNameCallback callback) { + for (const auto& [_, info] : aeadIndex) { + callback(info.name); + } +} + +const Aead Aead::EMPTY = Aead(); +const Aead Aead::AES_128_GCM = Aead::FromConstructor(EVP_aead_aes_128_gcm); +const Aead Aead::AES_192_GCM = Aead::FromConstructor(EVP_aead_aes_192_gcm); +const Aead Aead::AES_256_GCM = Aead::FromConstructor(EVP_aead_aes_256_gcm); +const Aead Aead::CHACHA20_POLY1305 = + Aead::FromConstructor(EVP_aead_chacha20_poly1305); +const Aead Aead::XCHACHA20_POLY1305 = + Aead::FromConstructor(EVP_aead_xchacha20_poly1305); +const Aead Aead::AES_128_CTR_HMAC_SHA256 = + Aead::FromConstructor(EVP_aead_aes_128_ctr_hmac_sha256); +const Aead Aead::AES_256_CTR_HMAC_SHA256 = + Aead::FromConstructor(EVP_aead_aes_256_ctr_hmac_sha256); +const Aead Aead::AES_128_GCM_SIV = + Aead::FromConstructor(EVP_aead_aes_128_gcm_siv); +const Aead Aead::AES_256_GCM_SIV = + Aead::FromConstructor(EVP_aead_aes_256_gcm_siv); +const Aead Aead::AES_128_GCM_RANDNONCE = + Aead::FromConstructor(EVP_aead_aes_128_gcm_randnonce); +const Aead Aead::AES_256_GCM_RANDNONCE = + Aead::FromConstructor(EVP_aead_aes_256_gcm_randnonce); +const Aead Aead::AES_128_CCM_BLUETOOTH = + Aead::FromConstructor(EVP_aead_aes_128_ccm_bluetooth); +const Aead Aead::AES_128_CCM_BLUETOOTH_8 = + Aead::FromConstructor(EVP_aead_aes_128_ccm_bluetooth_8); +const Aead Aead::AES_128_CCM_MATTER = + Aead::FromConstructor(EVP_aead_aes_128_ccm_matter); +const Aead Aead::AES_128_EAX = Aead::FromConstructor(EVP_aead_aes_128_eax); +const Aead Aead::AES_256_EAX = Aead::FromConstructor(EVP_aead_aes_256_eax); + +AeadCtxPointer AeadCtxPointer::New(const Aead& aead, + bool encrypt, + const unsigned char* key, + size_t keyLen, + size_t tagLen) { + // Note: In the EVP_AEAD API new always calls init + auto ret = AeadCtxPointer(EVP_AEAD_CTX_new(aead.get(), key, keyLen, tagLen)); + + if (!ret) { + return {}; + } + + return ret; +} + +AeadCtxPointer::AeadCtxPointer(EVP_AEAD_CTX* ctx) : ctx_(ctx) {} + +AeadCtxPointer::AeadCtxPointer(AeadCtxPointer&& other) noexcept + : ctx_(other.release()) {} + +AeadCtxPointer& AeadCtxPointer::operator=(AeadCtxPointer&& other) noexcept { + if (this == &other) return *this; + this->~AeadCtxPointer(); + return *new (this) AeadCtxPointer(std::move(other)); +} + +AeadCtxPointer::~AeadCtxPointer() { + reset(); +} + +void AeadCtxPointer::reset(EVP_AEAD_CTX* ctx) { + ctx_.reset(ctx); +} + +EVP_AEAD_CTX* AeadCtxPointer::release() { + return ctx_.release(); +} + +bool AeadCtxPointer::init(const Aead& aead, + bool encrypt, + const unsigned char* key, + size_t keyLen, + size_t tagLen) { + return EVP_AEAD_CTX_init_with_direction( + ctx_.get(), + aead, + key, + keyLen, + tagLen, + encrypt ? evp_aead_seal : evp_aead_open); +} + +bool AeadCtxPointer::encrypt(const Buffer& in, + Buffer& out, + Buffer& tag, + const Buffer& nonce, + const Buffer& aad) { + if (!ctx_) return false; + return EVP_AEAD_CTX_seal_scatter(ctx_.get(), + out.data, + tag.data, + &tag.len, + tag.len, + nonce.data, + nonce.len, + in.data, + in.len, + nullptr /* extra_in */, + 0 /* extra_in_len */, + aad.data, + aad.len) == 1; +} + +bool AeadCtxPointer::decrypt(const Buffer& in, + Buffer& out, + const Buffer& tag, + const Buffer& nonce, + const Buffer& aad) { + if (!ctx_) return false; + + return EVP_AEAD_CTX_open_gather(ctx_.get(), + out.data, + nonce.data, + nonce.len, + in.data, + in.len, + tag.data, + tag.len, + aad.data, + aad.len) == 1; +} +} // namespace ncrypto +#endif diff --git a/src/ncrypto.cpp b/src/ncrypto.cpp index f482c53..f413e15 100644 --- a/src/ncrypto.cpp +++ b/src/ncrypto.cpp @@ -1589,15 +1589,6 @@ int BIOPointer::Write(BIOPointer* bio, std::string_view message) { // ============================================================================ // DHPointer -namespace { -bool EqualNoCase(const std::string_view a, const std::string_view b) { - if (a.size() != b.size()) return false; - return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { - return std::tolower(a) == std::tolower(b); - }); -} -} // namespace - DHPointer::DHPointer(DH* dh) : dh_(dh) {} DHPointer::DHPointer(DHPointer&& other) noexcept : dh_(other.release()) {} @@ -5014,289 +5005,6 @@ DataPointer KEM::Decapsulate(const EVPKeyPointer& private_key, #endif // OPENSSL_VERSION_MAJOR >= 3 -// ============================================================================ -// AEAD (Authenticated Encryption with Associated Data) -#ifdef OPENSSL_IS_BORINGSSL - -const Aead Aead::FromName(std::string_view name) { - for (const auto& [construct, info] : aeadIndex) { - if (EqualNoCase(info.name, name)) { - return Aead(&info, construct()); - } - } - - return Aead(); -} - -const Aead Aead::FromCtx(std::string_view name, const AeadCtxPointer& ctx) { - for (const auto& [_, info] : aeadIndex) { - if (info.name == name) { - return Aead(&info, EVP_AEAD_CTX_aead(ctx.get())); - } - } - - return Aead(); -} - -int Aead::getMode() const { - if (!aead_) return -1; - - return info_->mode; -} - -int Aead::getNonceLength() const { - if (!aead_) return 0; - return EVP_AEAD_nonce_length(aead_); -} - -int Aead::getKeyLength() const { - if (!aead_) return 0; - return EVP_AEAD_key_length(aead_); -} - -int Aead::getMaxOverhead() const { - if (!aead_) return 0; - return EVP_AEAD_max_overhead(aead_); -} - -int Aead::getMaxTagLength() const { - if (!aead_) return 0; - return EVP_AEAD_max_tag_len(aead_); -} - -int Aead::getBlockSize() const { - if (!aead_) return 0; - - // EVP_CIPHER_CTX_block_size returns the block size, in bytes, of the cipher - // underlying |ctx|, or one if the cipher is a stream cipher. - return 1; -} - -std::string_view Aead::getName() const { - if (!aead_) return ""; - - return info_->name; -} - -int Aead::getNid() const { - if (!aead_) return 0; - - return info_->nid; -} - -const Aead Aead::FromConstructor(Aead::AeadConstructor construct) { - return Aead(&aeadIndex.at(construct), construct()); -} - -const std::unordered_map - Aead::aeadIndex = { - {EVP_aead_aes_128_gcm, - {.name = LN_aes_128_gcm, - .mode = EVP_CIPH_GCM_MODE, - .nid = NID_aes_128_gcm}}, - {EVP_aead_aes_192_gcm, - {.name = LN_aes_192_gcm, - .mode = EVP_CIPH_GCM_MODE, - .nid = NID_aes_192_gcm}}, - {EVP_aead_aes_256_gcm, - {.name = LN_aes_256_gcm, - .mode = EVP_CIPH_GCM_MODE, - .nid = NID_aes_256_gcm}}, - {EVP_aead_chacha20_poly1305, - {.name = LN_chacha20_poly1305, - .mode = EVP_CIPH_STREAM_CIPHER, - .nid = NID_chacha20_poly1305}}, - {EVP_aead_xchacha20_poly1305, - { - .name = "xchacha20-poly1305", - .mode = EVP_CIPH_STREAM_CIPHER, - }}, - {EVP_aead_aes_128_ctr_hmac_sha256, - { - .name = "aes-128-ctr-hmac-sha256", - .mode = EVP_CIPH_CTR_MODE, - }}, - {EVP_aead_aes_256_ctr_hmac_sha256, - { - .name = "aes-256-ctr-hmac-sha256", - .mode = EVP_CIPH_CTR_MODE, - }}, - {EVP_aead_aes_128_gcm_siv, - { - .name = "aes-128-gcm-siv", - .mode = EVP_CIPH_GCM_MODE, - }}, - {EVP_aead_aes_256_gcm_siv, - { - .name = "aes-256-gcm-siv", - .mode = EVP_CIPH_GCM_MODE, - }}, - {EVP_aead_aes_128_gcm_randnonce, - { - .name = "aes-128-gcm-randnonce", - .mode = EVP_CIPH_GCM_MODE, - }}, - {EVP_aead_aes_256_gcm_randnonce, - { - .name = "aes-256-gcm-randnonce", - .mode = EVP_CIPH_GCM_MODE, - }}, - {EVP_aead_aes_128_ccm_bluetooth, - { - .name = "aes-128-ccm-bluetooth", - .mode = EVP_CIPH_CCM_MODE, - }}, - {EVP_aead_aes_128_ccm_bluetooth_8, - { - .name = "aes-128-ccm-bluetooth-8", - .mode = EVP_CIPH_CCM_MODE, - }}, - {EVP_aead_aes_128_ccm_matter, - { - .name = "aes-128-ccm-matter", - .mode = EVP_CIPH_CCM_MODE, - }}, - {EVP_aead_aes_128_eax, - {.name = "aes-128-eax", - // BoringSSL does not define a mode constant for EAX. Using STREAM - // arbitrarily - .mode = EVP_CIPH_STREAM_CIPHER}}, - {EVP_aead_aes_256_eax, - {.name = "aes-256-eax", - // BoringSSL does not define a mode constant for EAX. Using STREAM - // arbitrarily - .mode = EVP_CIPH_STREAM_CIPHER}}, - }; - -void Aead::ForEach(AeadNameCallback callback) { - for (const auto& [_, info] : aeadIndex) { - callback(info.name); - } -} - -const Aead Aead::EMPTY = Aead(); -const Aead Aead::AES_128_GCM = Aead::FromConstructor(EVP_aead_aes_128_gcm); -const Aead Aead::AES_192_GCM = Aead::FromConstructor(EVP_aead_aes_192_gcm); -const Aead Aead::AES_256_GCM = Aead::FromConstructor(EVP_aead_aes_256_gcm); -const Aead Aead::CHACHA20_POLY1305 = - Aead::FromConstructor(EVP_aead_chacha20_poly1305); -const Aead Aead::XCHACHA20_POLY1305 = - Aead::FromConstructor(EVP_aead_xchacha20_poly1305); -const Aead Aead::AES_128_CTR_HMAC_SHA256 = - Aead::FromConstructor(EVP_aead_aes_128_ctr_hmac_sha256); -const Aead Aead::AES_256_CTR_HMAC_SHA256 = - Aead::FromConstructor(EVP_aead_aes_256_ctr_hmac_sha256); -const Aead Aead::AES_128_GCM_SIV = - Aead::FromConstructor(EVP_aead_aes_128_gcm_siv); -const Aead Aead::AES_256_GCM_SIV = - Aead::FromConstructor(EVP_aead_aes_256_gcm_siv); -const Aead Aead::AES_128_GCM_RANDNONCE = - Aead::FromConstructor(EVP_aead_aes_128_gcm_randnonce); -const Aead Aead::AES_256_GCM_RANDNONCE = - Aead::FromConstructor(EVP_aead_aes_256_gcm_randnonce); -const Aead Aead::AES_128_CCM_BLUETOOTH = - Aead::FromConstructor(EVP_aead_aes_128_ccm_bluetooth); -const Aead Aead::AES_128_CCM_BLUETOOTH_8 = - Aead::FromConstructor(EVP_aead_aes_128_ccm_bluetooth_8); -const Aead Aead::AES_128_CCM_MATTER = - Aead::FromConstructor(EVP_aead_aes_128_ccm_matter); -const Aead Aead::AES_128_EAX = Aead::FromConstructor(EVP_aead_aes_128_eax); -const Aead Aead::AES_256_EAX = Aead::FromConstructor(EVP_aead_aes_256_eax); - -template class ModeMixin; - -AeadCtxPointer AeadCtxPointer::New(const Aead& aead, - bool encrypt, - const unsigned char* key, - size_t keyLen, - size_t tagLen) { - // Note: In the EVP_AEAD API new always calls init - auto ret = AeadCtxPointer(EVP_AEAD_CTX_new(aead.get(), key, keyLen, tagLen)); - - if (!ret) { - return {}; - } - - return ret; -} - -AeadCtxPointer::AeadCtxPointer(EVP_AEAD_CTX* ctx) : ctx_(ctx) {} - -AeadCtxPointer::AeadCtxPointer(AeadCtxPointer&& other) noexcept - : ctx_(other.release()) {} - -AeadCtxPointer& AeadCtxPointer::operator=(AeadCtxPointer&& other) noexcept { - if (this == &other) return *this; - this->~AeadCtxPointer(); - return *new (this) AeadCtxPointer(std::move(other)); -} - -AeadCtxPointer::~AeadCtxPointer() { - reset(); -} - -void AeadCtxPointer::reset(EVP_AEAD_CTX* ctx) { - ctx_.reset(ctx); -} - -EVP_AEAD_CTX* AeadCtxPointer::release() { - return ctx_.release(); -} - -bool AeadCtxPointer::init(const Aead& aead, - bool encrypt, - const unsigned char* key, - size_t keyLen, - size_t tagLen) { - return EVP_AEAD_CTX_init_with_direction( - ctx_.get(), - aead, - key, - keyLen, - tagLen, - encrypt ? evp_aead_seal : evp_aead_open); -} - -bool AeadCtxPointer::encrypt(const Buffer& in, - Buffer& out, - Buffer& tag, - const Buffer& nonce, - const Buffer& aad) { - if (!ctx_) return false; - return EVP_AEAD_CTX_seal_scatter(ctx_.get(), - out.data, - tag.data, - &tag.len, - tag.len, - nonce.data, - nonce.len, - in.data, - in.len, - nullptr /* extra_in */, - 0 /* extra_in_len */, - aad.data, - aad.len) == 1; -} - -bool AeadCtxPointer::decrypt(const Buffer& in, - Buffer& out, - const Buffer& tag, - const Buffer& nonce, - const Buffer& aad) { - if (!ctx_) return false; - - return EVP_AEAD_CTX_open_gather(ctx_.get(), - out.data, - nonce.data, - nonce.len, - in.data, - in.len, - tag.data, - tag.len, - aad.data, - aad.len) == 1; -} -#endif } // namespace ncrypto // =========================================================================== diff --git a/tests/basic.cpp b/tests/basic.cpp index 05744cd..d8c7f11 100644 --- a/tests/basic.cpp +++ b/tests/basic.cpp @@ -1,3 +1,4 @@ +#include #include #include