# Password hashing

Scrypt & Argon2

```js import crypto from 'node:crypto'; const PASSWORD = '12345678'; const SALT = crypto.randomBytes(16); // unique for each password const NORMALIZED_PASSWORD = PASSWORD.slice(-128).normalize('NFKC'); console.log('Salt:', SALT.toString('hex'), '\n'); ////////////////////////////////////////////////// // SCRYPT (Node.js v10.9) ////////////////////////////////////////////////// const hashScryptBuffer = crypto.scryptSync( NORMALIZED_PASSWORD, SALT, 64, // keylen { N: 16384, // CPU/memory cost r: 8, // Block size p: 1 // Parallelization } ); const hashScryptHex = hashScryptBuffer.toString('hex'); console.log('Scrypt:', hashScryptHex); const hashScryptIsEqual = crypto.timingSafeEqual( Buffer.from(hashScryptHex, 'hex'), hashScryptBuffer ); console.log('Verify:', hashScryptIsEqual, '\n'); ////////////////////////////////////////////////// // ARGON2 (Node.js v24.7) ////////////////////////////////////////////////// const hashArgon2Buffer = crypto.argon2Sync( 'argon2id', { message: NORMALIZED_PASSWORD, nonce: SALT, parallelism: 4, tagLength: 64, memory: 65536, passes: 3 } ); const hashArgon2Hex = hashArgon2Buffer.toString('hex'); console.log('Argon2:', hashArgon2Hex); const hashArgon2IsEqual = crypto.timingSafeEqual( Buffer.from(hashArgon2Hex, 'hex'), hashArgon2Buffer ); console.log('Verify:', hashArgon2IsEqual); ```
# JSON Web Token (JWT) Internet standard for creating data with optional signature whose payload holds JSON that asserts some number of claims.

RSA PKCS1-v1.5 (1993)

```js import crypto from 'node:crypto'; // Base 64 Encoding with URL and Filename Safe Alphabet. function toBase64Url(data) { if (Buffer.isBuffer(data)) return data.toString('base64url'); if (typeof(data) !== 'string') data = JSON.stringify(data); return toBase64Url(Buffer.from(data)); } function fromBase64Url(data, parseJson) { data = Buffer.from(data, 'base64url'); if (parseJson != null) data = data.toString('utf8'); return parseJson ? JSON.parse(data) : data; } ////////////////////////////////////////////////// // JWT: HEADER & PAYLOAD ////////////////////////////////////////////////// // RSA PKCS1-v1.5 (1993). // // RSA: Rivest–Shamir–Adleman // PKCS1: Public Key Cryptography Standard #1 const ALG = 'RS256'; // 'RS256' | 'RS384' | 'RS512' const ALGORITHM = 'SHA256'; // 'SHA256' | 'SHA384' | 'SHA512' const header = { alg: ALG, typ: 'JWT' }; const payload = { data: 'Hello World!' }; ////////////////////////////////////////////////// // KEYS ////////////////////////////////////////////////// const { publicKey, privateKey } = crypto.generateKeyPairSync( 'rsa', { modulusLength: 3072, // ≥2048 publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, } ); const PADDING = crypto.constants.RSA_PKCS1_PADDING; const PUBLIC_KEY = { key: publicKey, padding: PADDING }; const PRIVATE_KEY = { key: privateKey, padding: PADDING }; console.log(`publicKey:\n${publicKey}`); ////////////////////////////////////////////////// // SIGN ////////////////////////////////////////////////// const headerBase64Url = toBase64Url(header); const payloadBase64Url = toBase64Url(payload); const data = `${headerBase64Url}.${payloadBase64Url}`; const signature = crypto.sign(ALGORITHM, data, PRIVATE_KEY); const signatureBase64Url = toBase64Url(signature); const jsonWebToken = `${data}.${signatureBase64Url}`; console.log('Token:', jsonWebToken, '\n'); ////////////////////////////////////////////////// // VERIFY ////////////////////////////////////////////////// const jwtParts = jsonWebToken.split('.'); const jwtHeaderBase64Url = jwtParts[0]; const jwtPayloadBase64Url = jwtParts[1]; const jwtSignatureBase64Url = jwtParts[2]; const jwtHeaderObject = fromBase64Url(jwtHeaderBase64Url, true); const jwtPayloadObject = fromBase64Url(jwtPayloadBase64Url, true); const jwtSignatureBuffer = fromBase64Url(jwtSignatureBase64Url); if (jwtHeaderObject.alg !== header.alg) throw new Error('Invalid algorithm'); const jwtData = `${jwtHeaderBase64Url}.${jwtPayloadBase64Url}`; const isValid = crypto.verify(ALGORITHM, jwtData, PUBLIC_KEY, jwtSignatureBuffer); console.log('Verify:', isValid); // true console.log('Header:', jwtHeaderObject); // { alg: 'RS256', typ: 'JWT' } console.log('Payload:', jwtPayloadObject); // { data: 'Hello World!' } ```

