From c0f199e3cbcd2d53bfee7abbe3b69d4c7c642f2b Mon Sep 17 00:00:00 2001
From: James M Snell <jasnell@gmail.com>
Date: Wed, 3 Mar 2021 14:25:03 -0800
Subject: [PATCH] doc: crypto esm examples

Signed-off-by: James M Snell <jasnell@gmail.com>
---
 doc/api/crypto.md | 1588 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 1386 insertions(+), 202 deletions(-)

diff --git a/doc/api/crypto.md b/doc/api/crypto.md
index 95a3791764d3554..c291be4fc8fc741 100644
--- a/doc/api/crypto.md
+++ b/doc/api/crypto.md
@@ -9,9 +9,19 @@
 The `crypto` module provides cryptographic functionality that includes a set of
 wrappers for OpenSSL's hash, HMAC, cipher, decipher, sign, and verify functions.
 
-Use `require('crypto')` to access this module.
+```js esm
+import { createHmac } from 'crypto';
 
-```js
+const secret = 'abcdefg';
+const hash = createHmac('sha256', secret)
+               .update('I love cupcakes')
+               .digest('hex');
+console.log(hash);
+// Prints:
+//   c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658e
+```
+
+```js cjs
 const crypto = require('crypto');
 
 const secret = 'abcdefg';
@@ -26,10 +36,12 @@ console.log(hash);
 ## Determining if crypto support is unavailable
 
 It is possible for Node.js to be built without including support for the
-`crypto` module. In such cases, calling `require('crypto')` will result in an
-error being thrown.
+`crypto` module. In such cases, attempting to `import` from `crypto` or
+calling `require('crypto')` will result in an error being thrown.
 
