vendor: 5,271 bytes, lines 1-179
1(function() { 2 "use strict"; 3 function bufferStartsWith(buffer, prefix) { 4 if (prefix.length > buffer.length) { 5 return false; 6 } 7 for (let i = 0; i < prefix.length; i++) { 8 if (buffer[i] !== prefix[i]) { 9 return false; 10 } 11 } 12 return true; 13 } 14 function bufferToHex(buffer) { 15 return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join(""); 16 } 17 function concatBuffers(a, b) { 18 const out = new Uint8Array(a.length + b.length); 19 out.set(a, 0); 20 out.set(b, a.length); 21 return out; 22 } 23 function hexToBuffer(hex) { 24 if (hex.length % 2 !== 0) { 25 throw new Error(`Hex string must have an even length. Got: ${hex}`); 26 } 27 const buffer = new ArrayBuffer(hex.length / 2); 28 const view = new DataView(buffer); 29 for (let i = 0; i < hex.length; i += 2) { 30 const byteString = hex.substring(i, i + 2); 31 const byteValue = parseInt(byteString, 16); 32 view.setUint8(i / 2, byteValue); 33 } 34 return new Uint8Array(buffer); 35 } 36 async function delay(ms) { 37 await new Promise((resolve) => setTimeout(resolve, ms)); 38 } 39 function timeDuration(start) { 40 return Math.floor((performance.now() - start) * 10) / 10; 41 } 42 class PasswordBuffer { 43 constructor(nonce, mode = "uint32") { 44 this.nonce = nonce; 45 this.mode = mode; 46 this.buffer = new Uint8Array(this.nonce.length + this.COUNTER_BYTES); 47 this.buffer.set(this.nonce, 0); 48 this.dataView = new DataView(this.buffer.buffer); 49 } 50 COUNTER_BYTES = 4; 51 buffer; 52 dataView; 53 encoder = new TextEncoder(); 54 /** 55 * Appends the counter to the nonce buffer. 56 * In 'string' mode, encodes the counter as a UTF-8 string. 57 * In 'uint32' mode, writes the counter as a big-endian 32-bit integer. 58 */ 59 setCounter(n) { 60 if (this.mode === "string") { 61 return concatBuffers(this.nonce, this.encoder.encode(n.toString())); 62 } 63 this.dataView.setUint32(this.nonce.length, n, false); 64 return this.buffer; 65 } 66 } 67 async function solveChallenge(options) { 68 const { 69 challenge, 70 controller, 71 counterMode = "uint32", 72 counterStart = 0, 73 counterStep = 1, 74 deriveKey: deriveKey2, 75 timeout = 9e4 76 } = options; 77 const { nonce, keyPrefix, salt } = challenge.parameters; 78 const nonceBuf = hexToBuffer(nonce); 79 const saltBuf = hexToBuffer(salt); 80 const keyPrefixBuf = keyPrefix.length % 2 === 0 ? hexToBuffer(keyPrefix) : null; 81 const password = new PasswordBuffer(nonceBuf, counterMode); 82 const start = performance.now(); 83 let counter = counterStart; 84 let iterations = 0; 85 let derivedKeyHex = ""; 86 let lastYield = start; 87 while (true) { 88 if (controller?.signal.aborted || timeout && iterations % 10 === 0 && performance.now() - start > timeout) { 89 return null; 90 } 91 const { derivedKey } = await deriveKey2( 92 challenge.parameters, 93 saltBuf, 94 password.setCounter(counter) 95 ); 96 if (iterations % 10 === 0 && performance.now() - lastYield > 200) { 97 await delay(0); 98 lastYield = performance.now(); 99 } 100 if (keyPrefixBuf ? bufferStartsWith(derivedKey, keyPrefixBuf) : bufferToHex(derivedKey).startsWith(keyPrefix)) { 101 derivedKeyHex = bufferToHex(derivedKey); 102 break; 103 } 104 counter = counter + counterStep; 105 iterations = iterations + 1; 106 } 107 return { 108 counter, 109 derivedKey: derivedKeyHex, 110 time: timeDuration(start) 111 }; 112 } 113 function handler(options) { 114 const { deriveKey: deriveKey2 } = options; 115 let controller = void 0; 116 self.onmessage = async (message) => { 117 const { challenge, counterMode, counterStart, counterStep, timeout, type } = message.data; 118 if (type === "abort") { 119 controller?.abort(); 120 } else if (type === "work") { 121 controller = new AbortController(); 122 let solution; 123 try { 124 solution = await solveChallenge({ 125 challenge, 126 controller, 127 counterStart, 128 counterStep, 129 deriveKey: deriveKey2, 130 counterMode, 131 timeout 132 }); 133 } catch (err) { 134 return self.postMessage({ error: err }); 135 } 136 self.postMessage(solution); 137 } 138 }; 139 } 140 function getDigest(algorithm) { 141 switch (algorithm) { 142 case "PBKDF2/SHA-512": 143 return "SHA-512"; 144 case "PBKDF2/SHA-384": 145 return "SHA-384"; 146 case "PBKDF2/SHA-256": 147 default: 148 return "SHA-256"; 149 } 150 } 151 async function deriveKey(parameters, salt, password) { 152 const { algorithm, cost, keyLength = 32 } = parameters; 153 const passwordKey = await crypto.subtle.importKey( 154 "raw", 155 password, 156 { name: "PBKDF2" }, 157 false, 158 ["deriveKey"] 159 ); 160 const derivedKey = await crypto.subtle.deriveKey( 161 { 162 name: "PBKDF2", 163 salt, 164 iterations: cost, 165 hash: getDigest(algorithm) 166 }, 167 passwordKey, 168 { name: "AES-GCM", length: keyLength * 8 }, 169 true, 170 ["encrypt"] 171 ); 172 return { 173 derivedKey: new Uint8Array(await crypto.subtle.exportKey("raw", derivedKey)) 174 }; 175 } 176 handler({ 177 deriveKey 178 }); 179})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.