Skip to content

Commit 168603a

Browse files
jasnellclaude
authored andcommitted
src: refine ncrypto more
An eventual goal for ncrypto is to completely abstract away details of working directly with openssl in order to make it easier to work with multiple different openssl/boringssl versions. As part of that we want to move away from direct reliance on specific openssl APIs in the runtime and instead go through the ncrypto abstractions. Not only does this help other runtimes trying to be compatible with Node.js, but it helps Node.js also by reducing the complexity of the crypto code in Node.js itself. PR-URL: nodejs/node#57300 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Note: Merge conflicts were resolved by Claude Code. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 6f427b2 commit 168603a

File tree

2 files changed

+309
-45
lines changed

2 files changed

+309
-45
lines changed

include/ncrypto.h

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,45 @@ struct Buffer {
253253
size_t len = 0;
254254
};
255255

256+
class Digest final {
257+
public:
258+
static constexpr size_t MAX_SIZE = EVP_MAX_MD_SIZE;
259+
Digest() = default;
260+
Digest(const EVP_MD* md) : md_(md) {}
261+
Digest(const Digest&) = default;
262+
Digest& operator=(const Digest&) = default;
263+
inline Digest& operator=(const EVP_MD* md) {
264+
md_ = md;
265+
return *this;
266+
}
267+
NCRYPTO_DISALLOW_MOVE(Digest)
268+
269+
size_t size() const;
270+
271+
inline const EVP_MD* get() const { return md_; }
272+
inline operator const EVP_MD*() const { return md_; }
273+
inline operator bool() const { return md_ != nullptr; }
274+
275+
static const Digest MD5;
276+
static const Digest SHA1;
277+
static const Digest SHA256;
278+
static const Digest SHA384;
279+
static const Digest SHA512;
280+
281+
static const Digest FromName(std::string_view name);
282+
283+
private:
284+
const EVP_MD* md_ = nullptr;
285+
};
286+
256287
DataPointer hashDigest(const Buffer<const unsigned char>& data,
257288
const EVP_MD* md);
258289

