Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 1x 1x 7x 7x 7x 7x 7x 7x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 100000x 100000x 100000x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 99999x 99999x 6399936x 1x 1x 1x 1x 8x 8x 1x 7x | import { getCryptoLib } from './cryptoUtils' export type Pbkdf2Digests = 'sha512' | 'sha256' export interface Pbkdf2 { derive( password: string, salt: Buffer, iterations: number, keyLength: number, digest: Pbkdf2Digests): Promise<Buffer>; } type NodePbkdf2Fn = typeof import('crypto').pbkdf2 export class NodeCryptoPbkdf2 implements Pbkdf2 { nodePbkdf2: NodePbkdf2Fn constructor(nodePbkdf2: NodePbkdf2Fn) { this.nodePbkdf2 = nodePbkdf2 } async derive( password: string, salt: Buffer, iterations: number, keyLength: number, digest: Pbkdf2Digests): Promise<Buffer> { Iif (digest !== 'sha512' && digest !== 'sha256') { throw new Error(`Unsupported digest "${digest}" for Pbkdf2`) } return new Promise((resolve, reject) => { this.nodePbkdf2(password, salt, iterations, keyLength, digest, (error, result) => { Iif (error) { reject(error) } resolve(result) }) }) } } export class WebCryptoPbkdf2 implements Pbkdf2 { subtleCrypto: SubtleCrypto constructor(subtleCrypto: SubtleCrypto) { this.subtleCrypto = subtleCrypto } async derive( password: string, salt: Buffer, iterations: number, keyLength: number, digest: Pbkdf2Digests): Promise<Buffer> { let algo: string Iif (digest === 'sha256') { algo = 'SHA-256' } else Eif (digest === 'sha512') { algo = 'SHA-512' } else { throw new Error(`Unsupported Pbkdf2 digest algorithm "${digest}"`) } let result: ArrayBuffer const passwordBytes = Buffer.from(password, 'utf8') try { const key = await this.subtleCrypto.importKey( 'raw', passwordBytes, 'PBKDF2', false, ['deriveBits'] ) result = await this.subtleCrypto.deriveBits({ name: 'PBKDF2', salt, iterations, hash: { name: algo } }, key, keyLength * 8) } catch (error) { // Browser appears to support WebCrypto but missing pbkdf2 support. const partialWebCrypto = new WebCryptoPartialPbkdf2(this.subtleCrypto) return partialWebCrypto.derive(password, salt, iterations, keyLength, digest) } return Buffer.from(result) } } export class WebCryptoPartialPbkdf2 implements Pbkdf2 { // An async implementation for browsers that support WebCrypto hmac // but not pbkdf2. Extracted from crypto-browserify/pbkdf2 and modified to // use WebCrypto for hmac operations. // Original: https://github.com/crypto-browserify/pbkdf2/tree/v3.0.17/lib subtleCrypto: SubtleCrypto constructor(subtleCrypto: SubtleCrypto) { this.subtleCrypto = subtleCrypto } async derive( password: string, salt: Buffer, iterations: number, keyLength: number, digest: Pbkdf2Digests): Promise<Buffer> { Iif (digest !== 'sha512' && digest !== 'sha256') { throw new Error(`Unsupported digest "${digest}" for Pbkdf2`) } const key = Buffer.from(password, 'utf8') const algo = digest === 'sha512' ? 'SHA-512' : 'SHA-256' const algoOpts = { name: 'HMAC', hash: algo } const hmacDigest = (key: ArrayBuffer, data: ArrayBuffer) => this.subtleCrypto .importKey('raw', key, algoOpts, true, ['sign']) .then(cryptoKey => this.subtleCrypto.sign(algoOpts, cryptoKey, data)) .then(result => new Uint8Array(result)) const DK = new Uint8Array(keyLength) const saltLength = salt.length const block1 = new Uint8Array(saltLength + 4) block1.set(salt) let destPos = 0 const hLen = digest === 'sha512' ? 64 : 32 const l = Math.ceil(keyLength / hLen) function writeUInt32BE(data: Uint8Array, value: number, offset: number) { value = +value offset >>>= 0 data[offset] = (value >>> 24) data[offset + 1] = (value >>> 16) data[offset + 2] = (value >>> 8) data[offset + 3] = (value & 0xff) return offset + 4 } for (let i = 1; i <= l; i++) { writeUInt32BE(block1, i, saltLength) // eslint-disable-next-line no-await-in-loop const T = await hmacDigest(key, block1) let U = T for (let j = 1; j < iterations; j++) { // eslint-disable-next-line no-await-in-loop U = await hmacDigest(key, U) for (let k = 0; k < hLen; k++) { T[k] ^= U[k] } } DK.set(T.subarray(0, DK.byteLength - destPos), destPos) destPos += hLen } return Buffer.from(DK.buffer) } } export async function createPbkdf2(): Promise<Pbkdf2> { const cryptoLib = await getCryptoLib() if (cryptoLib.name === 'subtleCrypto') { return new WebCryptoPbkdf2(cryptoLib.lib) } else { return new NodeCryptoPbkdf2(cryptoLib.lib.pbkdf2) } } |