-```js
+When using CommonJS, the error thrown can be caught using try/catch:
+
+```js cjs
 let crypto;
 try {
   crypto = require('crypto');
@@ -38,6 +50,24 @@ try {
 }
 ```
 
+When using the lexical ESM `import` keyword, the error can only be
+caught if a handler for `process.on('uncaughtException')` is registered
+*before* any attempt to load the module is made -- using, for instance,
+a preload module.
+
+When using ESM, if there is a chance that the code may be run on a build
+of Node.js where crypto support is not enabled, consider using the
+`import()` function instead of the lexical `import` keyword:
+
+```js esm
+let crypto;
+try {
+  crypto = await import('crypto');
+} catch (err) {
+  console.log('crypto support is disabled!');
+}
+```
+
 ## Class: `Certificate`
 <!-- YAML
 added: v0.11.8
@@ -68,7 +98,15 @@ changes:
 * Returns: {Buffer} The challenge component of the `spkac` data structure, which
   includes a public key and a challenge.
 
-```js
+```js esm
+const { Certificate } = await import('crypto');
+const spkac = getSpkacSomehow();
+const challenge = Certificate.exportChallenge(spkac);
+console.log(challenge.toString('utf8'));
+// Prints: the challenge as a UTF8 string
+```
+
+```js cjs
 const { Certificate } = require('crypto');
 const spkac = getSpkacSomehow();
 const challenge = Certificate.exportChallenge(spkac);
@@ -91,7 +129,15 @@ changes:
 * Returns: {Buffer} The public key component of the `spkac` data structure,
   which includes a public key and a challenge.
 
-```js
+```js esm
+const { Certificate } = await import('crypto');
+const spkac = getSpkacSomehow();
+const publicKey = Certificate.exportPublicKey(spkac);
+console.log(publicKey);
+// Prints: the public key as <Buffer ...>
+```
+
+```js cjs
 const { Certificate } = require('crypto');
 const spkac = getSpkacSomehow();
 const publicKey = Certificate.exportPublicKey(spkac);
@@ -115,7 +161,14 @@ changes:
 * Returns: {boolean} `true` if the given `spkac` data structure is valid,
   `false` otherwise.
 
-```js
+```js esm
+const { Certificate } = await import('crypto');
+const spkac = getSpkacSomehow();
+console.log(Certificate.verifySpkac(Buffer.from(spkac)));
+// Prints: true or false
+```
+
+```js cjs
 const { Certificate } = require('crypto');
 const spkac = getSpkacSomehow();
 console.log(Certificate.verifySpkac(Buffer.from(spkac)));
@@ -134,11 +187,18 @@ the `crypto.Certificate` class as illustrated in the examples below.
 Instances of the `Certificate` class can be created using the `new` keyword
 or by calling `crypto.Certificate()` as a function:
 
-```js
-const crypto = require('crypto');
+```js esm
+const { Certificate } = await import('crypto');
+
+const cert1 = new Certificate();
+const cert2 = Certificate();
+```
 
-const cert1 = new crypto.Certificate();
-const cert2 = crypto.Certificate();
+```js cjs
+const { Certificate } = require('crypto');
+
+const cert1 = new Certificate();
+const cert2 = Certificate();
 ```
 
 #### `certificate.exportChallenge(spkac[, encoding])`
@@ -151,8 +211,18 @@ added: v0.11.8
 * Returns: {Buffer} The challenge component of the `spkac` data structure, which
   includes a public key and a challenge.
 
-```js
-const cert = require('crypto').Certificate();
+```js esm
+const { Certificate } = await import('crypto');
+const cert = Certificate();
+const spkac = getSpkacSomehow();
+const challenge = cert.exportChallenge(spkac);
+console.log(challenge.toString('utf8'));
+// Prints: the challenge as a UTF8 string
+```
+
+```js cjs
+const { Certificate } = require('crypto');
+const cert = Certificate();
 const spkac = getSpkacSomehow();
 const challenge = cert.exportChallenge(spkac);
 console.log(challenge.toString('utf8'));
@@ -169,8 +239,18 @@ added: v0.11.8
 * Returns: {Buffer} The public key component of the `spkac` data structure,
   which includes a public key and a challenge.
 
-```js
-const cert = require('crypto').Certificate();
+```js esm
+const { Certificate } = await import('crypto');
+const cert = Certificate();
+const spkac = getSpkacSomehow();
+const publicKey = cert.exportPublicKey(spkac);
+console.log(publicKey);
+// Prints: the public key as <Buffer ...>
+```
+
+```js cjs
+const { Certificate } = require('crypto');
+const cert = Certificate();
 const spkac = getSpkacSomehow();
 const publicKey = cert.exportPublicKey(spkac);
 console.log(publicKey);
@@ -187,8 +267,17 @@ added: v0.11.8
 * Returns: {boolean} `true` if the given `spkac` data structure is valid,
   `false` otherwise.
 
-```js
-const cert = require('crypto').Certificate();
+```js esm
+const { Certificate } = await import('crypto');
+const cert = Certificate();
+const spkac = getSpkacSomehow();
+console.log(cert.verifySpkac(Buffer.from(spkac)));
+// Prints: true or false
+```
+
+```js cjs
+const { Certificate } = require('crypto');
+const cert = Certificate();
 const spkac = getSpkacSomehow();
 console.log(cert.verifySpkac(Buffer.from(spkac)));
 // Prints: true or false
@@ -215,22 +304,59 @@ directly using the `new` keyword.
 
 Example: Using `Cipher` objects as streams:
 
-```js
-const crypto = require('crypto');
+```js esm
+const {
+  scrypt,
+  randomFill,
+  createCipheriv
+} = await import('crypto');
 
 const algorithm = 'aes-192-cbc';
 const password = 'Password used to generate key';
 
 // First, we'll generate the key. The key length is dependent on the algorithm.
 // In this case for aes192, it is 24 bytes (192 bits).
-crypto.scrypt(password, 'salt', 24, (err, key) => {
+scrypt(password, 'salt', 24, (err, key) => {
   if (err) throw err;
   // Then, we'll generate a random initialization vector
-  crypto.randomFill(new Uint8Array(16), (err, iv) => {
+  randomFill(new Uint8Array(16), (err, iv) => {
     if (err) throw err;
 
     // Once we have the key and iv, we can create and use the cipher...
-    const cipher = crypto.createCipheriv(algorithm, key, iv);
+    const cipher = createCipheriv(algorithm, key, iv);
+
+    let encrypted = '';
+    cipher.setEncoding('hex');
+
+    cipher.on('data', (chunk) => encrypted += chunk);
+    cipher.on('end', () => console.log(encrypted));
+
+    cipher.write('some clear text data');
+    cipher.end();
+  });
+});
+```
+
+```js cjs
+const {
+  scrypt,
+  randomFill,
+  createCipheriv
+} = require('crypto');
+
+const algorithm = 'aes-192-cbc';
+const password = 'Password used to generate key';
+
+// First, we'll generate the key. The key length is dependent on the algorithm.
+// In this case for aes192, it is 24 bytes (192 bits).
+scrypt(password, 'salt', 24, (err, key) => {
+  if (err) throw err;
+  // Then, we'll generate a random initialization vector
+  randomFill(new Uint8Array(16), (err, iv) => {
+    if (err) throw err;
+
+    // Once we have the key and iv, we can create and use the cipher...
+    const cipher = createCipheriv(algorithm, key, iv);
 
     let encrypted = '';
     cipher.setEncoding('hex');
@@ -246,26 +372,76 @@ crypto.scrypt(password, 'salt', 24, (err, key) => {
 
 Example: Using `Cipher` and piped streams:
 
-```js
-const crypto = require('crypto');
-const fs = require('fs');
-const { pipeline } = require('stream');
+```js esm
+import {
+  createReadStream,
+  createWriteStream,
+} from 'fs';
+
+import {
+  pipeline
+} from 'stream';
+
+const {
+  scrypt,
+  randomFill,
+  createCipheriv,
+} = await import('crypto');
 
 const algorithm = 'aes-192-cbc';
 const password = 'Password used to generate key';
 
 // First, we'll generate the key. The key length is dependent on the algorithm.
 // In this case for aes192, it is 24 bytes (192 bits).
-crypto.scrypt(password, 'salt', 24, (err, key) => {
+scrypt(password, 'salt', 24, (err, key) => {
   if (err) throw err;
   // Then, we'll generate a random initialization vector
-  crypto.randomFill(new Uint8Array(16), (err, iv) => {
+  randomFill(new Uint8Array(16), (err, iv) => {
     if (err) throw err;
 
-    const cipher = crypto.createCipheriv(algorithm, key, iv);
+    const cipher = createCipheriv(algorithm, key, iv);
 
-    const input = fs.createReadStream('test.js');
-    const output = fs.createWriteStream('test.enc');
+    const input = createReadStream('test.js');
+    const output = createWriteStream('test.enc');
+
+    pipeline(input, cipher, output, (err) => {
+      if (err) throw err;
+    });
+  });
+});
+```
+
+```js cjs
+const {
+  createReadStream,
+  createWriteStream,
+} = require('fs');
+
+const {
+  pipeline
+} = require('stream');
+
+const {
+  scrypt,
+  randomFill,
+  createCipheriv,
+} = require('crypto');
+
+const algorithm = 'aes-192-cbc';
+const password = 'Password used to generate key';
+
+// First, we'll generate the key. The key length is dependent on the algorithm.
+// In this case for aes192, it is 24 bytes (192 bits).
+scrypt(password, 'salt', 24, (err, key) => {
+  if (err) throw err;
+  // Then, we'll generate a random initialization vector
+  randomFill(new Uint8Array(16), (err, iv) => {
+    if (err) throw err;
+
+    const cipher = createCipheriv(algorithm, key, iv);
+
+    const input = createReadStream('test.js');
+    const output = createWriteStream('test.enc');
 
     pipeline(input, cipher, output, (err) => {
       if (err) throw err;
@@ -276,21 +452,52 @@ crypto.scrypt(password, 'salt', 24, (err, key) => {
 
 Example: Using the [`cipher.update()`][] and [`cipher.final()`][] methods:
 
-```js
-const crypto = require('crypto');
+```js esm
+const {
+  scrypt,
+  randomFill,
+  createCipheriv,
+} = await import('crypto');
+
+const algorithm = 'aes-192-cbc';
+const password = 'Password used to generate key';
+
+// First, we'll generate the key. The key length is dependent on the algorithm.
+// In this case for aes192, it is 24 bytes (192 bits).
+scrypt(password, 'salt', 24, (err, key) => {
+  if (err) throw err;
+  // Then, we'll generate a random initialization vector
+  randomFill(new Uint8Array(16), (err, iv) => {
+    if (err) throw err;
+
+    const cipher = createCipheriv(algorithm, key, iv);
+
+    let encrypted = cipher.update('some clear text data', 'utf8', 'hex');
+    encrypted += cipher.final('hex');
+    console.log(encrypted);
+  });
+});
+```
+
+```js cjs
+const {
+  scrypt,
+  randomFill,
+  createCipheriv,
+} = require('crypto');
 
 const algorithm = 'aes-192-cbc';
 const password = 'Password used to generate key';
 
 // First, we'll generate the key. The key length is dependent on the algorithm.
 // In this case for aes192, it is 24 bytes (192 bits).
-crypto.scrypt(password, 'salt', 24, (err, key) => {
+scrypt(password, 'salt', 24, (err, key) => {
   if (err) throw err;
   // Then, we'll generate a random initialization vector
-  crypto.randomFill(new Uint8Array(16), (err, iv) => {
+  randomFill(new Uint8Array(16), (err, iv) => {
     if (err) throw err;
 
-    const cipher = crypto.createCipheriv(algorithm, key, iv);
+    const cipher = createCipheriv(algorithm, key, iv);
 
     let encrypted = cipher.update('some clear text data', 'utf8', 'hex');
     encrypted += cipher.final('hex');
@@ -418,19 +625,57 @@ directly using the `new` keyword.
 
 Example: Using `Decipher` objects as streams:
 
-```js
-const crypto = require('crypto');
+```js esm
+const {
+  scryptSync,
+  createDecipheriv,
+} = await import('crypto');
 
 const algorithm = 'aes-192-cbc';
 const password = 'Password used to generate key';
 // Key length is dependent on the algorithm. In this case for aes192, it is
 // 24 bytes (192 bits).
 // Use the async `crypto.scrypt()` instead.
-const key = crypto.scryptSync(password, 'salt', 24);
+const key = scryptSync(password, 'salt', 24);
 // The IV is usually passed along with the ciphertext.
 const iv = Buffer.alloc(16, 0); // Initialization vector.
 
-const decipher = crypto.createDecipheriv(algorithm, key, iv);
+const decipher = createDecipheriv(algorithm, key, iv);
+
+let decrypted = '';
+decipher.on('readable', () => {
+  while (null !== (chunk = decipher.read())) {
+    decrypted += chunk.toString('utf8');
+  }
+});
+decipher.on('end', () => {
+  console.log(decrypted);
+  // Prints: some clear text data
+});
+
+// Encrypted with same algorithm, key and iv.
+const encrypted =
+  'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa';
+decipher.write(encrypted, 'hex');
+decipher.end();
+```
+
+```js cjs
+const {
+  scryptSync,
+  createDecipheriv,
+} = require('crypto');
+
+const algorithm = 'aes-192-cbc';
+const password = 'Password used to generate key';
+// Key length is dependent on the algorithm. In this case for aes192, it is
+// 24 bytes (192 bits).
+// Use the async `crypto.scrypt()` instead.
+const key = scryptSync(password, 'salt', 24);
+// The IV is usually passed along with the ciphertext.
+const iv = Buffer.alloc(16, 0); // Initialization vector.
+
+const decipher = createDecipheriv(algorithm, key, iv);
 
 let decrypted = '';
 decipher.on('readable', () => {
@@ -452,38 +697,98 @@ decipher.end();
 
 Example: Using `Decipher` and piped streams:
 
-```js
-const crypto = require('crypto');
-const fs = require('fs');
+```js esm
+import {
+  createReadStream,
+  createWriteStream,
+} from 'fs';
+
+const {
+  scryptSync,
+  createDecipheriv,
+} = await import('crypto');
 
 const algorithm = 'aes-192-cbc';
 const password = 'Password used to generate key';
 // Use the async `crypto.scrypt()` instead.
-const key = crypto.scryptSync(password, 'salt', 24);
+const key = scryptSync(password, 'salt', 24);
 // The IV is usually passed along with the ciphertext.
 const iv = Buffer.alloc(16, 0); // Initialization vector.
 
-const decipher = crypto.createDecipheriv(algorithm, key, iv);
+const decipher = createDecipheriv(algorithm, key, iv);
 
-const input = fs.createReadStream('test.enc');
-const output = fs.createWriteStream('test.js');
+const input = createReadStream('test.enc');
+const output = createWriteStream('test.js');
+
+input.pipe(decipher).pipe(output);
+```
+
+```js cjs
+const {
+  createReadStream,
+  createWriteStream,
+} = require('fs');
+
+const {
+  scryptSync,
+  createDecipheriv,
+} = require('crypto');
+
+const algorithm = 'aes-192-cbc';
+const password = 'Password used to generate key';
+// Use the async `crypto.scrypt()` instead.
+const key = scryptSync(password, 'salt', 24);
+// The IV is usually passed along with the ciphertext.
+const iv = Buffer.alloc(16, 0); // Initialization vector.
+
+const decipher = createDecipheriv(algorithm, key, iv);
+
+const input = createReadStream('test.enc');
+const output = createWriteStream('test.js');
 
 input.pipe(decipher).pipe(output);
 ```
 
 Example: Using the [`decipher.update()`][] and [`decipher.final()`][] methods:
 
-```js
-const crypto = require('crypto');
+```js esm
+const {
+  scryptSync,
+  createDecipheriv,
+} = await import('crypto');
 
 const algorithm = 'aes-192-cbc';
 const password = 'Password used to generate key';
 // Use the async `crypto.scrypt()` instead.
-const key = crypto.scryptSync(password, 'salt', 24);
+const key = scryptSync(password, 'salt', 24);
 // The IV is usually passed along with the ciphertext.
 const iv = Buffer.alloc(16, 0); // Initialization vector.
 
-const decipher = crypto.createDecipheriv(algorithm, key, iv);
+const decipher = createDecipheriv(algorithm, key, iv);
+
+// Encrypted using same algorithm, key and iv.
+const encrypted =
+  'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa';
+let decrypted = decipher.update(encrypted, 'hex', 'utf8');
+decrypted += decipher.final('utf8');
+console.log(decrypted);
+// Prints: some clear text data
+```
+
+```js cjs
+const {
+  scryptSync,
+  createDecipheriv,
+} = require('crypto');
+
+const algorithm = 'aes-192-cbc';
+const password = 'Password used to generate key';
+// Use the async `crypto.scrypt()` instead.
+const key = scryptSync(password, 'salt', 24);
+// The IV is usually passed along with the ciphertext.
+const iv = Buffer.alloc(16, 0); // Initialization vector.
+
+const decipher = createDecipheriv(algorithm, key, iv);
 
 // Encrypted using same algorithm, key and iv.
 const encrypted =
@@ -633,16 +938,44 @@ exchanges.
 Instances of the `DiffieHellman` class can be created using the
 [`crypto.createDiffieHellman()`][] function.
 
-```js
-const crypto = require('crypto');
-const assert = require('assert');
+```js esm
+import { strictEqual } from 'assert';
+
+const {
+  createDiffieHellman,
+} = await import('crypto');
 
 // Generate Alice's keys...
-const alice = crypto.createDiffieHellman(2048);
+const alice = createDiffieHellman(2048);
 const aliceKey = alice.generateKeys();
 
 // Generate Bob's keys...
-const bob = crypto.createDiffieHellman(alice.getPrime(), alice.getGenerator());
+const bob = createDiffieHellman(alice.getPrime(), alice.getGenerator());
+const bobKey = bob.generateKeys();
+
+// Exchange and generate the secret...
+const aliceSecret = alice.computeSecret(bobKey);
+const bobSecret = bob.computeSecret(aliceKey);
+
+// OK
+strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
+```
+
+```js cjs
+const {
+  strictEqual,
+} = require('assert');
+
+const {
+  createDiffieHellman,
+} = require('crypto');
+
+// Generate Alice's keys...
+const alice = createDiffieHellman(2048);
+const aliceKey = alice.generateKeys();
+
+// Generate Bob's keys...
+const bob = createDiffieHellman(alice.getPrime(), alice.getGenerator());
 const bobKey = bob.generateKeys();
 
 // Exchange and generate the secret...
@@ -786,12 +1119,18 @@ added: v0.7.5
 The `DiffieHellmanGroup` class takes a well-known modp group as its argument but
 otherwise works the same as `DiffieHellman`.
 
-```js
-const name = 'modp1';
-const dh = crypto.createDiffieHellmanGroup(name);
+```js esm
+const { createDiffieHellmanGroup } = await import('crypto');
+const dh = createDiffieHellmanGroup('modp1');
+```
+
+```js cjs
+const { createDiffieHellmanGroup } = require('crypto');
+const dh = createDiffieHellmanGroup('modp1');
 ```
 
-`name` is taken from [RFC 2412][] (modp1 and 2) and [RFC 3526][]:
+The name (e.g. `'modp1'`) is taken from [RFC 2412][] (modp1 and 2) and
+[RFC 3526][]:
 
 ```console
 $ perl -ne 'print "$1\n" if /"(modp\d+)"/' src/node_crypto_groups.h
@@ -816,23 +1155,53 @@ key exchanges.
 Instances of the `ECDH` class can be created using the
 [`crypto.createECDH()`][] function.
 
-```js
-const crypto = require('crypto');
-const assert = require('assert');
+```js esm
+import {
+  strictEqual,
+} from 'assert';
+
+const {
+  createECDH,
+} = await import('crypto');
 
 // Generate Alice's keys...
-const alice = crypto.createECDH('secp521r1');
+const alice = createECDH('secp521r1');
 const aliceKey = alice.generateKeys();
 
 // Generate Bob's keys...
-const bob = crypto.createECDH('secp521r1');
+const bob = createECDH('secp521r1');
 const bobKey = bob.generateKeys();
 
 // Exchange and generate the secret...
 const aliceSecret = alice.computeSecret(bobKey);
 const bobSecret = bob.computeSecret(aliceKey);
 
-assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
+strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
+// OK
+```
+
+```js cjs
+const {
+  strictEqual,
+} = require('assert');
+
+const {
+  createECDH,
+} = require('crypto');
+
+// Generate Alice's keys...
+const alice = createECDH('secp521r1');
+const aliceKey = alice.generateKeys();
+
+// Generate Bob's keys...
+const bob = createECDH('secp521r1');
+const bobKey = bob.generateKeys();
+
+// Exchange and generate the secret...
+const aliceSecret = alice.computeSecret(bobKey);
+const bobSecret = bob.computeSecret(aliceKey);
+
+strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
 // OK
 ```
 
@@ -866,8 +1235,32 @@ If the `inputEncoding` is not provided, `key` is expected to be a [`Buffer`][],
 
 Example (uncompressing a key):
 
-```js
-const { createECDH, ECDH } = require('crypto');
+```js esm
+const {
+  createECDH,
+  ECDH,
+} = await import('crypto');
+
+const ecdh = createECDH('secp256k1');
+ecdh.generateKeys();
+
+const compressedKey = ecdh.getPublicKey('hex', 'compressed');
+
+const uncompressedKey = ECDH.convertKey(compressedKey,
+                                        'secp256k1',
+                                        'hex',
+                                        'hex',
+                                        'uncompressed');
+
+// The converted key and the uncompressed public key should be the same
+console.log(uncompressedKey === ecdh.getPublicKey('hex'));
+```
+
+```js cjs
+const {
+  createECDH,
+  ECDH,
+} = require('crypto');
 
 const ecdh = createECDH('secp256k1');
 ecdh.generateKeys();
@@ -1008,16 +1401,47 @@ set.
 
 Example (obtaining a shared secret):
 
-```js
-const crypto = require('crypto');
-const alice = crypto.createECDH('secp256k1');
-const bob = crypto.createECDH('secp256k1');
+```js esm
+const {
+  createECDH,
+  createHash,
+} = await crypto('crypto');
+
+const alice = createECDH('secp256k1');
+const bob = createECDH('secp256k1');
 
 // This is a shortcut way of specifying one of Alice's previous private
 // keys. It would be unwise to use such a predictable private key in a real
 // application.
 alice.setPrivateKey(
-  crypto.createHash('sha256').update('alice', 'utf8').digest()
+  createHash('sha256').update('alice', 'utf8').digest()
+);
+
+// Bob uses a newly generated cryptographically strong
+// pseudorandom key pair
+bob.generateKeys();
+
+const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex');
+const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex');
+
+// aliceSecret and bobSecret should be the same shared secret value
+console.log(aliceSecret === bobSecret);
+```
+
+```js cjs
+const {
+  createECDH,
+  createHash,
+} = require('crypto');
+
+const alice = createECDH('secp256k1');
+const bob = createECDH('secp256k1');
+
+// This is a shortcut way of specifying one of Alice's previous private
+// keys. It would be unwise to use such a predictable private key in a real
+// application.
+alice.setPrivateKey(
+  createHash('sha256').update('alice', 'utf8').digest()
 );
 
 // Bob uses a newly generated cryptographically strong
@@ -1051,9 +1475,34 @@ objects are not to be created directly using the `new` keyword.
 
 Example: Using `Hash` objects as streams:
 
-```js
-const crypto = require('crypto');
-const hash = crypto.createHash('sha256');
+```js esm
+const {
+  createHash,
+} = await import('crypto');
+
+const hash = createHash('sha256');
+
+hash.on('readable', () => {
+  // Only one element is going to be produced by the
+  // hash stream.
+  const data = hash.read();
+  if (data) {
+    console.log(data.toString('hex'));
+    // Prints:
+    //   6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
+  }
+});
+
+hash.write('some data to hash');
+hash.end();
+```
+
+```js cjs
+const {
+  createHash,
+} = require('crypto');
+
+const hash = createHash('sha256');
 
 hash.on('readable', () => {
   // Only one element is going to be produced by the
@@ -1072,20 +1521,56 @@ hash.end();
 
 Example: Using `Hash` and piped streams:
 
-```js
-const crypto = require('crypto');
-const fs = require('fs');
-const hash = crypto.createHash('sha256');
+```js esm
+const {
+  createReadStream,
+} = require('fs');
+
+const {
+  createHash,
+} = await import('crypto');
+const hash = createHash('sha256');
+
+const input = createReadStream('test.js');
+input.pipe(hash).setEncoding('hex').pipe(process.stdout);
+```
+
+```js cjs
+const {
+  createReadStream,
+} = require('fs');
+
+const {
+  createHash,
+} = require('crypto');
+
+const hash = createHash('sha256');
 
-const input = fs.createReadStream('test.js');
+const input = createReadStream('test.js');
 input.pipe(hash).setEncoding('hex').pipe(process.stdout);
 ```
 
 Example: Using the [`hash.update()`][] and [`hash.digest()`][] methods:
 
-```js
-const crypto = require('crypto');
-const hash = crypto.createHash('sha256');
+```js esm
+const {
+  createHash,
+} = require('crypto');
+
+const hash = createHash('sha256');
+
+hash.update('some data to hash');
+console.log(hash.digest('hex'));
+// Prints:
+//   6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
+```
+
+```js cjs
+const {
+  createHash,
+} = require('crypto');
+
+const hash = createHash('sha256');
 
 hash.update('some data to hash');
 console.log(hash.digest('hex'));
@@ -1111,10 +1596,33 @@ specify the desired output length in bytes.
 An error is thrown when an attempt is made to copy the `Hash` object after
 its [`hash.digest()`][] method has been called.
 
-```js
+```js esm
 // Calculate a rolling hash.
-const crypto = require('crypto');
-const hash = crypto.createHash('sha256');
+const {
+  createHash,
+} = require('crypto');
+
+const hash = createHash('sha256');
+
+hash.update('one');
+console.log(hash.copy().digest('hex'));
+
+hash.update('two');
+console.log(hash.copy().digest('hex'));
+
+hash.update('three');
+console.log(hash.copy().digest('hex'));
+
+// Etc.
+```
+
+```js cjs
+// Calculate a rolling hash.
+const {
+  createHash,
+} = require('crypto');
+
+const hash = createHash('sha256');
 
 hash.update('one');
 console.log(hash.copy().digest('hex'));
@@ -1184,9 +1692,34 @@ objects are not to be created directly using the `new` keyword.
 
 Example: Using `Hmac` objects as streams:
 
-```js
-const crypto = require('crypto');
-const hmac = crypto.createHmac('sha256', 'a secret');
+```js esm
+const {
+  createHmac,
+} = require('crypto');
+
+const hmac = createHmac('sha256', 'a secret');
+
+hmac.on('readable', () => {
+  // Only one element is going to be produced by the
+  // hash stream.
+  const data = hmac.read();
+  if (data) {
+    console.log(data.toString('hex'));
+    // Prints:
+    //   7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e
+  }
+});
+
+hmac.write('some data to hash');
+hmac.end();
+```
+
+```js cjs
+const {
+  createHmac,
+} = require('crypto');
+
+const hmac = createHmac('sha256', 'a secret');
 
 hmac.on('readable', () => {
   // Only one element is going to be produced by the
@@ -1205,20 +1738,55 @@ hmac.end();
 
 Example: Using `Hmac` and piped streams:
 
-```js
-const crypto = require('crypto');
-const fs = require('fs');
-const hmac = crypto.createHmac('sha256', 'a secret');
+```js esm
+import { createReadStream } from 'fs';
+
+const {
+  createHmac,
+} = await import('crypto');
 
-const input = fs.createReadStream('test.js');
+const hmac = createHmac('sha256', 'a secret');
+
+const input = createReadStream('test.js');
+input.pipe(hmac).pipe(process.stdout);
+```
+
+```js cjs
+const {
+  createReadStream,
+} = require('fs');
+
+const {
+  createHmac,
+} = require('crypto');
+
+const hmac = createHmac('sha256', 'a secret');
+
+const input = createReadStream('test.js');
 input.pipe(hmac).pipe(process.stdout);
 ```
 
 Example: Using the [`hmac.update()`][] and [`hmac.digest()`][] methods:
 
-```js
-const crypto = require('crypto');
-const hmac = crypto.createHmac('sha256', 'a secret');
+```js esm
+const {
+  createHmac,
+} = await import('crypto');
+
+const hmac = createHmac('sha256', 'a secret');
+
+hmac.update('some data to hash');
+console.log(hmac.digest('hex'));
+// Prints:
+//   7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e
+```
+
+```js cjs
+const {
+  createHmac,
+} = require('crypto');
+
+const hmac = createHmac('sha256', 'a secret');
 
 hmac.update('some data to hash');
 console.log(hmac.digest('hex'));
@@ -1300,8 +1868,32 @@ added: v15.0.0
 
 Example: Converting a `CryptoKey` instance to a `KeyObject`:
 
-```js
-const { webcrypto: { subtle }, KeyObject } = require('crypto');
+```js esm
+const {
+  webcrypto: {
+    subtle,
+  },
+  KeyObject,
+} = await import('crypto');
+
+const key = await subtle.generateKey({
+  name: 'HMAC',
+  hash: 'SHA-256',
+  length: 256
+}, true, ['sign', 'verify']);
+
+const keyObject = KeyObject.from(key);
+console.log(keyObject.symmetricKeySize);
+// Prints: 32 (symmetric key size in bytes)
+```
+
+```js cjs
+const {
+  webcrypto: {
+    subtle,
+  },
+  KeyObject,
+} = require('crypto');
 
 (async function() {
   const key = await subtle.generateKey({
@@ -1468,19 +2060,46 @@ to be created directly using the `new` keyword.
 
 Example: Using `Sign` and [`Verify`][] objects as streams:
 
-```js
-const crypto = require('crypto');
+```js esm
+const {
+  generateKeyPairSync,
+  createSign,
+  createVerify,
+} = await import('crypto');
 
-const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
+const { privateKey, publicKey } = generateKeyPairSync('ec', {
   namedCurve: 'sect239k1'
 });
 
-const sign = crypto.createSign('SHA256');
+const sign = createSign('SHA256');
 sign.write('some data to sign');
 sign.end();
 const signature = sign.sign(privateKey, 'hex');
 
-const verify = crypto.createVerify('SHA256');
+const verify = createVerify('SHA256');
+verify.write('some data to sign');
+verify.end();
+console.log(verify.verify(publicKey, signature, 'hex'));
+// Prints: true
+```
+
+```js cjs
+const {
+  generateKeyPairSync,
+  createSign,
+  createVerify,
+} = require('crypto');
+
+const { privateKey, publicKey } = generateKeyPairSync('ec', {
+  namedCurve: 'sect239k1'
+});
+
+const sign = createSign('SHA256');
+sign.write('some data to sign');
+sign.end();
+const signature = sign.sign(privateKey, 'hex');
+
+const verify = createVerify('SHA256');
 verify.write('some data to sign');
 verify.end();
 console.log(verify.verify(publicKey, signature, 'hex'));
@@ -1489,19 +2108,46 @@ console.log(verify.verify(publicKey, signature, 'hex'));
 
 Example: Using the [`sign.update()`][] and [`verify.update()`][] methods:
 
-```js
-const crypto = require('crypto');
+```js esm
+const {
+  generateKeyPairSync,
+  createSign,
+  createVerify,
+} = await import('crypto');
+
+const { privateKey, publicKey } = generateKeyPairSync('rsa', {
+  modulusLength: 2048,
+});
+
+const sign = createSign('SHA256');
+sign.update('some data to sign');
+sign.end();
+const signature = sign.sign(privateKey);
+
+const verify = createVerify('SHA256');
+verify.update('some data to sign');
+verify.end();
+console.log(verify.verify(publicKey, signature));
+// Prints: true
+```
 
-const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
+```js cjs
+const {
+  generateKeyPairSync,
+  createSign,
+  createVerify,
+} = require('crypto');
+
+const { privateKey, publicKey } = generateKeyPairSync('rsa', {
   modulusLength: 2048,
 });
 
-const sign = crypto.createSign('SHA256');
+const sign = createSign('SHA256');
 sign.update('some data to sign');
 sign.end();
 const signature = sign.sign(privateKey);
 
-const verify = crypto.createVerify('SHA256');
+const verify = createVerify('SHA256');
 verify.update('some data to sign');
 verify.end();
 console.log(verify.verify(publicKey, signature));
@@ -1710,7 +2356,15 @@ added: v15.6.0
 Encapsulates an X509 certificate and provides read-only access to
 its information.
 
-```js
+```js esm
+const { X509Certificate } = await import('crypto');
+
+const x509 = new X509Certificate('{... pem encoded cert ...}');
+
+console.log(x509.subject);
+```
+
+```js cjs
 const { X509Certificate } = require('crypto');
 
 const x509 = new X509Certificate('{... pem encoded cert ...}');
@@ -2374,14 +3028,46 @@ display the available digest algorithms.
 
 Example: generating the sha256 sum of a file
 
-```js
+```js esm
+import {
+  createReadStream
+} = from 'fs';
+
+const {
+  createHash,
+} = await import('crypto');
+
 const filename = process.argv[2];
-const crypto = require('crypto');
-const fs = require('fs');
 
-const hash = crypto.createHash('sha256');
+const hash = createHash('sha256');
 
-const input = fs.createReadStream(filename);
+const input = createReadStream(filename);
+input.on('readable', () => {
+  // Only one element is going to be produced by the
+  // hash stream.
+  const data = input.read();
+  if (data)
+    hash.update(data);
+  else {
+    console.log(`${hash.digest('hex')} ${filename}`);
+  }
+});
+```
+
+```js cjs
+const {
+  createReadStream,
+} = require('fs');
+
+const {
+  createHash,
+} = require('crypto');
+
+const filename = process.argv[2];
+
+const hash = createHash('sha256');
+
+const input = createReadStream(filename);
 input.on('readable', () => {
   // Only one element is going to be produced by the
   // hash stream.
@@ -2428,14 +3114,46 @@ a [`KeyObject`][], its type must be `secret`.
 
 Example: generating the sha256 HMAC of a file
 
-```js
+```js esm
+import {
+  createReadStream
+} from 'fs';
+
+const {
+  createHmac,
+} = await import('crypto');
+
+const filename = process.argv[2];
+
+const hmac = createHmac('sha256', 'a secret');
+
+const input = createReadStream(filename);
+input.on('readable', () => {
+  // Only one element is going to be produced by the
+  // hash stream.
+  const data = input.read();
+  if (data)
+    hmac.update(data);
+  else {
+    console.log(`${hmac.digest('hex')} ${filename}`);
+  }
+});
+```
+
+```js cjs
+const {
+  createReadStream,
+} = require('fs');
+
+const {
+  createHmac,
+} = require('crypto');
+
 const filename = process.argv[2];
-const crypto = require('crypto');
-const fs = require('fs');
 
-const hmac = crypto.createHmac('sha256', 'a secret');
+const hmac = createHmac('sha256', 'a secret');
 
-const input = fs.createReadStream(filename);
+const input = createReadStream(filename);
 input.on('readable', () => {
   // Only one element is going to be produced by the
   // hash stream.
@@ -2613,8 +3331,21 @@ added: v15.0.0
 Asynchronously generates a new random secret key of the given `length`. The
 `type` will determine which validations will be performed on the `length`.
 
-```js
-const { generateKey } = require('crypto');
+```js esm
+const {
+  generateKey,
+} = await import('crypto');
+
+generateKey('hmac', { length: 64 }, (err, key) => {
+  if (err) throw err;
+  console.log(key.export().toString('hex'));  // 46e..........620
+});
+```
+
+```js cjs
+const {
+  generateKey,
+} = require('crypto');
 
 generateKey('hmac', { length: 64 }, (err, key) => {
   if (err) throw err;
@@ -2669,11 +3400,36 @@ If a `publicKeyEncoding` or `privateKeyEncoding` was specified, this function
 behaves as if [`keyObject.export()`][] had been called on its result. Otherwise,
 the respective part of the key is returned as a [`KeyObject`][].
 
-It is recommended to encode public keys as `'spki'` and private keys as
-`'pkcs8'` with encryption for long-term storage:
+It is recommended to encode public keys as `'spki'` and private keys as
+`'pkcs8'` with encryption for long-term storage:
+
+```js esm
+const {
+  generateKeyPair,
+} = await import('crypto');
+
+generateKeyPair('rsa', {
+  modulusLength: 4096,
+  publicKeyEncoding: {
+    type: 'spki',
+    format: 'pem'
+  },
+  privateKeyEncoding: {
+    type: 'pkcs8',
+    format: 'pem',
+    cipher: 'aes-256-cbc',
+    passphrase: 'top secret'
+  }
+}, (err, publicKey, privateKey) => {
+  // Handle errors and use the generated key pair.
+});
+```
+
+```js cjs
+const {
+  generateKeyPair,
+} = require('crypto');
 
-```js
-const { generateKeyPair } = require('crypto');
 generateKeyPair('rsa', {
   modulusLength: 4096,
   publicKeyEncoding: {
@@ -2744,9 +3500,38 @@ When encoding public keys, it is recommended to use `'spki'`. When encoding
 private keys, it is recommended to use `'pkcs8'` with a strong passphrase,
 and to keep the passphrase confidential.
 
-```js
-const { generateKeyPairSync } = require('crypto');
-const { publicKey, privateKey } = generateKeyPairSync('rsa', {
+```js esm
+const {
+  generateKeyPairSync,
+} = await import('crypto');
+
+const {
+  publicKey,
+  privateKey,
+} = generateKeyPairSync('rsa', {
+  modulusLength: 4096,
+  publicKeyEncoding: {
+    type: 'spki',
+    format: 'pem'
+  },
+  privateKeyEncoding: {
+    type: 'pkcs8',
+    format: 'pem',
+    cipher: 'aes-256-cbc',
+    passphrase: 'top secret'
+  }
+});
+```
+
+```js cjs
+const {
+  generateKeyPairSync,
+} = require('crypto');
+
+const {
+  publicKey,
+  privateKey,
+} = generateKeyPairSync('rsa', {
   modulusLength: 4096,
   publicKeyEncoding: {
     type: 'spki',
@@ -2783,8 +3568,19 @@ added: v15.0.0
 Synchronously generates a new random secret key of the given `length`. The
 `type` will determine which validations will be performed on the `length`.
 
-```js
-const { generateKeySync } = require('crypto');
+```js esm
+const {
+  generateKeySync,
+} = await import('crypto');
+
+const key = generateKeySync('hmac', 64);
+console.log(key.export().toString('hex'));  // e89..........41e
+```
+
+```js cjs
+const {
+  generateKeySync,
+} = require('crypto');
 
 const key = generateKeySync('hmac', 64);
 console.log(key.export().toString('hex'));  // e89..........41e
@@ -2909,9 +3705,20 @@ added: v0.9.3
 * Returns: {string[]} An array with the names of the supported cipher
   algorithms.
 
-```js
-const ciphers = crypto.getCiphers();
-console.log(ciphers); // ['aes-128-cbc', 'aes-128-ccm', ...]
+```js esm
+const {
+  getCiphers,
+} = await import('crypto');
+
+console.log(getCiphers()); // ['aes-128-cbc', 'aes-128-ccm', ...]
+```
+
+```js cjs
+const {
+  getCiphers,
+} = require('crypto');
+
+console.log(getCiphers()); // ['aes-128-cbc', 'aes-128-ccm', ...]
 ```
 
 ### `crypto.getCurves()`
@@ -2921,9 +3728,20 @@ added: v2.3.0
 
 * Returns: {string[]} An array with the names of the supported elliptic curves.
 
-```js
-const curves = crypto.getCurves();
-console.log(curves); // ['Oakley-EC2N-3', 'Oakley-EC2N-4', ...]
+```js esm
+const {
+  getCurves,
+} = await import('crypto');
+
+console.log(getCurves()); // ['Oakley-EC2N-3', 'Oakley-EC2N-4', ...]
+```
+
+```js cjs
+const {
+  getCurves,
+} = require('crypto');
+
+console.log(getCurves()); // ['Oakley-EC2N-3', 'Oakley-EC2N-4', ...]
 ```
 
 ### `crypto.getDiffieHellman(groupName)`
@@ -2947,10 +3765,30 @@ and communication time.
 
 Example (obtaining a shared secret):
 
-```js
-const crypto = require('crypto');
-const alice = crypto.getDiffieHellman('modp14');
-const bob = crypto.getDiffieHellman('modp14');
+```js esm
+const {
+  getDiffieHellman,
+} = await import('crypto');
+const alice = getDiffieHellman('modp14');
+const bob = getDiffieHellman('modp14');
+
+alice.generateKeys();
+bob.generateKeys();
+
+const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex');
+const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex');
+
+/* aliceSecret and bobSecret should be the same */
+console.log(aliceSecret === bobSecret);
+```
+
+```js cjs
+const {
+  getDiffieHellman,
+} = require('crypto');
+
+const alice = getDiffieHellman('modp14');
+const bob = getDiffieHellman('modp14');
 
 alice.generateKeys();
 bob.generateKeys();
@@ -2979,9 +3817,20 @@ added: v0.9.3
 * Returns: {string[]} An array of the names of the supported hash algorithms,
   such as `'RSA-SHA256'`. Hash algorithms are also called "digest" algorithms.
 
-```js
-const hashes = crypto.getHashes();
-console.log(hashes); // ['DSA', 'DSA-SHA', 'DSA-SHA1', ...]
+```js esm
+const {
+  getHashes,
+} = await import('crypto');
+
+console.log(getHashes()); // ['DSA', 'DSA-SHA', 'DSA-SHA1', ...]
+```
+
+```js cjs
+const {
+  getHashes,
+} = require('crypto');
+
+console.log(getHashes()); // ['DSA', 'DSA-SHA', 'DSA-SHA1', ...]
 ```
 
 ### `crypto.hkdf(digest, key, salt, info, keylen, callback)`
@@ -3013,9 +3862,23 @@ otherwise `err` will be `null`. The successfully generated `derivedKey` will
 be passed to the callback as an {ArrayBuffer}. An error will be thrown if any
 of the input aguments specify invalid values or types.
 
-```js
-const crypto = require('crypto');
-crypto.hkdf('sha512', 'key', 'salt', 'info', 64, (err, derivedKey) => {
+```js esm
+const {
+  hkdf,
+} = await import('crypto');
+
+hkdf('sha512', 'key', 'salt', 'info', 64, (err, derivedKey) => {
+  if (err) throw err;
+  console.log(Buffer.from(derivedKey).toString('hex'));  // '24156e2...5391653'
+});
+```
+
+```js cjs
+const {
+  hkdf,
+} = require('crypto');
+
+hkdf('sha512', 'key', 'salt', 'info', 64, (err, derivedKey) => {
   if (err) throw err;
   console.log(Buffer.from(derivedKey).toString('hex'));  // '24156e2...5391653'
 });
@@ -3048,9 +3911,21 @@ The successfully generated `derivedKey` will be returned as an {ArrayBuffer}.
 An error will be thrown if any of the input aguments specify invalid values or
 types, or if the derived key cannot be generated.
 
-```js
-const crypto = require('crypto');
-const derivedKey = crypto.hkdfSync('sha512', 'key', 'salt', 'info', 64);
+```js esm
+const {
+  hkdfSync,
+} = await import('crypto');
+
+const derivedKey = hkdfSync('sha512', 'key', 'salt', 'info', 64);
+console.log(Buffer.from(derivedKey).toString('hex'));  // '24156e2...5391653'
+```
+
+```js cjs
+const {
+  hkdfSync,
+} = require('crypto');
+
+const derivedKey = hkdfSync('sha512', 'key', 'salt', 'info', 64);
 console.log(Buffer.from(derivedKey).toString('hex'));  // '24156e2...5391653'
 ```
 
@@ -3112,9 +3987,23 @@ random and at least 16 bytes long. See [NIST SP 800-132][] for details.
 When passing strings for `password` or `salt`, please consider
 [caveats when using strings as inputs to cryptographic APIs][].
 
-```js
-const crypto = require('crypto');
-crypto.pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, derivedKey) => {
+```js esm
+const {
+  pbkdf2,
+} = await import('crypto');
+
+pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, derivedKey) => {
+  if (err) throw err;
+  console.log(derivedKey.toString('hex'));  // '3745e48...08d59ae'
+});
+```
+
+```js cjs
+const {
+  pbkdf2,
+} = require('crypto');
+
+pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, derivedKey) => {
   if (err) throw err;
   console.log(derivedKey.toString('hex'));  // '3745e48...08d59ae'
 });
@@ -3124,7 +4013,16 @@ The `crypto.DEFAULT_ENCODING` property can be used to change the way the
 `derivedKey` is passed to the callback. This property, however, has been
 deprecated and use should be avoided.
 
-```js
+```js esm
+const crypto = await import('crypto');
+crypto.DEFAULT_ENCODING = 'hex';
+crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', (err, derivedKey) => {
+  if (err) throw err;
+  console.log(derivedKey);  // '3745e48...aa39b34'
+});
+```
+
+```js cjs
 const crypto = require('crypto');
 crypto.DEFAULT_ENCODING = 'hex';
 crypto.pbkdf2('secret', 'salt', 100000, 512, 'sha512', (err, derivedKey) => {
@@ -3186,9 +4084,21 @@ random and at least 16 bytes long. See [NIST SP 800-132][] for details.
 When passing strings for `password` or `salt`, please consider
 [caveats when using strings as inputs to cryptographic APIs][].
 
-```js
-const crypto = require('crypto');
-const key = crypto.pbkdf2Sync('secret', 'salt', 100000, 64, 'sha512');
+```js esm
+const {
+  pbkdf2Sync,
+} = await import('crypto');
+
+const key = pbkdf2Sync('secret', 'salt', 100000, 64, 'sha512');
+console.log(key.toString('hex'));  // '3745e48...08d59ae'
+```
+
+```js cjs
+const {
+  pbkdf2Sync,
+} = require('crypto');
+
+const key = pbkdf2Sync('secret', 'salt', 100000, 64, 'sha512');
 console.log(key.toString('hex'));  // '3745e48...08d59ae'
 ```
 
@@ -3196,7 +4106,14 @@ The `crypto.DEFAULT_ENCODING` property may be used to change the way the
 `derivedKey` is returned. This property, however, is deprecated and use
 should be avoided.
 
-```js
+```js esm
+const crypto = await import('crypto');
+crypto.DEFAULT_ENCODING = 'hex';
+const key = crypto.pbkdf2Sync('secret', 'salt', 100000, 512, 'sha512');
+console.log(key);  // '3745e48...aa39b34'
+```
+
+```js cjs
 const crypto = require('crypto');
 crypto.DEFAULT_ENCODING = 'hex';
 const key = crypto.pbkdf2Sync('secret', 'salt', 100000, 512, 'sha512');
@@ -3404,10 +4321,25 @@ and the `callback` function is invoked with two arguments: `err` and `buf`.
 If an error occurs, `err` will be an `Error` object; otherwise it is `null`. The
 `buf` argument is a [`Buffer`][] containing the generated bytes.
 
-```js
+```js esm
 // Asynchronous
-const crypto = require('crypto');
-crypto.randomBytes(256, (err, buf) => {
+const {
+  randomBytes,
+} = await import('crypto');
+
+randomBytes(256, (err, buf) => {
+  if (err) throw err;
+  console.log(`${buf.length} bytes of random data: ${buf.toString('hex')}`);
+});
+```
+
+```js cjs
+// Asynchronous
+const {
+  randomBytes,
+} = require('crypto');
+
+randomBytes(256, (err, buf) => {
   if (err) throw err;
   console.log(`${buf.length} bytes of random data: ${buf.toString('hex')}`);
 });
@@ -3417,9 +4349,24 @@ If the `callback` function is not provided, the random bytes are generated
 synchronously and returned as a [`Buffer`][]. An error will be thrown if
 there is a problem generating the bytes.
 
-```js
+```js esm
 // Synchronous
-const buf = crypto.randomBytes(256);
+const {
+  randomBytes,
+} = await import('crypto');
+
+const buf = randomBytes(256);
+console.log(
+  `${buf.length} bytes of random data: ${buf.toString('hex')}`);
+```
+
+```js cjs
+// Synchronous
+const {
+  randomBytes,
+} = require('crypto');
+
+const buf = randomBytes(256);
 console.log(
   `${buf.length} bytes of random data: ${buf.toString('hex')}`);
 ```
@@ -3460,36 +4407,81 @@ changes:
 
 Synchronous version of [`crypto.randomFill()`][].
 
-```js
+```js esm
+const {
+  randomFillSync,
+} = await import('crypto');
+
 const buf = Buffer.alloc(10);
-console.log(crypto.randomFillSync(buf).toString('hex'));
+console.log(randomFillSync(buf).toString('hex'));
 
-crypto.randomFillSync(buf, 5);
+randomFillSync(buf, 5);
 console.log(buf.toString('hex'));
 
 // The above is equivalent to the following:
-crypto.randomFillSync(buf, 5, 5);
+randomFillSync(buf, 5, 5);
+console.log(buf.toString('hex'));
+```
+
+```js cjs
+const {
+  randomFillSync,
+} = require('crypto');
+
+const buf = Buffer.alloc(10);
+console.log(randomFillSync(buf).toString('hex'));
+
+randomFillSync(buf, 5);
+console.log(buf.toString('hex'));
+
+// The above is equivalent to the following:
+randomFillSync(buf, 5, 5);
 console.log(buf.toString('hex'));
 ```
 
 Any `ArrayBuffer`, `TypedArray` or `DataView` instance may be passed as
 `buffer`.
 
-```js
+```js esm
+const {
+  randomFillSync,
+} = await import('crypto');
+
+const a = new Uint32Array(10);
+console.log(Buffer.from(randomFillSync(a).buffer,
+                        a.byteOffset, a.byteLength).toString('hex'));
+
+const b = new Float64Array(10);
+console.log(Buffer.from(randomFillSync(b).buffer,
+                        b.byteOffset, b.byteLength).toString('hex'));
+
+const c = new DataView(new ArrayBuffer(10));
+console.log(Buffer.from(randomFillSync(c).buffer,
+                        c.byteOffset, c.byteLength).toString('hex'));
+
+const d = new ArrayBuffer(10);
+console.log(Buffer.from(randomFillSync(d)).toString('hex'));
+```
+
+```js cjs
+const {
+  randomFillSync,
+} = require('crypto');
+
 const a = new Uint32Array(10);
-console.log(Buffer.from(crypto.randomFillSync(a).buffer,
+console.log(Buffer.from(randomFillSync(a).buffer,
                         a.byteOffset, a.byteLength).toString('hex'));
 
 const b = new Float64Array(10);
-console.log(Buffer.from(crypto.randomFillSync(b).buffer,
+console.log(Buffer.from(randomFillSync(b).buffer,
                         b.byteOffset, b.byteLength).toString('hex'));
 
 const c = new DataView(new ArrayBuffer(10));
-console.log(Buffer.from(crypto.randomFillSync(c).buffer,
+console.log(Buffer.from(randomFillSync(c).buffer,
                         c.byteOffset, c.byteLength).toString('hex'));
 
 const d = new ArrayBuffer(10);
-console.log(Buffer.from(crypto.randomFillSync(d)).toString('hex'));
+console.log(Buffer.from(randomFillSync(d)).toString('hex'));
 ```
 
 ### `crypto.randomFill(buffer[, offset][, size], callback)`
@@ -3516,20 +4508,47 @@ requires that a callback is passed in.
 
 If the `callback` function is not provided, an error will be thrown.
 
-```js
+```js esm
+const {
+  randomFill,
+} = await import('crypto');
+
+const buf = Buffer.alloc(10);
+randomFill(buf, (err, buf) => {
+  if (err) throw err;
+  console.log(buf.toString('hex'));
+});
+
+randomFill(buf, 5, (err, buf) => {
+  if (err) throw err;
+  console.log(buf.toString('hex'));
+});
+
+// The above is equivalent to the following:
+randomFill(buf, 5, 5, (err, buf) => {
+  if (err) throw err;
+  console.log(buf.toString('hex'));
+});
+```
+
+```js cjs
+const {
+  randomFill,
+} = require('crypto');
+
 const buf = Buffer.alloc(10);
-crypto.randomFill(buf, (err, buf) => {
+randomFill(buf, (err, buf) => {
   if (err) throw err;
   console.log(buf.toString('hex'));
 });
 
-crypto.randomFill(buf, 5, (err, buf) => {
+randomFill(buf, 5, (err, buf) => {
   if (err) throw err;
   console.log(buf.toString('hex'));
 });
 
 // The above is equivalent to the following:
-crypto.randomFill(buf, 5, 5, (err, buf) => {
+randomFill(buf, 5, 5, (err, buf) => {
   if (err) throw err;
   console.log(buf.toString('hex'));
 });
@@ -3538,30 +4557,67 @@ crypto.randomFill(buf, 5, 5, (err, buf) => {
 Any `ArrayBuffer` `TypedArray` or `DataView` instance may be passed as
 `buffer`.
 
-```js
+```js esm
+const {
+  randomFill,
+} = await import('crypto');
+
+const a = new Uint32Array(10);
+randomFill(a, (err, buf) => {
+  if (err) throw err;
+  console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)
+    .toString('hex'));
+});
+
+const b = new Float64Array(10);
+randomFill(b, (err, buf) => {
+  if (err) throw err;
+  console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)
+    .toString('hex'));
+});
+
+const c = new DataView(new ArrayBuffer(10));
+randomFill(c, (err, buf) => {
+  if (err) throw err;
+  console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)
+    .toString('hex'));
+});
+
+const d = new ArrayBuffer(10);
+randomFill(d, (err, buf) => {
+  if (err) throw err;
+  console.log(Buffer.from(buf).toString('hex'));
+});
+```
+
+```js cjs
+const {
+  randomFill,
+} = require('crypto');
+
 const a = new Uint32Array(10);
-crypto.randomFill(a, (err, buf) => {
+randomFill(a, (err, buf) => {
   if (err) throw err;
   console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)
     .toString('hex'));
 });
 
 const b = new Float64Array(10);
-crypto.randomFill(b, (err, buf) => {
+randomFill(b, (err, buf) => {
   if (err) throw err;
   console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)
     .toString('hex'));
 });
 
 const c = new DataView(new ArrayBuffer(10));
-crypto.randomFill(c, (err, buf) => {
+randomFill(c, (err, buf) => {
   if (err) throw err;
   console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength)
     .toString('hex'));
 });
 
 const d = new ArrayBuffer(10);
-crypto.randomFill(d, (err, buf) => {
+randomFill(d, (err, buf) => {
   if (err) throw err;
   console.log(Buffer.from(buf).toString('hex'));
 });
@@ -3596,23 +4652,67 @@ be [safe integers][].
 If the `callback` function is not provided, the random integer is
 generated synchronously.
 
-```js
+```js esm
+// Asynchronous
+const {
+  randomInt,
+} = await import('crypto');
+
+randomInt(3, (err, n) => {
+  if (err) throw err;
+  console.log(`Random number chosen from (0, 1, 2): ${n}`);
+});
+```
+
+```js cjs
 // Asynchronous
-crypto.randomInt(3, (err, n) => {
+const {
+  randomInt,
+} = require('crypto');
+
+randomInt(3, (err, n) => {
   if (err) throw err;
   console.log(`Random number chosen from (0, 1, 2): ${n}`);
 });
 ```
 
-```js
+```js esm
+// Synchronous
+const {
+  randomInt,
+} = await import('crypto');
+
+const n = randomInt(3);
+console.log(`Random number chosen from (0, 1, 2): ${n}`);
+```
+
+```js cjs
 // Synchronous
-const n = crypto.randomInt(3);
+const {
+  randomInt,
+} = require('crypto');
+
+const n = randomInt(3);
 console.log(`Random number chosen from (0, 1, 2): ${n}`);
 ```
 
-```js
+```js esm
 // With `min` argument
-const n = crypto.randomInt(1, 7);
+const {
+  randomInt,
+} = await import('crypto');
+
+const n = randomInt(1, 7);
+console.log(`The dice rolled: ${n}`);
+```
+
+```js cjs
+// With `min` argument
+const {
+  randomInt,
+} = require('crypto');
+
+const n = randomInt(1, 7);
 console.log(`The dice rolled: ${n}`);
 ```
 
@@ -3684,15 +4784,35 @@ The `callback` function is called with two arguments: `err` and `derivedKey`.
 An exception is thrown when any of the input arguments specify invalid values
 or types.
 
-```js
-const crypto = require('crypto');
+```js esm
+const {
+  scrypt,
+} = await import('crypto');
+
+// Using the factory defaults.
+scrypt('password', 'salt', 64, (err, derivedKey) => {
+  if (err) throw err;
+  console.log(derivedKey.toString('hex'));  // '3745e48...08d59ae'
+});
+// Using a custom N parameter. Must be a power of two.
+scrypt('password', 'salt', 64, { N: 1024 }, (err, derivedKey) => {
+  if (err) throw err;
+  console.log(derivedKey.toString('hex'));  // '3745e48...aa39b34'
+});
+```
+
+```js cjs
+const {
+  scrypt,
+} = require('crypto');
+
 // Using the factory defaults.
-crypto.scrypt('password', 'salt', 64, (err, derivedKey) => {
+scrypt('password', 'salt', 64, (err, derivedKey) => {
   if (err) throw err;
   console.log(derivedKey.toString('hex'));  // '3745e48...08d59ae'
 });
 // Using a custom N parameter. Must be a power of two.
-crypto.scrypt('password', 'salt', 64, { N: 1024 }, (err, derivedKey) => {
+scrypt('password', 'salt', 64, { N: 1024 }, (err, derivedKey) => {
   if (err) throw err;
   console.log(derivedKey.toString('hex'));  // '3745e48...aa39b34'
 });
@@ -3744,13 +4864,29 @@ returned as a [`Buffer`][].
 An exception is thrown when any of the input arguments specify invalid values
 or types.
 
-```js
-const crypto = require('crypto');
+```js esm
+const {
+  scryptSync,
+} = await import('crypto');
+// Using the factory defaults.
+
+const key1 = scryptSync('password', 'salt', 64);
+console.log(key1.toString('hex'));  // '3745e48...08d59ae'
+// Using a custom N parameter. Must be a power of two.
+const key2 = scryptSync('password', 'salt', 64, { N: 1024 });
+console.log(key2.toString('hex'));  // '3745e48...aa39b34'
+```
+
+```js cjs
+const {
+  scryptSync,
+} = require('crypto');
 // Using the factory defaults.
-const key1 = crypto.scryptSync('password', 'salt', 64);
+
+const key1 = scryptSync('password', 'salt', 64);
 console.log(key1.toString('hex'));  // '3745e48...08d59ae'
 // Using a custom N parameter. Must be a power of two.
-const key2 = crypto.scryptSync('password', 'salt', 64, { N: 1024 });
+const key2 = scryptSync('password', 'salt', 64, { N: 1024 });
 console.log(key2.toString('hex'));  // '3745e48...aa39b34'
 ```
 
@@ -4067,15 +5203,63 @@ mode must adhere to certain restrictions when using the cipher API:
   applications *must* call `final()` to compute or verify the
   authentication tag.
 
-```js
-const crypto = require('crypto');
+```js esm
+const {
+  createCipheriv,
+  createDecipheriv,
+  randomBytes,
+} = await import('crypto');
+
+const key = 'keykeykeykeykeykeykeykey';
+const nonce = randomBytes(12);
+
+const aad = Buffer.from('0123456789', 'hex');
+
+const cipher = createCipheriv('aes-192-ccm', key, nonce, {
+  authTagLength: 16
+});
+const plaintext = 'Hello world';
+cipher.setAAD(aad, {
+  plaintextLength: Buffer.byteLength(plaintext)
+});
+const ciphertext = cipher.update(plaintext, 'utf8');
+cipher.final();
+const tag = cipher.getAuthTag();
+
+// Now transmit { ciphertext, nonce, tag }.
+
+const decipher = createDecipheriv('aes-192-ccm', key, nonce, {
+  authTagLength: 16
+});
+decipher.setAuthTag(tag);
+decipher.setAAD(aad, {
+  plaintextLength: ciphertext.length
+});
+const receivedPlaintext = decipher.update(ciphertext, null, 'utf8');
+
+try {
+  decipher.final();
+} catch (err) {
+  console.error('Authentication failed!');
+  return;
+}
+
+console.log(receivedPlaintext);
+```
+
+```js cjs
+const {
+  createCipheriv,
+  createDecipheriv,
+  randomBytes,
+} = require('crypto');
 
 const key = 'keykeykeykeykeykeykeykey';
-const nonce = crypto.randomBytes(12);
+const nonce = randomBytes(12);
 
 const aad = Buffer.from('0123456789', 'hex');
 
-const cipher = crypto.createCipheriv('aes-192-ccm', key, nonce, {
+const cipher = createCipheriv('aes-192-ccm', key, nonce, {
   authTagLength: 16
 });
 const plaintext = 'Hello world';
@@ -4088,7 +5272,7 @@ const tag = cipher.getAuthTag();
 
 // Now transmit { ciphertext, nonce, tag }.
 
-const decipher = crypto.createDecipheriv('aes-192-ccm', key, nonce, {
+const decipher = createDecipheriv('aes-192-ccm', key, nonce, {
   authTagLength: 16
 });
 decipher.setAuthTag(tag);