259290
class Cipher final {
260291
public:
292+
static constexpr size_t MAX_KEY_LENGTH = EVP_MAX_KEY_LENGTH;
293+
static constexpr size_t MAX_IV_LENGTH = EVP_MAX_IV_LENGTH;
294+
261295
Cipher() = default;
262296
Cipher(const EVP_CIPHER* cipher) : cipher_(cipher) {}
263297
Cipher(const Cipher&) = default;
@@ -280,15 +314,53 @@ class Cipher final {
280314
std::string_view getModeLabel() const;
281315
std::string_view getName() const;
282316

317+
bool isGcmMode() const;
318+
bool isWrapMode() const;
319+
bool isCtrMode() const;
320+
bool isCcmMode() const;
321+
bool isOcbMode() const;
322+
bool isStreamMode() const;
323+
bool isChaCha20Poly1305() const;
324+
283325
bool isSupportedAuthenticatedMode() const;
284326

327+
int bytesToKey(const Digest& digest,
328+
const Buffer<const unsigned char>& input,
329+
unsigned char* key,
330+
unsigned char* iv) const;
331+
285332
static const Cipher FromName(std::string_view name);
286333
static const Cipher FromNid(int nid);
287334
static const Cipher FromCtx(const CipherCtxPointer& ctx);
288335

336+
using CipherNameCallback = std::function<void(std::string_view name)>;
337+
338+
// Iterates the known ciphers if the underlying implementation
339+
// is able to do so.
340+
static void ForEach(CipherNameCallback callback);
341+
342+
// Utilities to get various ciphers by type. If the underlying
343+
// implementation does not support the requested cipher, then
344+
// the result will be an empty Cipher object whose bool operator
345+
// will return false.
346+
347+
static const Cipher EMPTY;
348+
static const Cipher AES_128_CBC;
349+
static const Cipher AES_192_CBC;
350+
static const Cipher AES_256_CBC;
351+
static const Cipher AES_128_CTR;
352+
static const Cipher AES_192_CTR;
353+
static const Cipher AES_256_CTR;
354+
static const Cipher AES_128_GCM;
355+
static const Cipher AES_192_GCM;
356+
static const Cipher AES_256_GCM;
357+
static const Cipher AES_128_KW;
358+
static const Cipher AES_192_KW;
359+
static const Cipher AES_256_KW;
360+
289361
struct CipherParams {
290362
int padding;
291-
const EVP_MD* digest;
363+
Digest digest;
292364
const Buffer<const void> label;
293365
};
294366

@@ -612,7 +684,8 @@ class CipherCtxPointer final {
612684
void reset(EVP_CIPHER_CTX* ctx = nullptr);
613685
EVP_CIPHER_CTX* release();
614686

615-
void setFlags(int flags);
687+
void setAllowWrap();
688+
616689
bool setKeyLength(size_t length);
617690
bool setIvLength(size_t length);
618691
bool setAeadTag(const Buffer<const char>& tag);
@@ -627,6 +700,11 @@ class CipherCtxPointer final {
627700
int getMode() const;
628701
int getNid() const;
629702

703+
bool isGcmMode() const;
704+
bool isCcmMode() const;
705+
bool isWrapMode() const;
706+
bool isChaCha20Poly1305() const;
707+
630708
bool update(const Buffer<const unsigned char>& in,
631709
unsigned char* out,
632710
int* out_len,
@@ -662,13 +740,13 @@ class EVPKeyCtxPointer final {
662740
bool setDsaParameters(uint32_t bits, std::optional<int> q_bits);
663741
bool setEcParameters(int curve, int encoding);
664742

665-
bool setRsaOaepMd(const EVP_MD* md);
666-
bool setRsaMgf1Md(const EVP_MD* md);
743+
bool setRsaOaepMd(const Digest& md);
744+
bool setRsaMgf1Md(const Digest& md);
667745
bool setRsaPadding(int padding);
668746
bool setRsaKeygenPubExp(BignumPointer&& e);
669747
bool setRsaKeygenBits(int bits);
670-
bool setRsaPssKeygenMd(const EVP_MD* md);
671-
bool setRsaPssKeygenMgf1Md(const EVP_MD* md);
748+
bool setRsaPssKeygenMd(const Digest& md);
749+
bool setRsaPssKeygenMgf1Md(const Digest& md);
672750
bool setRsaPssSaltlen(int salt_len);
673751
bool setRsaImplicitRejection();
674752
bool setRsaOaepLabel(DataPointer&& data);
@@ -945,6 +1023,8 @@ class SSLCtxPointer final {
9451023
SSL_CTX_set_tlsext_status_arg(get(), nullptr);
9461024
}
9471025

1026+
bool setCipherSuites(std::string_view ciphers);
1027+
9481028
static SSLCtxPointer NewServer();
9491029
static SSLCtxPointer NewClient();
9501030
static SSLCtxPointer New(const SSL_METHOD* method = TLS_method());
@@ -1073,7 +1153,7 @@ class X509View final {
10731153
bool checkPrivateKey(const EVPKeyPointer& pkey) const;
10741154
bool checkPublicKey(const EVPKeyPointer& pkey) const;
10751155

1076-
std::optional<std::string> getFingerprint(const EVP_MD* method) const;
1156+
std::optional<std::string> getFingerprint(const Digest& method) const;
10771157

10781158
X509Pointer clone() const;
10791159

@@ -1269,16 +1349,16 @@ class EVPMDCtxPointer final {
12691349
void reset(EVP_MD_CTX* ctx = nullptr);
12701350
EVP_MD_CTX* release();
12711351

1272-
bool digestInit(const EVP_MD* digest);
1352+
bool digestInit(const Digest& digest);
12731353
bool digestUpdate(const Buffer<const void>& in);
12741354
DataPointer digestFinal(size_t length);
12751355
bool digestFinalInto(Buffer<void>* buf);
12761356
size_t getExpectedSize();
12771357

12781358
std::optional<EVP_PKEY_CTX*> signInit(const EVPKeyPointer& key,
1279-
const EVP_MD* digest);
1359+
const Digest& digest);
12801360
std::optional<EVP_PKEY_CTX*> verifyInit(const EVPKeyPointer& key,
1281-
const EVP_MD* digest);
1361+
const Digest& digest);
12821362

12831363
DataPointer signOneShot(const Buffer<const unsigned char>& buf) const;
12841364
DataPointer sign(const Buffer<const unsigned char>& buf) const;
@@ -1313,7 +1393,7 @@ class HMACCtxPointer final {
13131393
void reset(HMAC_CTX* ctx = nullptr);
13141394
HMAC_CTX* release();
13151395

1316-
bool init(const Buffer<const void>& buf, const EVP_MD* md);
1396+
bool init(const Buffer<const void>& buf, const Digest& md);
13171397
bool update(const Buffer<const void>& buf);
13181398
DataPointer digest();
13191399
bool digestInto(Buffer<void>* buf);
@@ -1414,20 +1494,20 @@ const EVP_CIPHER* getCipherByName(const std::string_view name);
14141494
// Verify that the specified HKDF output length is valid for the given digest.
14151495
// The maximum length for HKDF output for a given digest is 255 times the
14161496
// hash size for the given digest algorithm.
1417-
bool checkHkdfLength(const EVP_MD* md, size_t length);
1497+
bool checkHkdfLength(const Digest& digest, size_t length);
14181498

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

1423-
bool hkdfInfo(const EVP_MD* md,
1503+
bool hkdfInfo(const Digest& md,
14241504
const Buffer<const unsigned char>& key,
14251505
const Buffer<const unsigned char>& info,
14261506
const Buffer<const unsigned char>& salt,
14271507
size_t length,
14281508
Buffer<unsigned char>* out);
14291509

1430-
DataPointer hkdf(const EVP_MD* md,
1510+
DataPointer hkdf(const Digest& md,
14311511
const Buffer<const unsigned char>& key,
14321512
const Buffer<const unsigned char>& info,
14331513
const Buffer<const unsigned char>& salt,
@@ -1452,14 +1532,14 @@ DataPointer scrypt(const Buffer<const char>& pass,
14521532
uint64_t maxmem,
14531533
size_t length);
14541534

1455-
bool pbkdf2Into(const EVP_MD* md,
1535+
bool pbkdf2Into(const Digest& md,
14561536
const Buffer<const char>& pass,
14571537
const Buffer<const unsigned char>& salt,
14581538
uint32_t iterations,
14591539
size_t length,
14601540
Buffer<unsigned char>* out);
14611541

1462-
DataPointer pbkdf2(const EVP_MD* md,
1542+
DataPointer pbkdf2(const Digest& md,
14631543
const Buffer<const char>& pass,
14641544
const Buffer<const unsigned char>& salt,
14651545
uint32_t iterations,

0 commit comments

Comments
 (0)