Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
src: move more crypto impl details into ncrypto
  • Loading branch information
jasnell committed Mar 10, 2025
commit e2064b4cc05296c18acaa66e1dfecf063c80a0e0
82 changes: 65 additions & 17 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1669,17 +1669,17 @@ const EVP_CIPHER* getCipherByName(const std::string_view name) {
return EVP_get_cipherbyname(name.data());
}

bool checkHkdfLength(const EVP_MD* md, size_t length) {
bool checkHkdfLength(const Digest& md, size_t length) {
// HKDF-Expand computes up to 255 HMAC blocks, each having as many bits as
// the output of the hash function. 255 is a hard limit because HKDF appends
// an 8-bit counter to each HMAC'd message, starting at 1.
static constexpr size_t kMaxDigestMultiplier = 255;
size_t max_length = EVP_MD_size(md) * kMaxDigestMultiplier;
size_t max_length = md.size() * kMaxDigestMultiplier;
if (length > max_length) return false;
return true;
}

DataPointer hkdf(const EVP_MD* md,
DataPointer hkdf(const Digest& md,
const Buffer<const unsigned char>& key,
const Buffer<const unsigned char>& info,
const Buffer<const unsigned char>& salt,
Expand All @@ -1703,7 +1703,7 @@ DataPointer hkdf(const EVP_MD* md,
if (salt.len > 0) {
actual_salt = {reinterpret_cast<const char*>(salt.data), salt.len};
} else {
actual_salt = {default_salt, static_cast<unsigned>(EVP_MD_size(md))};
actual_salt = {default_salt, static_cast<unsigned>(md.size())};
}

// We do not use EVP_PKEY_HKDF_MODE_EXTRACT_AND_EXPAND because and instead
Expand Down Expand Up @@ -2786,6 +2786,11 @@ bool Cipher::isStreamMode() const {
return getMode() == EVP_CIPH_STREAM_CIPHER;
}

bool Cipher::isChaCha20Poly1305() const {
if (!cipher_) return false;
return getNid() == NID_chacha20_poly1305;
}

int Cipher::getMode() const {
if (!cipher_) return 0;
return EVP_CIPHER_mode(cipher_);
Expand Down Expand Up @@ -2862,6 +2867,14 @@ bool Cipher::isSupportedAuthenticatedMode() const {
}
}

int Cipher::bytesToKey(const Digest& digest,
const Buffer<const unsigned char>& input,
unsigned char* key,
unsigned char* iv) const {
return EVP_BytesToKey(
*this, Digest::MD5, nullptr, input.data, input.len, 1, key, iv);
}

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

CipherCtxPointer CipherCtxPointer::New() {
Expand Down Expand Up @@ -2938,6 +2951,26 @@ int CipherCtxPointer::getMode() const {
return EVP_CIPHER_CTX_mode(ctx_.get());
}

bool CipherCtxPointer::isGcmMode() const {
if (!ctx_) return false;
return getMode() == EVP_CIPH_GCM_MODE;
}

bool CipherCtxPointer::isCcmMode() const {
if (!ctx_) return false;
return getMode() == EVP_CIPH_CCM_MODE;
}

bool CipherCtxPointer::isWrapMode() const {
if (!ctx_) return false;
return getMode() == EVP_CIPH_WRAP_MODE;
}

bool CipherCtxPointer::isChaCha20Poly1305() const {
if (!ctx_) return false;
return getNid() == NID_chacha20_poly1305;
}

int CipherCtxPointer::getNid() const {
if (!ctx_) return 0;
return EVP_CIPHER_CTX_nid(ctx_.get());
Expand Down Expand Up @@ -3720,9 +3753,7 @@ DataPointer Cipher::recover(const EVPKeyPointer& key,
namespace {
struct CipherCallbackContext {
Cipher::CipherNameCallback cb;
void operator()(std::string_view name) {
cb(name);
}
void operator()(std::string_view name) { cb(name); }
};

#if OPENSSL_VERSION_MAJOR >= 3
Expand Down Expand Up @@ -3759,9 +3790,9 @@ void array_push_back(const TypeName* evp_ref,
#else
template <class TypeName>
void array_push_back(const TypeName* evp_ref,
const char* from,
const char* to,
void* arg) {
const char* from,
const char* to,
void* arg) {
if (!from) return;
auto& cb = *(static_cast<CipherCallbackContext*>(arg));
cb(from);
Expand All @@ -3776,15 +3807,15 @@ void Cipher::ForEach(Cipher::CipherNameCallback callback) {

EVP_CIPHER_do_all_sorted(
#if OPENSSL_VERSION_MAJOR >= 3
array_push_back<EVP_CIPHER,
EVP_CIPHER_fetch,
EVP_CIPHER_free,
EVP_get_cipherbyname,
EVP_CIPHER_get0_name>,
array_push_back<EVP_CIPHER,
EVP_CIPHER_fetch,
EVP_CIPHER_free,
EVP_get_cipherbyname,
EVP_CIPHER_get0_name>,
#else
array_push_back<EVP_CIPHER>,
array_push_back<EVP_CIPHER>,
#endif
&context);
&context);
}

// ============================================================================
Expand Down Expand Up @@ -4143,4 +4174,21 @@ size_t Dsa::getDivisorLength() const {
return BignumPointer::GetBitCount(getQ());
}

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

size_t Digest::size() const {
if (md_ == nullptr) return 0;
return EVP_MD_size(md_);
}

const Digest Digest::MD5 = Digest(EVP_md5());
const Digest Digest::SHA1 = Digest(EVP_sha1());
const Digest Digest::SHA256 = Digest(EVP_sha256());
const Digest Digest::SHA384 = Digest(EVP_sha384());
const Digest Digest::SHA512 = Digest(EVP_sha512());

const Digest Digest::FromName(std::string_view name) {
return ncrypto::getDigestByName(name);
}

} // namespace ncrypto
48 changes: 46 additions & 2 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,44 @@ struct Buffer {
size_t len = 0;
};

class Digest final {
public:
Digest() = default;
Digest(const EVP_MD* md) : md_(md) {}
Digest(const Digest&) = default;
Digest& operator=(const Digest&) = default;
inline Digest& operator=(const EVP_MD* md) {
md_ = md;
return *this;
}
NCRYPTO_DISALLOW_MOVE(Digest)

size_t size() const;

inline const EVP_MD* get() const { return md_; }
inline operator const EVP_MD*() const { return md_; }
inline operator bool() const { return md_ != nullptr; }

static const Digest MD5;
static const Digest SHA1;
static const Digest SHA256;
static const Digest SHA384;
static const Digest SHA512;

static const Digest FromName(std::string_view name);

private:
const EVP_MD* md_ = nullptr;
};

DataPointer hashDigest(const Buffer<const unsigned char>& data,
const EVP_MD* md);

class Cipher final {
public:
static constexpr size_t MAX_KEY_LENGTH = EVP_MAX_KEY_LENGTH;
static constexpr size_t MAX_IV_LENGTH = EVP_MAX_IV_LENGTH;

Cipher() = default;
Cipher(const EVP_CIPHER* cipher) : cipher_(cipher) {}
Cipher(const Cipher&) = default;
Expand Down Expand Up @@ -280,9 +313,15 @@ class Cipher final {
bool isCcmMode() const;
bool isOcbMode() const;
bool isStreamMode() const;
bool isChaCha20Poly1305() const;

bool isSupportedAuthenticatedMode() const;

int bytesToKey(const Digest& digest,
const Buffer<const unsigned char>& input,
unsigned char* key,
unsigned char* iv) const;

static const Cipher FromName(std::string_view name);
static const Cipher FromNid(int nid);
static const Cipher FromCtx(const CipherCtxPointer& ctx);
Expand Down Expand Up @@ -644,6 +683,11 @@ class CipherCtxPointer final {
int getMode() const;
int getNid() const;

bool isGcmMode() const;
bool isCcmMode() const;
bool isWrapMode() const;
bool isChaCha20Poly1305() const;

bool update(const Buffer<const unsigned char>& in,
unsigned char* out,
int* out_len,
Expand Down Expand Up @@ -1420,13 +1464,13 @@ const EVP_CIPHER* getCipherByName(const std::string_view name);
// Verify that the specified HKDF output length is valid for the given digest.
// The maximum length for HKDF output for a given digest is 255 times the
// hash size for the given digest algorithm.
bool checkHkdfLength(const EVP_MD* md, size_t length);
bool checkHkdfLength(const Digest& digest, size_t length);

bool extractP1363(const Buffer<const unsigned char>& buf,
unsigned char* dest,
size_t n);

DataPointer hkdf(const EVP_MD* md,
DataPointer hkdf(const Digest& md,
const Buffer<const unsigned char>& key,
const Buffer<const unsigned char>& info,
const Buffer<const unsigned char>& salt,
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/crypto_aes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ Maybe<void> AESCipherTraits::AdditionalConfig(
return Nothing<void>();
}

if (params->cipher.isWrapMode()) {
if (!params->cipher.isWrapMode()) {
if (!ValidateIV(env, mode, args[offset + 1], params)) {
return Nothing<void>();
}
Expand Down
Loading