diff options
| author | Bartek Iwańczuk <biwanczuk@gmail.com> | 2023-02-14 17:38:45 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-14 17:38:45 +0100 |
| commit | d47147fb6ad229b1c039aff9d0959b6e281f4df5 (patch) | |
| tree | 6e9e790f2b9bc71b5f0c9c7e64b95cae31579d58 /ext/node/polyfills/_crypto/crypto_browserify/browserify_aes | |
| parent | 1d00bbe47e2ca14e2d2151518e02b2324461a065 (diff) | |
feat(ext/node): embed std/node into the snapshot (#17724)
This commit moves "deno_std/node" in "ext/node" crate. The code is
transpiled and snapshotted during the build process.
During the first pass a minimal amount of work was done to create the
snapshot, a lot of code in "ext/node" depends on presence of "Deno"
global. This code will be gradually fixed in the follow up PRs to migrate
it to import relevant APIs from "internal:" modules.
Currently the code from snapshot is not used in any way, and all
Node/npm compatibility still uses code from
"https://deno.land/std/node" (or from the location specified by
"DENO_NODE_COMPAT_URL"). This will also be handled in a follow
up PRs.
---------
Co-authored-by: crowlkats <crowlkats@toaxl.com>
Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
Diffstat (limited to 'ext/node/polyfills/_crypto/crypto_browserify/browserify_aes')
17 files changed, 1271 insertions, 0 deletions
diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/aes.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/aes.js new file mode 100644 index 000000000..991b238fe --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/aes.js @@ -0,0 +1,244 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +// based on the aes implimentation in triple sec +// https://github.com/keybase/triplesec +// which is in turn based on the one from crypto-js +// https://code.google.com/p/crypto-js/ + +// deno-lint-ignore-file no-var no-inner-declarations + +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +function asUInt32Array(buf) { + if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf); + + var len = (buf.length / 4) | 0; + var out = new Array(len); + + for (var i = 0; i < len; i++) { + out[i] = buf.readUInt32BE(i * 4); + } + + return out; +} + +function scrubVec(v) { + for (var i = 0; i < v.length; v++) { + v[i] = 0; + } +} + +function cryptBlock(M, keySchedule, SUB_MIX, SBOX, nRounds) { + var SUB_MIX0 = SUB_MIX[0]; + var SUB_MIX1 = SUB_MIX[1]; + var SUB_MIX2 = SUB_MIX[2]; + var SUB_MIX3 = SUB_MIX[3]; + + var s0 = M[0] ^ keySchedule[0]; + var s1 = M[1] ^ keySchedule[1]; + var s2 = M[2] ^ keySchedule[2]; + var s3 = M[3] ^ keySchedule[3]; + var t0, t1, t2, t3; + var ksRow = 4; + + for (var round = 1; round < nRounds; round++) { + t0 = SUB_MIX0[s0 >>> 24] ^ SUB_MIX1[(s1 >>> 16) & 0xff] ^ + SUB_MIX2[(s2 >>> 8) & 0xff] ^ SUB_MIX3[s3 & 0xff] ^ keySchedule[ksRow++]; + t1 = SUB_MIX0[s1 >>> 24] ^ SUB_MIX1[(s2 >>> 16) & 0xff] ^ + SUB_MIX2[(s3 >>> 8) & 0xff] ^ SUB_MIX3[s0 & 0xff] ^ keySchedule[ksRow++]; + t2 = SUB_MIX0[s2 >>> 24] ^ SUB_MIX1[(s3 >>> 16) & 0xff] ^ + SUB_MIX2[(s0 >>> 8) & 0xff] ^ SUB_MIX3[s1 & 0xff] ^ keySchedule[ksRow++]; + t3 = SUB_MIX0[s3 >>> 24] ^ SUB_MIX1[(s0 >>> 16) & 0xff] ^ + SUB_MIX2[(s1 >>> 8) & 0xff] ^ SUB_MIX3[s2 & 0xff] ^ keySchedule[ksRow++]; + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } + + t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | + (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]; + t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | + (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]; + t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | + (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]; + t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | + (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]; + t0 = t0 >>> 0; + t1 = t1 >>> 0; + t2 = t2 >>> 0; + t3 = t3 >>> 0; + + return [t0, t1, t2, t3]; +} + +// AES constants +var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; +var G = (function () { + // Compute double table + var d = new Array(256); + for (var j = 0; j < 256; j++) { + if (j < 128) { + d[j] = j << 1; + } else { + d[j] = (j << 1) ^ 0x11b; + } + } + + var SBOX = []; + var INV_SBOX = []; + var SUB_MIX = [[], [], [], []]; + var INV_SUB_MIX = [[], [], [], []]; + + // Walk GF(2^8) + var x = 0; + var xi = 0; + for (var i = 0; i < 256; ++i) { + // Compute sbox + var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4); + sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63; + SBOX[x] = sx; + INV_SBOX[sx] = x; + + // Compute multiplication + var x2 = d[x]; + var x4 = d[x2]; + var x8 = d[x4]; + + // Compute sub bytes, mix columns tables + var t = (d[sx] * 0x101) ^ (sx * 0x1010100); + SUB_MIX[0][x] = (t << 24) | (t >>> 8); + SUB_MIX[1][x] = (t << 16) | (t >>> 16); + SUB_MIX[2][x] = (t << 8) | (t >>> 24); + SUB_MIX[3][x] = t; + + // Compute inv sub bytes, inv mix columns tables + t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100); + INV_SUB_MIX[0][sx] = (t << 24) | (t >>> 8); + INV_SUB_MIX[1][sx] = (t << 16) | (t >>> 16); + INV_SUB_MIX[2][sx] = (t << 8) | (t >>> 24); + INV_SUB_MIX[3][sx] = t; + + if (x === 0) { + x = xi = 1; + } else { + x = x2 ^ d[d[d[x8 ^ x2]]]; + xi ^= d[d[xi]]; + } + } + + return { + SBOX: SBOX, + INV_SBOX: INV_SBOX, + SUB_MIX: SUB_MIX, + INV_SUB_MIX: INV_SUB_MIX, + }; +})(); + +export function AES(key) { + this._key = asUInt32Array(key); + this._reset(); +} + +AES.blockSize = 4 * 4; +AES.keySize = 256 / 8; +AES.prototype.blockSize = AES.blockSize; +AES.prototype.keySize = AES.keySize; +AES.prototype._reset = function () { + var keyWords = this._key; + var keySize = keyWords.length; + var nRounds = keySize + 6; + var ksRows = (nRounds + 1) * 4; + + var keySchedule = []; + for (var k = 0; k < keySize; k++) { + keySchedule[k] = keyWords[k]; + } + + for (k = keySize; k < ksRows; k++) { + var t = keySchedule[k - 1]; + + if (k % keySize === 0) { + t = (t << 8) | (t >>> 24); + t = (G.SBOX[t >>> 24] << 24) | + (G.SBOX[(t >>> 16) & 0xff] << 16) | + (G.SBOX[(t >>> 8) & 0xff] << 8) | + (G.SBOX[t & 0xff]); + + t ^= RCON[(k / keySize) | 0] << 24; + } else if (keySize > 6 && k % keySize === 4) { + t = (G.SBOX[t >>> 24] << 24) | + (G.SBOX[(t >>> 16) & 0xff] << 16) | + (G.SBOX[(t >>> 8) & 0xff] << 8) | + (G.SBOX[t & 0xff]); + } + + keySchedule[k] = keySchedule[k - keySize] ^ t; + } + + var invKeySchedule = []; + for (var ik = 0; ik < ksRows; ik++) { + var ksR = ksRows - ik; + var tt = keySchedule[ksR - (ik % 4 ? 0 : 4)]; + + if (ik < 4 || ksR <= 4) { + invKeySchedule[ik] = tt; + } else { + invKeySchedule[ik] = G.INV_SUB_MIX[0][G.SBOX[tt >>> 24]] ^ + G.INV_SUB_MIX[1][G.SBOX[(tt >>> 16) & 0xff]] ^ + G.INV_SUB_MIX[2][G.SBOX[(tt >>> 8) & 0xff]] ^ + G.INV_SUB_MIX[3][G.SBOX[tt & 0xff]]; + } + } + + this._nRounds = nRounds; + this._keySchedule = keySchedule; + this._invKeySchedule = invKeySchedule; +}; + +AES.prototype.encryptBlockRaw = function (M) { + M = asUInt32Array(M); + return cryptBlock(M, this._keySchedule, G.SUB_MIX, G.SBOX, this._nRounds); +}; + +AES.prototype.encryptBlock = function (M) { + var out = this.encryptBlockRaw(M); + var buf = Buffer.allocUnsafe(16); + buf.writeUInt32BE(out[0], 0); + buf.writeUInt32BE(out[1], 4); + buf.writeUInt32BE(out[2], 8); + buf.writeUInt32BE(out[3], 12); + return buf; +}; + +AES.prototype.decryptBlock = function (M) { + M = asUInt32Array(M); + + // swap + var m1 = M[1]; + M[1] = M[3]; + M[3] = m1; + + var out = cryptBlock( + M, + this._invKeySchedule, + G.INV_SUB_MIX, + G.INV_SBOX, + this._nRounds, + ); + var buf = Buffer.allocUnsafe(16); + buf.writeUInt32BE(out[0], 0); + buf.writeUInt32BE(out[3], 4); + buf.writeUInt32BE(out[2], 8); + buf.writeUInt32BE(out[1], 12); + return buf; +}; + +AES.prototype.scrub = function () { + scrubVec(this._keySchedule); + scrubVec(this._invKeySchedule); + scrubVec(this._key); +}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/auth_cipher.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/auth_cipher.js new file mode 100644 index 000000000..c4bd5ebe4 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/auth_cipher.js @@ -0,0 +1,146 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +// deno-lint-ignore-file no-var no-inner-declarations + +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; +import * as aes from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/aes.js"; +import Transform from "internal:deno_node/polyfills/_crypto/crypto_browserify/cipher_base.js"; +import { GHASH } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/ghash.js"; +import { xor } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/xor.ts"; +import { incr32 } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/incr32.js"; + +function xorTest(a, b) { + var out = 0; + if (a.length !== b.length) out++; + + var len = Math.min(a.length, b.length); + for (var i = 0; i < len; ++i) { + out += a[i] ^ b[i]; + } + + return out; +} + +function calcIv(self, iv, ck) { + if (iv.length === 12) { + self._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])]); + return Buffer.concat([iv, Buffer.from([0, 0, 0, 2])]); + } + var ghash = new GHASH(ck); + var len = iv.length; + var toPad = len % 16; + ghash.update(iv); + if (toPad) { + toPad = 16 - toPad; + ghash.update(Buffer.alloc(toPad, 0)); + } + ghash.update(Buffer.alloc(8, 0)); + var ivBits = len * 8; + var tail = Buffer.alloc(8); + // Fixed from the original + // https://github.com/crypto-browserify/browserify-aes/issues/58#issuecomment-451778917 + tail.writeUIntBE(ivBits, 2, 6); + ghash.update(tail); + self._finID = ghash.state; + var out = Buffer.from(self._finID); + incr32(out); + return out; +} +export function StreamCipher(mode, key, iv, decrypt) { + Transform.call(this); + + var h = Buffer.alloc(4, 0); + + this._cipher = new aes.AES(key); + var ck = this._cipher.encryptBlock(h); + this._ghash = new GHASH(ck); + iv = calcIv(this, iv, ck); + + this._prev = Buffer.from(iv); + this._cache = Buffer.allocUnsafe(0); + this._secCache = Buffer.allocUnsafe(0); + this._decrypt = decrypt; + this._alen = 0; + this._len = 0; + this._mode = mode; + + this._authTag = null; + this._called = false; +} + +// StreamCipher inherts Transform +StreamCipher.prototype = Object.create(Transform.prototype, { + constructor: { + value: StreamCipher, + enumerable: false, + writable: true, + configurable: true, + }, +}); + +StreamCipher.prototype._update = function (chunk) { + if (!this._called && this._alen) { + var rump = 16 - (this._alen % 16); + if (rump < 16) { + rump = Buffer.alloc(rump, 0); + this._ghash.update(rump); + } + } + + this._called = true; + var out = this._mode.encrypt(this, chunk); + if (this._decrypt) { + this._ghash.update(chunk); + } else { + this._ghash.update(out); + } + this._len += chunk.length; + return out; +}; + +StreamCipher.prototype._final = function () { + if (this._decrypt && !this._authTag) { + throw new Error("Unsupported state or unable to authenticate data"); + } + + var tag = xor( + this._ghash.final(this._alen * 8, this._len * 8), + this._cipher.encryptBlock(this._finID), + ); + if (this._decrypt && xorTest(tag, this._authTag)) { + throw new Error("Unsupported state or unable to authenticate data"); + } + + this._authTag = tag; + this._cipher.scrub(); +}; + +StreamCipher.prototype.getAuthTag = function getAuthTag() { + if (this._decrypt || !Buffer.isBuffer(this._authTag)) { + throw new Error("Attempting to get auth tag in unsupported state"); + } + + return this._authTag; +}; + +StreamCipher.prototype.setAuthTag = function setAuthTag(tag) { + if (!this._decrypt) { + throw new Error("Attempting to set auth tag in unsupported state"); + } + + this._authTag = tag; +}; + +StreamCipher.prototype.setAAD = function setAAD(buf) { + if (this._called) { + throw new Error("Attempting to set AAD in unsupported state"); + } + + this._ghash.update(buf); + this._alen += buf.length; +}; + +export default StreamCipher; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/decrypter.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/decrypter.js new file mode 100644 index 000000000..6a92a4574 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/decrypter.js @@ -0,0 +1,138 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +// deno-lint-ignore-file no-var + +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; +import AuthCipher from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/auth_cipher.js"; +import StreamCipher from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/stream_cipher.js"; +import Transform from "internal:deno_node/polyfills/_crypto/crypto_browserify/cipher_base.js"; +import * as aes from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/aes.js"; +import ebtk from "internal:deno_node/polyfills/_crypto/crypto_browserify/evp_bytes_to_key.ts"; +import { MODES } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/mod.js"; + +function Decipher(mode, key, iv) { + Transform.call(this); + + this._cache = new Splitter(); + this._last = void 0; + this._cipher = new aes.AES(key); + this._prev = Buffer.from(iv); + this._mode = mode; + this._autopadding = true; +} + +Decipher.prototype = Object.create(Transform.prototype, { + constructor: { + value: Decipher, + enumerable: false, + writable: true, + configurable: true, + }, +}); + +Decipher.prototype._update = function (data) { + this._cache.add(data); + var chunk; + var thing; + var out = []; + while ((chunk = this._cache.get(this._autopadding))) { + thing = this._mode.decrypt(this, chunk); + out.push(thing); + } + return Buffer.concat(out); +}; + +Decipher.prototype._final = function () { + var chunk = this._cache.flush(); + if (this._autopadding) { + return unpad(this._mode.decrypt(this, chunk)); + } else if (chunk) { + throw new Error("data not multiple of block length"); + } +}; + +Decipher.prototype.setAutoPadding = function (setTo) { + this._autopadding = !!setTo; + return this; +}; + +function Splitter() { + this.cache = Buffer.allocUnsafe(0); +} + +Splitter.prototype.add = function (data) { + this.cache = Buffer.concat([this.cache, data]); +}; + +Splitter.prototype.get = function (autoPadding) { + var out; + if (autoPadding) { + if (this.cache.length > 16) { + out = this.cache.slice(0, 16); + this.cache = this.cache.slice(16); + return out; + } + } else { + if (this.cache.length >= 16) { + out = this.cache.slice(0, 16); + this.cache = this.cache.slice(16); + return out; + } + } + + return null; +}; + +Splitter.prototype.flush = function () { + if (this.cache.length) return this.cache; +}; + +function unpad(last) { + var padded = last[15]; + if (padded < 1 || padded > 16) { + throw new Error("unable to decrypt data"); + } + var i = -1; + while (++i < padded) { + if (last[i + (16 - padded)] !== padded) { + throw new Error("unable to decrypt data"); + } + } + if (padded === 16) return; + + return last.slice(0, 16 - padded); +} + +export function createDecipheriv(suite, password, iv) { + var config = MODES[suite.toLowerCase()]; + if (!config) throw new TypeError("invalid suite type"); + + if (typeof iv === "string") iv = Buffer.from(iv); + if (config.mode !== "GCM" && iv.length !== config.iv) { + throw new TypeError("invalid iv length " + iv.length); + } + + if (typeof password === "string") password = Buffer.from(password); + if (password.length !== config.key / 8) { + throw new TypeError("invalid key length " + password.length); + } + + if (config.type === "stream") { + return new StreamCipher(config.module, password, iv, true); + } else if (config.type === "auth") { + return new AuthCipher(config.module, password, iv, true); + } + + return new Decipher(config.module, password, iv); +} + +export function createDecipher(suite, password) { + var config = MODES[suite.toLowerCase()]; + if (!config) throw new TypeError("invalid suite type"); + + var keys = ebtk(password, false, config.key, config.iv); + return createDecipheriv(suite, keys.key, keys.iv); +} diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/encrypter.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/encrypter.js new file mode 100644 index 000000000..6a95a719c --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/encrypter.js @@ -0,0 +1,128 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +// deno-lint-ignore-file no-var + +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; +import AuthCipher from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/auth_cipher.js"; +import StreamCipher from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/stream_cipher.js"; +import Transform from "internal:deno_node/polyfills/_crypto/crypto_browserify/cipher_base.js"; +import * as aes from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/aes.js"; +import ebtk from "internal:deno_node/polyfills/_crypto/crypto_browserify/evp_bytes_to_key.ts"; +import { MODES } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/mod.js"; + +function Cipher(mode, key, iv) { + Transform.call(this); + + this._cache = new Splitter(); + this._cipher = new aes.AES(key); + this._prev = Buffer.from(iv); + this._mode = mode; + this._autopadding = true; +} + +Cipher.prototype = Object.create(Transform.prototype, { + constructor: { + value: Cipher, + enumerable: false, + writable: true, + configurable: true, + }, +}); + +Cipher.prototype._update = function (data) { + this._cache.add(data); + var chunk; + var thing; + var out = []; + + while ((chunk = this._cache.get())) { + thing = this._mode.encrypt(this, chunk); + out.push(thing); + } + + return Buffer.concat(out); +}; + +var PADDING = Buffer.alloc(16, 0x10); + +Cipher.prototype._final = function () { + var chunk = this._cache.flush(); + if (this._autopadding) { + chunk = this._mode.encrypt(this, chunk); + this._cipher.scrub(); + return chunk; + } + + if (!chunk.equals(PADDING)) { + this._cipher.scrub(); + throw new Error("data not multiple of block length"); + } +}; + +Cipher.prototype.setAutoPadding = function (setTo) { + this._autopadding = !!setTo; + return this; +}; + +function Splitter() { + this.cache = Buffer.allocUnsafe(0); +} + +Splitter.prototype.add = function (data) { + this.cache = Buffer.concat([this.cache, data]); +}; + +Splitter.prototype.get = function () { + if (this.cache.length > 15) { + const out = this.cache.slice(0, 16); + this.cache = this.cache.slice(16); + return out; + } + return null; +}; + +Splitter.prototype.flush = function () { + var len = 16 - this.cache.length; + var padBuff = Buffer.allocUnsafe(len); + + var i = -1; + while (++i < len) { + padBuff.writeUInt8(len, i); + } + + return Buffer.concat([this.cache, padBuff]); +}; + +export function createCipheriv(suite, password, iv) { + var config = MODES[suite.toLowerCase()]; + if (!config) throw new TypeError("invalid suite type"); + + if (typeof password === "string") password = Buffer.from(password); + if (password.length !== config.key / 8) { + throw new TypeError("invalid key length " + password.length); + } + + if (typeof iv === "string") iv = Buffer.from(iv); + if (config.mode !== "GCM" && iv.length !== config.iv) { + throw new TypeError("invalid iv length " + iv.length); + } + + if (config.type === "stream") { + return new StreamCipher(config.module, password, iv); + } else if (config.type === "auth") { + return new AuthCipher(config.module, password, iv); + } + + return new Cipher(config.module, password, iv); +} + +export function createCipher(suite, password) { + var config = MODES[suite.toLowerCase()]; + if (!config) throw new TypeError("invalid suite type"); + + var keys = ebtk(password, false, config.key, config.iv); + return createCipheriv(suite, keys.key, keys.iv); +} diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/ghash.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/ghash.js new file mode 100644 index 000000000..ac896f921 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/ghash.js @@ -0,0 +1,96 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. +// Copyright 2009-2015, Emily Stark, Mike Hamburg and Dan Boneh at Stanford University. All rights reserved. + +// deno-lint-ignore-file no-var + +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +var ZEROES = Buffer.alloc(16, 0); + +function toArray(buf) { + return [ + buf.readUInt32BE(0), + buf.readUInt32BE(4), + buf.readUInt32BE(8), + buf.readUInt32BE(12), + ]; +} + +function fromArray(out) { + var buf = Buffer.allocUnsafe(16); + buf.writeUInt32BE(out[0] >>> 0, 0); + buf.writeUInt32BE(out[1] >>> 0, 4); + buf.writeUInt32BE(out[2] >>> 0, 8); + buf.writeUInt32BE(out[3] >>> 0, 12); + return buf; +} + +export function GHASH(key) { + this.h = key; + this.state = Buffer.alloc(16, 0); + this.cache = Buffer.allocUnsafe(0); +} + +// from http://bitwiseshiftleft.github.io/sjcl/doc/symbols/src/core_gcm.js.html +// by Juho Vähä-Herttua +GHASH.prototype.ghash = function (block) { + var i = -1; + while (++i < block.length) { + this.state[i] ^= block[i]; + } + this._multiply(); +}; + +GHASH.prototype._multiply = function () { + var Vi = toArray(this.h); + var Zi = [0, 0, 0, 0]; + var j, xi, lsbVi; + var i = -1; + while (++i < 128) { + xi = (this.state[~~(i / 8)] & (1 << (7 - (i % 8)))) !== 0; + if (xi) { + // Z_i+1 = Z_i ^ V_i + Zi[0] ^= Vi[0]; + Zi[1] ^= Vi[1]; + Zi[2] ^= Vi[2]; + Zi[3] ^= Vi[3]; + } + + // Store the value of LSB(V_i) + lsbVi = (Vi[3] & 1) !== 0; + + // V_i+1 = V_i >> 1 + for (j = 3; j > 0; j--) { + Vi[j] = (Vi[j] >>> 1) | ((Vi[j - 1] & 1) << 31); + } + Vi[0] = Vi[0] >>> 1; + + // If LSB(V_i) is 1, V_i+1 = (V_i >> 1) ^ R + if (lsbVi) { + Vi[0] = Vi[0] ^ (0xe1 << 24); + } + } + this.state = fromArray(Zi); +}; + +GHASH.prototype.update = function (buf) { + this.cache = Buffer.concat([this.cache, buf]); + var chunk; + while (this.cache.length >= 16) { + chunk = this.cache.slice(0, 16); + this.cache = this.cache.slice(16); + this.ghash(chunk); + } +}; + +GHASH.prototype.final = function (abl, bl) { + if (this.cache.length) { + this.ghash(Buffer.concat([this.cache, ZEROES], 16)); + } + + this.ghash(fromArray([0, abl, 0, bl])); + return this.state; +}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/incr32.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/incr32.js new file mode 100644 index 000000000..65172eefb --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/incr32.js @@ -0,0 +1,19 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +export function incr32(iv) { + let len = iv.length; + let item; + while (len--) { + item = iv.readUInt8(len); + if (item === 255) { + iv.writeUInt8(0, len); + } else { + item++; + iv.writeUInt8(item, len); + break; + } + } +} diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/mod.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/mod.js new file mode 100644 index 000000000..abf5bde5f --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/mod.js @@ -0,0 +1,13 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +import { MODES } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/mod.js"; + +export * from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/encrypter.js"; +export * from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/decrypter.js"; + +export function getCiphers() { + return Object.keys(MODES); +} diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cbc.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cbc.js new file mode 100644 index 000000000..837adf32f --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cbc.js @@ -0,0 +1,22 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +import { xor } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/xor.ts"; + +export const encrypt = function (self, block) { + const data = xor(block, self._prev); + + self._prev = self._cipher.encryptBlock(data); + return self._prev; +}; + +export const decrypt = function (self, block) { + const pad = self._prev; + + self._prev = block; + const out = self._cipher.decryptBlock(block); + + return xor(out, pad); +}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb.js new file mode 100644 index 000000000..8bfd81463 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb.js @@ -0,0 +1,41 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +import { xor } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/xor.ts"; +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +function encryptStart(self, data, decrypt) { + const len = data.length; + const out = xor(data, self._cache); + self._cache = self._cache.slice(len); + self._prev = Buffer.concat([self._prev, decrypt ? data : out]); + return out; +} + +export const encrypt = function (self, data, decrypt) { + let out = Buffer.allocUnsafe(0); + let len; + + while (data.length) { + if (self._cache.length === 0) { + self._cache = self._cipher.encryptBlock(self._prev); + self._prev = Buffer.allocUnsafe(0); + } + + if (self._cache.length <= data.length) { + len = self._cache.length; + out = Buffer.concat([ + out, + encryptStart(self, data.slice(0, len), decrypt), + ]); + data = data.slice(len); + } else { + out = Buffer.concat([out, encryptStart(self, data, decrypt)]); + break; + } + } + + return out; +}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb1.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb1.js new file mode 100644 index 000000000..2af8824f0 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb1.js @@ -0,0 +1,47 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +function encryptByte(self, byteParam, decrypt) { + let pad; + let i = -1; + const len = 8; + let out = 0; + let bit, value; + while (++i < len) { + pad = self._cipher.encryptBlock(self._prev); + bit = (byteParam & (1 << (7 - i))) ? 0x80 : 0; + value = pad[0] ^ bit; + out += (value & 0x80) >> (i % 8); + self._prev = shiftIn(self._prev, decrypt ? bit : value); + } + return out; +} + +function shiftIn(buffer, value) { + const len = buffer.length; + let i = -1; + const out = Buffer.allocUnsafe(buffer.length); + buffer = Buffer.concat([buffer, Buffer.from([value])]); + + while (++i < len) { + out[i] = buffer[i] << 1 | buffer[i + 1] >> (7); + } + + return out; +} + +export const encrypt = function (self, chunk, decrypt) { + const len = chunk.length; + const out = Buffer.allocUnsafe(len); + let i = -1; + + while (++i < len) { + out[i] = encryptByte(self, chunk[i], decrypt); + } + + return out; +}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb8.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb8.js new file mode 100644 index 000000000..262494a81 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb8.js @@ -0,0 +1,30 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +function encryptByte(self, byteParam, decrypt) { + const pad = self._cipher.encryptBlock(self._prev); + const out = pad[0] ^ byteParam; + + self._prev = Buffer.concat([ + self._prev.slice(1), + Buffer.from([decrypt ? byteParam : out]), + ]); + + return out; +} + +export const encrypt = function (self, chunk, decrypt) { + const len = chunk.length; + const out = Buffer.allocUnsafe(len); + let i = -1; + + while (++i < len) { + out[i] = encryptByte(self, chunk[i], decrypt); + } + + return out; +}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ctr.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ctr.js new file mode 100644 index 000000000..fd1781ab2 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ctr.js @@ -0,0 +1,35 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +import { xor } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/xor.ts"; +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; +import { incr32 } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/incr32.js"; + +function getBlock(self) { + const out = self._cipher.encryptBlockRaw(self._prev); + incr32(self._prev); + return out; +} + +const blockSize = 16; +export const encrypt = function (self, chunk) { + const chunkNum = Math.ceil(chunk.length / blockSize); + const start = self._cache.length; + self._cache = Buffer.concat([ + self._cache, + Buffer.allocUnsafe(chunkNum * blockSize), + ]); + for (let i = 0; i < chunkNum; i++) { + const out = getBlock(self); + const offset = start + i * blockSize; + self._cache.writeUInt32BE(out[0], offset + 0); + self._cache.writeUInt32BE(out[1], offset + 4); + self._cache.writeUInt32BE(out[2], offset + 8); + self._cache.writeUInt32BE(out[3], offset + 12); + } + const pad = self._cache.slice(0, chunk.length); + self._cache = self._cache.slice(chunk.length); + return xor(chunk, pad); +}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ecb.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ecb.js new file mode 100644 index 000000000..b4f99cffb --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ecb.js @@ -0,0 +1,12 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +export const encrypt = function (self, block) { + return self._cipher.encryptBlock(block); +}; + +export const decrypt = function (self, block) { + return self._cipher.decryptBlock(block); +}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/mod.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/mod.js new file mode 100644 index 000000000..b30ed0b25 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/mod.js @@ -0,0 +1,221 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +import * as ECB from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ecb.js"; +import * as CBC from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cbc.js"; +import * as CFB from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb.js"; +import * as CFB8 from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb8.js"; +import * as CFB1 from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/cfb1.js"; +import * as OFB from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ofb.js"; +import * as CTR from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ctr.js"; + +const GCM = CTR; + +const modeModules = { + ECB, + CBC, + CFB, + CFB8, + CFB1, + OFB, + CTR, + GCM, +}; + +export const MODES = { + "aes-128-ecb": { + "cipher": "AES", + "key": 128, + "iv": 0, + "mode": "ECB", + "type": "block", + }, + "aes-192-ecb": { + "cipher": "AES", + "key": 192, + "iv": 0, + "mode": "ECB", + "type": "block", + }, + "aes-256-ecb": { + "cipher": "AES", + "key": 256, + "iv": 0, + "mode": "ECB", + "type": "block", + }, + "aes-128-cbc": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CBC", + "type": "block", + }, + "aes-192-cbc": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CBC", + "type": "block", + }, + "aes-256-cbc": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CBC", + "type": "block", + }, + "aes128": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CBC", + "type": "block", + }, + "aes192": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CBC", + "type": "block", + }, + "aes256": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CBC", + "type": "block", + }, + "aes-128-cfb": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CFB", + "type": "stream", + }, + "aes-192-cfb": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CFB", + "type": "stream", + }, + "aes-256-cfb": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CFB", + "type": "stream", + }, + "aes-128-cfb8": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CFB8", + "type": "stream", + }, + "aes-192-cfb8": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CFB8", + "type": "stream", + }, + "aes-256-cfb8": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CFB8", + "type": "stream", + }, + "aes-128-cfb1": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CFB1", + "type": "stream", + }, + "aes-192-cfb1": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CFB1", + "type": "stream", + }, + "aes-256-cfb1": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CFB1", + "type": "stream", + }, + "aes-128-ofb": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "OFB", + "type": "stream", + }, + "aes-192-ofb": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "OFB", + "type": "stream", + }, + "aes-256-ofb": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "OFB", + "type": "stream", + }, + "aes-128-ctr": { + "cipher": "AES", + "key": 128, + "iv": 16, + "mode": "CTR", + "type": "stream", + }, + "aes-192-ctr": { + "cipher": "AES", + "key": 192, + "iv": 16, + "mode": "CTR", + "type": "stream", + }, + "aes-256-ctr": { + "cipher": "AES", + "key": 256, + "iv": 16, + "mode": "CTR", + "type": "stream", + }, + "aes-128-gcm": { + "cipher": "AES", + "key": 128, + "iv": 12, + "mode": "GCM", + "type": "auth", + }, + "aes-192-gcm": { + "cipher": "AES", + "key": 192, + "iv": 12, + "mode": "GCM", + "type": "auth", + }, + "aes-256-gcm": { + "cipher": "AES", + "key": 256, + "iv": 12, + "mode": "GCM", + "type": "auth", + }, +}; + +for (const mode of Object.values(MODES)) { + mode.module = modeModules[mode.mode]; +} diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ofb.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ofb.js new file mode 100644 index 000000000..20ccdf015 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/modes/ofb.js @@ -0,0 +1,22 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +import { xor } from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/xor.ts"; +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +function getBlock(self) { + self._prev = self._cipher.encryptBlock(self._prev); + return self._prev; +} + +export const encrypt = function (self, chunk) { + while (self._cache.length < chunk.length) { + self._cache = Buffer.concat([self._cache, getBlock(self)]); + } + + const pad = self._cache.slice(0, chunk.length); + self._cache = self._cache.slice(chunk.length); + return xor(chunk, pad); +}; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/stream_cipher.js b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/stream_cipher.js new file mode 100644 index 000000000..432730f91 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/stream_cipher.js @@ -0,0 +1,40 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +import * as aes from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_aes/aes.js"; +import Transform from "internal:deno_node/polyfills/_crypto/crypto_browserify/cipher_base.js"; + +export function StreamCipher(mode, key, iv, decrypt) { + Transform.call(this); + + this._cipher = new aes.AES(key); + this._prev = Buffer.from(iv); + this._cache = Buffer.allocUnsafe(0); + this._secCache = Buffer.allocUnsafe(0); + this._decrypt = decrypt; + this._mode = mode; +} + +// StreamCipher inherits Transform +StreamCipher.prototype = Object.create(Transform.prototype, { + constructor: { + value: StreamCipher, + enumerable: false, + writable: true, + configurable: true, + }, +}); + +StreamCipher.prototype._update = function (chunk) { + return this._mode.encrypt(this, chunk, this._decrypt); +}; + +StreamCipher.prototype._final = function () { + this._cipher.scrub(); +}; + +export default StreamCipher; diff --git a/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/xor.ts b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/xor.ts new file mode 100644 index 000000000..6b9327ebc --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/browserify_aes/xor.ts @@ -0,0 +1,17 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2014-2017 browserify-aes contributors. All rights reserved. MIT license. +// Copyright 2013 Maxwell Krohn. All rights reserved. MIT license. +// Copyright 2009-2013 Jeff Mott. All rights reserved. MIT license. + +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +export function xor(a: Buffer, b: Buffer): Buffer { + const length = Math.min(a.length, b.length); + const buffer = Buffer.allocUnsafe(length); + + for (let i = 0; i < length; ++i) { + buffer[i] = a[i] ^ b[i]; + } + + return buffer; +} |
