1# Node.js `src/crypto` documentation 2 3Welcome. You've found your way to the Node.js native crypto subsystem. 4 5Do not be afraid. 6 7While crypto may be a dark, mysterious, and forboding subject; and while 8this directory may be filled with many `*.h` and `*.cc` files, finding 9your way around is not too difficult. And I can promise you that a Gru 10will not jump out of the shadows and eat you (well, "promise" may be a 11bit too strong, a Gru may jump out of the shadows and eat you if you 12live in a place where such things are possible). 13 14## Finding your way around 15 16All of the code in this directory is structured into units organized by 17function or crypto protocol. 18 19The following provide generalized utility declarations that are used throughout 20the various other crypto files and other parts of Node.js: 21 22* `crypto_util.h` / `crypto_util.cc` (Core crypto definitions) 23* `crypto_common.h` / `crypto_common.cc` (Shared TLS utility functions) 24* `crypto_bio.h` / `crypto_bio.cc` (Custom OpenSSL i/o implementation) 25 26Of these, `crypto_util.h` and `crypto_util.cc` are the most important, as 27they provide the core declarations and utility functions used most extensively 28throughout the rest of the code. 29 30The rest of the files are structured by their function, as detailed in the 31following table: 32 33| File (\*.h/\*.cc) | Description | 34| -------------------- | -------------------------------------------------------------------------- | 35| `crypto_aes` | AES Cipher support. | 36| `crypto_cipher` | General Encryption/Decryption utilities. | 37| `crypto_clienthello` | TLS/SSL client hello parser implementation. Used during SSL/TLS handshake. | 38| `crypto_context` | Implementation of the `SecureContext` object. | 39| `crypto_dh` | Diffie-Hellman Key Agreement implementation. | 40| `crypto_dsa` | DSA (Digital Signature) Key Generation functions. | 41| `crypto_ec` | Elliptic-curve cryptography implementation. | 42| `crypto_hash` | Basic hash (e.g. SHA-256) functions. | 43| `crypto_hkdf` | HKDF (Key derivation) implementation. | 44| `crypto_hmac` | HMAC implementations. | 45| `crypto_keys` | Utilities for using and generating secret, private, and public keys. | 46| `crypto_pbkdf2` | PBKDF2 key / bit generation implementation. | 47| `crypto_rsa` | RSA Key Generation functions. | 48| `crypto_scrypt` | Scrypt key / bit generation implementation. | 49| `crypto_sig` | General digital signature and verification utilities. | 50| `crypto_spkac` | Netscape SPKAC certificate utilities. | 51| `crypto_ssl` | Implementation of the `SSLWrap` object. | 52| `crypto_timing` | Implementation of the TimingSafeEqual. | 53 54When new crypto protocols are added, they will be added into their own 55`crypto_` `*.h` and `*.cc` files. 56 57## Helpful concepts 58 59Node.js currently uses OpenSSL to provide it's crypto substructure. 60(Some custom Node.js distributions -- such as Electron -- use BoringSSL 61instead.) 62 63This section aims to explain some of the utilities that have been 64provided to make working with the OpenSSL APIs a bit easier. 65 66### Pointer types 67 68Most of the key OpenSSL types need to be explicitly freed when they are 69no longer needed. Failure to do so introduces memory leaks. To make this 70easier (and less error prone), the `crypto_util.h` defines a number of 71smart-pointer aliases that should be used: 72 73```cpp 74using X509Pointer = DeleteFnPtr<X509, X509_free>; 75using BIOPointer = DeleteFnPtr<BIO, BIO_free_all>; 76using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>; 77using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>; 78using SSLPointer = DeleteFnPtr<SSL, SSL_free>; 79using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>; 80using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>; 81using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>; 82using EVPMDPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>; 83using RSAPointer = DeleteFnPtr<RSA, RSA_free>; 84using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>; 85using BignumPointer = DeleteFnPtr<BIGNUM, BN_free>; 86using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>; 87using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>; 88using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>; 89using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>; 90using DHPointer = DeleteFnPtr<DH, DH_free>; 91using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>; 92using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>; 93using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>; 94``` 95 96Examples of these being used are pervasive through the `src/crypto` code. 97 98### `ByteSource` 99 100The `ByteSource` class is a helper utility representing a _read-only_ byte 101array. Instances can either wrap external ("foreign") data sources, such as 102an `ArrayBuffer` (`v8::BackingStore`), or allocated data. 103 104* If a pointer to external data is used to create a `ByteSource`, that pointer 105 must remain valid until the `ByteSource` is destroyed. 106* If allocated data is used, then it must have been allocated using OpenSSL's 107 allocator. It will be freed automatically when the `ByteSource` is destroyed. 108 109The `ByteSource::Builder` class can be used to allocate writable memory that can 110then be released as a `ByteSource`, making it read-only, or freed by destroying 111the `ByteSource::Builder` without releasing it as a `ByteSource`. 112 113### `ArrayBufferOrViewContents` 114 115The `ArrayBufferOrViewContents` class is a helper utility that abstracts 116`ArrayBuffer`, `TypedArray`, or `DataView` inputs and provides access to 117their underlying data pointers. It is used extensively through `src/crypto` 118to make it easier to deal with inputs that allow any `ArrayBuffer`-backed 119object. 120 121The lifetime of `ArrayBufferOrViewContents` should not exceed the 122lifetime of its input. 123 124### Key objects 125 126Most crypto operations involve the use of keys -- cryptographic inputs 127that protect data. There are three general types of keys: 128 129* Secret Keys (Symmetric) 130* Public Keys (Asymmetric) 131* Private Keys (Asymmetric) 132 133Secret keys consist of a variable number of bytes. They are "symmetrical" 134in that the same key used to encrypt data, or generate a signature, must 135be used to decrypt or validate that signature. If two people are exchanging 136messages encrypted using a secret key, both of them must have access to the 137same secret key data. 138 139Public and Private keys always come in pairs. When one is used to encrypt 140data or generate a signature, the other is used to decrypt or validate the 141signature. The Public key is intended to be shared and can be shared openly. 142The Private key must be kept secret and known only to the owner of the key. 143 144The `src/crypto` subsystem uses several objects to represent keys. These 145objects are structured in a way to allow key data to be shared across 146multiple threads (the Node.js main thread, Worker Threads, and the libuv 147threadpool). 148 149Refer to `crypto_keys.h` and `crypto_keys.cc` for all code relating to the 150core key objects. 151 152#### `ManagedEVPPKey` 153 154The `ManagedEVPPKey` class is a smart pointer for OpenSSL `EVP_PKEY` 155structures. These manage the lifecycle of Public and Private key pairs. 156 157#### `KeyObjectData` 158 159`KeyObjectData` is an internal thread-safe structure used to wrap either 160a `ManagedEVPPKey` (for Public or Private keys) or a `ByteSource` containing 161a Secret key. 162 163#### `KeyObjectHandle` 164 165The `KeyObjectHandle` provides the interface between the native C++ code 166handling keys and the public JavaScript `KeyObject` API. 167 168#### `KeyObject` 169 170A `KeyObject` is the public Node.js-specific API for keys. A single 171`KeyObject` wraps exactly one `KeyObjectHandle`. 172 173#### `CryptoKey` 174 175A `CryptoKey` is the Web Crypto API's alternative to `KeyObject`. In the 176Node.js implementation, `CryptoKey` is a thin wrapper around the 177`KeyObject` and it is largely possible to use them interchangeably. 178 179### `CryptoJob` 180 181All operations that are not either Stream-based or single-use functions 182are built around the `CryptoJob` class. 183 184A `CryptoJob` encapsulates a single crypto operation that can be 185invoked synchronously or asynchronously. 186 187The `CryptoJob` class itself is a C++ template that takes a single 188`CryptoJobTraits` struct as a parameter. The `CryptoJobTraits` 189provides the implementation detail of the job. 190 191There are (currently) four basic `CryptoJob` specializations: 192 193* `CipherJob` (defined in `src/crypto_cipher.h`) -- Used for 194 encrypt and decrypt operations. 195* `KeyGenJob` (defined in `src/crypto_keygen.h`) -- Used for 196 secret and key pair generation operations. 197* `KeyExportJob` (defined in `src/crypto_keys.h`) -- Used for 198 key export operations. 199* `DeriveBitsJob` (defined in `src/crypto_util.h`) -- Used for 200 key and byte derivation operations. 201 202Every `CryptoJobTraits` provides two fundamental operations: 203 204* Configuration -- Processes input arguments when a 205 `CryptoJob` instance is created. 206* Implementation -- Provides the specific implementation of 207 the operation. 208 209The Configuration is typically provided by an `AdditionalConfig()` 210method, the signature of which is slightly different for each 211of the above `CryptoJob` specializations. Despite the signature 212differences, the purpose of the `AdditionalConfig()` function 213remains the same: to process input arguments and set the properties 214on the `CryptoJob`'s parameters object. 215 216The parameters object is specific to each `CryptoJob` type, and 217is stored with the `CryptoJob`. It holds all of the inputs that 218are used by the Implementation. The inputs held by the parameters 219must be threadsafe. 220 221The `AdditionalConfig()` function is always called when the 222`CryptoJob` instance is being created. 223 224The Implementation function is unique to each of the `CryptoJob` 225specializations and will either be called synchronously within 226the current thread or from within the libuv threadpool. 227 228Every `CryptoJob` instance exposes a `run()` function to the 229JavaScript layer. When called, `run()` with either dispatch the 230job to the libuv threadpool or invoke the Implementation 231function synchronously. If invoked synchronously, run() will 232return a JavaScript array. The first value in the array is 233either an `Error` or `undefined`. If the operation was successful, 234the second value in the array will contain the result of the 235operation. Typically, the result is an `ArrayBuffer`, but 236certain `CryptoJob` types can alter the output. 237 238If the `CryptoJob` is processed asynchronously, then the job 239must have an `ondone` property whose value is a function that 240is invoked when the operation is complete. This function will 241be called with two arguments. The first is either an `Error` 242or `undefined`, and the second is the result of the operation 243if successful. 244 245For `CipherJob` types, the output is always an `ArrayBuffer`. 246 247For `KeyExportJob` types, the output is either an `ArrayBuffer` or 248a JavaScript object (for JWK output format); 249 250For `KeyGenJob` types, the output is either a single KeyObject, 251or an array containing a Public/Private key pair represented 252either as a `KeyObjectHandle` object or a `Buffer`. 253 254For `DeriveBitsJob` type output is typically an `ArrayBuffer` but 255can be other values (`RandomBytesJob` for instance, fills an 256input buffer and always returns `undefined`). 257 258### Errors 259 260#### `ThrowCryptoError` and the `THROW_ERR_CRYPTO_*` macros 261 262The `ThrowCryptoError()` is a legacy utility that will throw a 263JavaScript exception containing details collected from OpenSSL 264about a failed operation. `ThrowCryptoError()` should only be 265used when necessary to report low-level OpenSSL failures. 266 267In `node_errors.h`, there are a number of `ERR_CRYPTO_*` 268macro definitions that define semantically specific errors. 269These can be called from within the C++ code as functions, 270like `THROW_ERR_CRYPTO_INVALID_IV(env)`. These methods 271should be used to throw JavaScript errors when necessary. 272 273## Crypto API patterns 274 275### Operation mode 276 277All crypto functions in Node.js operate in one of three 278modes: 279 280* Synchronous single-call 281* Asynchronous single-call 282* Stream-oriented 283 284It is often possible to perform various operations across 285multiple modes. For instance, cipher and decipher operations 286can be performed in any of the three modes. 287 288Synchronous single-call operations are always blocking. 289They perform their actions immediately. 290 291```js 292// Example synchronous single-call operation 293const a = new Uint8Array(10); 294const b = new Uint8Array(10); 295crypto.timingSafeEqual(a, b); 296``` 297 298Asynchronous single-call operations generally perform a 299number of synchronous input validation steps, but then 300defer the actual crypto-operation work to the libuv threadpool. 301 302```js 303// Example asynchronous single-call operation 304const buf = new Uint8Array(10); 305crypto.randomFill(buf, (err, buf) => { 306 console.log(buf); 307}); 308``` 309 310For the legacy Node.js crypto API, asynchronous single-call 311operations use the traditional Node.js callback pattern, as 312illustrated in the previous `randomFill()` example. In the 313Web Crypto API (accessible via `require('node:crypto').webcrypto`), 314all asynchronous single-call operations are Promise-based. 315 316```js 317// Example Web Crypto API asynchronous single-call operation 318const { subtle } = require('node:crypto').webcrypto; 319 320subtle.generateKeys({ name: 'HMAC', length: 256 }, true, ['sign']) 321 .then((key) => { 322 console.log(key); 323 }) 324 .catch((error) => { 325 console.error('an error occurred'); 326 }); 327``` 328 329In nearly every case, asynchronous single-call operations make use 330of the libuv threadpool to perform crypto operations off the main 331event loop thread. 332 333Stream-oriented operations use an object to maintain state 334over multiple individual synchronous steps. The steps themselves 335can be performed over time. 336 337```js 338// Example stream-oriented operation 339const hash = crypto.createHash('sha256'); 340let updates = 10; 341setTimeout(() => { 342 hash.update('hello world'); 343 setTimeout(() => { 344 console.log(hash.digest();) 345 }, 1000); 346}, 1000); 347``` 348