RSA-PSS PKCS1-v2.1 (2002)

```js import crypto from 'node:crypto'; // Base 64 Encoding with URL and Filename Safe Alphabet. function toBase64Url(data) { if (Buffer.isBuffer(data)) return data.toString('base64url'); if (typeof(data) !== 'string') data = JSON.stringify(data); return toBase64Url(Buffer.from(data)); } function fromBase64Url(data, parseJson) { data = Buffer.from(data, 'base64url'); if (parseJson != null) data = data.toString('utf8'); return parseJson ? JSON.parse(data) : data; } ////////////////////////////////////////////////// // JWT: HEADER & PAYLOAD ////////////////////////////////////////////////// // RSA-PSS PKCS1-v2.1 (2002) // // RSA: Rivest–Shamir–Adleman // PSS: Probabilistic Signature Scheme // PKCS1: Public Key Cryptography Standard #1 const ALG = 'PS256'; // 'PS256' | 'PS384' | 'PS512' const ALGORITHM = 'SHA256'; // 'SHA256' | 'SHA384' | 'SHA512' const header = { alg: ALG, typ: 'JWT' }; const payload = { data: 'Hello World!' }; ////////////////////////////////////////////////// // KEYS ////////////////////////////////////////////////// const { publicKey, privateKey } = crypto.generateKeyPairSync( 'rsa', { modulusLength: 3072, // ≥2048 publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, } ); const PADDING = crypto.constants.RSA_PKCS1_PSS_PADDING; // MGF1 const SALTLENGTH = crypto.constants.RSA_PSS_SALTLEN_DIGEST; const PUBLIC_KEY = { key: publicKey, padding: PADDING, saltLength: SALTLENGTH }; const PRIVATE_KEY = { key: privateKey, padding: PADDING, saltLength: SALTLENGTH }; console.log(`publicKey:\n${publicKey}`); ////////////////////////////////////////////////// // SIGN ////////////////////////////////////////////////// const headerBase64Url = toBase64Url(header); const payloadBase64Url = toBase64Url(payload); const data = `${headerBase64Url}.${payloadBase64Url}`; const signature = crypto.sign(ALGORITHM, data, PRIVATE_KEY); const signatureBase64Url = toBase64Url(signature); const jsonWebToken = `${data}.${signatureBase64Url}`; console.log('Token:', jsonWebToken, '\n'); ////////////////////////////////////////////////// // VERIFY ////////////////////////////////////////////////// const jwtParts = jsonWebToken.split('.'); const jwtHeaderBase64Url = jwtParts[0]; const jwtPayloadBase64Url = jwtParts[1]; const jwtSignatureBase64Url = jwtParts[2]; const jwtHeaderObject = fromBase64Url(jwtHeaderBase64Url, true); const jwtPayloadObject = fromBase64Url(jwtPayloadBase64Url, true); const jwtSignatureBuffer = fromBase64Url(jwtSignatureBase64Url); if (jwtHeaderObject.alg !== header.alg) throw new Error('Invalid algorithm'); const jwtData = `${jwtHeaderBase64Url}.${jwtPayloadBase64Url}`; const isValid = crypto.verify(ALGORITHM, jwtData, PUBLIC_KEY, jwtSignatureBuffer); console.log('Verify:', isValid); // true console.log('Header:', jwtHeaderObject); // { alg: 'PS256', typ: 'JWT' } console.log('Payload:', jwtPayloadObject); // { data: 'Hello World!' } ```

Elliptic Curve Digital Signature Algorithm (ECDSA)

