Principles of Encryption API Selection
- The standard library first.
- Prefer well-known and audited libraries.
- Before choosing a third-party library, do some investigation first.
Basics
- Encode / Decode:
Buffer
Class. - Random numbers
- The basis of cryptography.
- It is extremely difficult to obtain true random numbers, commonly, pseudo-random numbers are used.
- Don't use
Math.random
! - Use the
random
functions in thecrypto
module, e.g.crypto.randomBytes
.
- Hash
- Irreversible.
- The output is a fixed-length string.
- Same input, same output.
- Different inputs, different outputs.
- Typical applications
- Data integrity verification
- Passphrase hashing
- Derived Keys
- Key
- Derived Key: A key generated from a master key.
- Key Encapsulation: encrypt and export the key.
- Key Decapsulation: decrypts and imports the key
- Authenticated Encryption: encryption and tamper-proof
- Symmetric Encryption
- Use the same key for encryption and decryption
- Fast
- Suitable for large data blocks
- Key exchange is difficult
- Asymmetric encryption
- Public key + Private key
- Encryption: public key encryption, private key decryption
- Signing: private key encryption, public key decryption
- Slow
- Not suitable for large data blocks
- Typical applications
- Key exchange
- Digital certificates
- Digital signatures
- Public key + Private key
- Hybrid encryption
- Combination of the above two
- Asymmetric encryption for key exchange
- Symmetric encryption for data manipulation
- Combination of the above two
- Encryption modes
- Block encryption, grouping before encryption.
- Never use ECB mode.
- Stream encryption, dealing with continuous or unknown length byte streams, advantageous when the plaintext is small.
- Block encryption, grouping before encryption.
Hash
- Don't use:
- MD5
- SHA-1
- PBKDF2
- bcrypt
- Message digest: SHA-256
crypto.createHash('sha256')
- Use stream mode for large data
- Do not use for sensitive data such as passphrases
- Message Authentication Code (HMAC)
- hash and key (key to be known by both parties)
crypto.createHmac('sha256', 'secret')
- Password hashing and KDF (Key Derivation Function)
- Features.
- salt built-in
- Deliberated slow algorithms to offset the computational power boost caused by newer hardware.
- argon2 (recommended)
- argon2i, resistant to side-channel attacks
- argon2d, resistant to GPU attacks
- argon2id (recommended), combination of the above
- https://www.npmjs.com/package/argon2
- scrypt
crypto.scrypt
- Features.
Symmetric Encryption
- Don't use:
- DES, including 3DES.
- Blowfish
- TWofish is its successor, but not popular.
- AES-ECB
- No ECB mode, please.
- AES
- Common modes.
- AES-CBC, when authentication is not required
crypto.createCipheriv('aes-256-cbc', ...)
crypto.createDecipheriv('aes-256-cbc', ...)
- AES-GCM, when authentication is required
crypto.createCipheriv('aes-256-gcm', ...)
crypto.createDecipheriv('aes-256-gcm', ...)
- AES-CBC, when authentication is not required
- For big data use stream mode
- Common modes.
- ChaCha20-Poly1305
- ChaCha20 encryption + Poly1305 hashing
- Equivalent to AES-GCM
- Suitable for environments without AES hardware acceleration support
crypto.createCipheriv('chacha20-poly1305', ...)
crypto.createDecipheriv('chacha20-poly1305', ...)
Asymmetric Encryption
- ASN.1 Data Structure
-
Key encoding format: PEM format
-
Public key: SPKI
// import crypto.createPrivateKey(fs.readFileSync("public.pem"));
-
Private key.
- PKCS #1 (old, RSA only)
- PKCS #8 (new, for multiple algorithms)
// import crypto.createPrivateKey(fs.readFileSync("private.pem"));
Export:
crypto.KeyObject.export(option)
-
-
RSA
- key
crypto.generateKeyPair('rsa', ...)
-
encryption and decryption
- padding: add random data to the plaintext before encryption to improve the security of RSA.
- Always used if no special reasons.
- crypto.constants.RSA_PKCS1_OAEP_PADDING (recommended)
- crypto.constants.RSA_PKCS1_PADDING (not recommended)
-
encryption
crypto.publicEncrypt( { key: publicKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: "sha256", }, plaintext );
-
decryption
crypto.privateDecrypt( { key: privateKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: "sha256", }, message );
- padding: add random data to the plaintext before encryption to improve the security of RSA.
-
Digital signature
- padding:
- crypto.constants.RSA_PKCS1_PADDING (default)
- crypto.constants.RSA_PKCS1_PSS_PADDING (new version, recommended)
- signing
crypto.sign("sha256", message, { key: privateKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, });
- verification
crypto.verify( "sha256", message, { key: publicKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, }, signature );
- padding:
- key
-
Elliptic Curve
- Equivalent security to RSA
- Shorter keys, faster and cheaper
- Unlike RSA, its key pair does not support asymmetric encryption, i.e.: the public key decrypts the message encrypted by the private key, or vice versa.
- Commonly used curves
- P-256: secp256r1 / prime256v1, NIST standard
- Curve25519
- X25519 for key exchange
- Ed25519 for digital signatures
- secp256k1, used by Bitcoin
- Typical Applications
- Key exchange (ECDH)
- Digital signatures
- key
crypto.generateKeyPair('ec', ...)
- ECDH
- Unlike RSA (where party A encrypts the key with party B's public key and then sends it to party B to decrypt).
- DH protocol
- Alice and Bob each generate a key pair
- They exchange the public keys
- Combine their private keys to generate a shared key, i.e.
shareSecret(A public key, B private key) = shareSecret(B public key, A private key)
crypto.diffieHellman({A public key, B private key})
- A reference implementation of shared keys.
-
crypto.diffieHellman
gets shareSecret - Generate a random salt
-
sha256(shareSecret, salt)
is the shared key, note: remember to pass the salt to the other side with the ciphertext.
-
- Digital signatures
- ECDSA (using prime256v1)
crypto.sign('sha256', message, privateKey)
crypto.verify('sha256', message, publicKey, signature)
- EdDSA (using Ed25519), which does not require an externally configured hash function as it already has a built-in digital signature algorithm.
crypto.sign(null, message, privateKey)
crypto.verify(null, message, publicKey, signature)
- ECDSA (using prime256v1)
Web Crypto
- Used in the browser environment
- Encoding
ArrayBuffer
-
atob
andbtoa
TextEncoder
- Random numbers.
Window.crypto.getRandomValues
Window.crypto.randomUUID
- keys
window.crypto.subtle.generateKey(algorithm, extractable, usages)
window.crypto.subtle.importKey(format, data, algorithm, extractable, usages)
window.crypto.subtle.exportKey(format, key)
window.crypto.subtle.wrapKey
window.crypto.subtle.unwrapKey
window.crypto.subtle.deriveKey
- Hash
- SHA-256:
window.crypto.subtle.digest('SHA-256', ...)
- HMAC:
window.crypto.subtle.sign("HMAC", key, encoded)
- Passphrase hash: https://www.npmjs.com/package/hash-wasm
- SHA-256:
- Encryption and decryption (both symmetric and asymmetric)
crypto.subtle.encrypt(algorithm, key, data)
crypto.subtle.decrypt(algorithm, key, data)
- Digital signatures
window.crypto.subtle.sign
window.crypto.subtle.verify
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.