```js import crypto from 'node:crypto'; // Base 64 Encoding with URL and Filename Safe Alphabet. function toBase64Url(data) { if (Buffer.isBuffer(data)) return data.toString('base64url'); if (typeof(data) !== 'string') data = JSON.stringify(data); return toBase64Url(Buffer.from(data)); } function fromBase64Url(data, parseJson) { data = Buffer.from(data, 'base64url'); if (parseJson != null) data = data.toString('utf8'); return parseJson ? JSON.parse(data) : data; } ////////////////////////////////////////////////// // JWT: HEADER & PAYLOAD ////////////////////////////////////////////////// // Elliptic Curve Digital Signature Algorithm (ECDSA) const ALG = 'ES256'; // 'ES256' | 'ES384' | 'ES512' const NAMED_CURVE = 'P-256'; // 'P-256' | 'P-384' | 'P-512' const ALGORITHM = 'SHA256'; // 'SHA256' | 'SHA384' | 'SHA512' const header = { alg: ALG, typ: 'JWT' }; const payload = { data: 'Hello World!' }; ////////////////////////////////////////////////// // KEYS ////////////////////////////////////////////////// const { publicKey, privateKey } = crypto.generateKeyPairSync( 'ec', { namedCurve: NAMED_CURVE, publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, } ); console.log(`publicKey:\n${publicKey}`); ////////////////////////////////////////////////// // SIGN ////////////////////////////////////////////////// const headerBase64Url = toBase64Url(header); const payloadBase64Url = toBase64Url(payload); const data = `${headerBase64Url}.${payloadBase64Url}`; const signature = crypto.sign(ALGORITHM, data, privateKey); const signatureBase64Url = toBase64Url(signature); const jsonWebToken = `${data}.${signatureBase64Url}`; console.log('Token:', jsonWebToken, '\n'); ////////////////////////////////////////////////// // VERIFY ////////////////////////////////////////////////// const jwtParts = jsonWebToken.split('.'); const jwtHeaderBase64Url = jwtParts[0]; const jwtPayloadBase64Url = jwtParts[1]; const jwtSignatureBase64Url = jwtParts[2]; const jwtHeaderObject = fromBase64Url(jwtHeaderBase64Url, true); const jwtPayloadObject = fromBase64Url(jwtPayloadBase64Url, true); const jwtSignatureBuffer = fromBase64Url(jwtSignatureBase64Url); if (jwtHeaderObject.alg !== header.alg) throw new Error('Invalid algorithm'); const jwtData = `${jwtHeaderBase64Url}.${jwtPayloadBase64Url}`; const isValid = crypto.verify(ALGORITHM, jwtData, publicKey, jwtSignatureBuffer); console.log('Verify:', isValid); // true console.log('Header:', jwtHeaderObject); // { alg: 'ES256', typ: 'JWT' } console.log('Payload:', jwtPayloadObject); // { data: 'Hello World!' } ```

Module-Lattice-Based Digital Signature Algorithm (MLDSA)

Node.js v24.7.0. ```js import crypto from 'node:crypto'; // Base 64 Encoding with URL and Filename Safe Alphabet. function toBase64Url(data) { if (Buffer.isBuffer(data)) return data.toString('base64url'); if (typeof(data) !== 'string') data = JSON.stringify(data); return toBase64Url(Buffer.from(data)); } function fromBase64Url(data, parseJson) { data = Buffer.from(data, 'base64url'); if (parseJson != null) data = data.toString('utf8'); return parseJson ? JSON.parse(data) : data; } ////////////////////////////////////////////////// // JWT: HEADER & PAYLOAD ////////////////////////////////////////////////// // Post-Quantum Cryptography (NIST FIPS 204, ML-DSA) // Module-Lattice-Based Digital Signature Algorithm (MLDSA) const ALG = 'MLDSA44'; // 'MLDSA44' | 'MLDSA65' | 'MLDSA87' const KEY_TYPE = 'ml-dsa-44'; // 'ml-dsa-44' | 'ml-dsa-65' | 'ml-dsa-87' const header = { alg: ALG, typ: 'JWT' }; const payload = { data: 'Hello World!' }; ////////////////////////////////////////////////// // KEYS ////////////////////////////////////////////////// const { publicKey, privateKey } = crypto.generateKeyPairSync( KEY_TYPE, { publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, } ); console.log(`publicKey:\n${publicKey}`); ////////////////////////////////////////////////// // SIGN ////////////////////////////////////////////////// const headerBase64Url = toBase64Url(header); const payloadBase64Url = toBase64Url(payload); const data = `${headerBase64Url}.${payloadBase64Url}`; const signature = crypto.sign(null, data, privateKey); const signatureBase64Url = toBase64Url(signature); const jsonWebToken = `${data}.${signatureBase64Url}`; console.log(`Token:\n${jsonWebToken}\n`); ////////////////////////////////////////////////// // VERIFY ////////////////////////////////////////////////// const jwtParts = jsonWebToken.split('.'); const jwtHeaderBase64Url = jwtParts[0]; const jwtPayloadBase64Url = jwtParts[1]; const jwtSignatureBase64Url = jwtParts[2]; const jwtHeaderObject = fromBase64Url(jwtHeaderBase64Url, true); const jwtPayloadObject = fromBase64Url(jwtPayloadBase64Url, true); const jwtSignatureBuffer = fromBase64Url(jwtSignatureBase64Url); if (jwtHeaderObject.alg !== header.alg) throw new Error('Invalid algorithm'); const jwtData = `${jwtHeaderBase64Url}.${jwtPayloadBase64Url}`; const isValid = crypto.verify(null, jwtData, publicKey, jwtSignatureBuffer); console.log('Verify:', isValid); // true console.log('Header:', jwtHeaderObject); // { alg: 'MLDSA44', typ: 'JWT' } console.log('Payload:', jwtPayloadObject); // { data: 'Hello World!' } ```