diff options
Diffstat (limited to 'ext/node/polyfills/_crypto/crypto_browserify/public_encrypt')
6 files changed, 278 insertions, 0 deletions
diff --git a/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/mgf.js b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/mgf.js new file mode 100644 index 000000000..5bb41f896 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/mgf.js @@ -0,0 +1,22 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2017 Calvin Metcalf. All rights reserved. MIT license. + +import { createHash } from "internal:deno_node/polyfills/internal/crypto/hash.ts"; +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +export default function (seed, len) { + let t = Buffer.alloc(0); + let i = 0; + let c; + while (t.length < len) { + c = i2ops(i++); + t = Buffer.concat([t, createHash("sha1").update(seed).update(c).digest()]); + } + return t.slice(0, len); +} + +function i2ops(c) { + const out = Buffer.allocUnsafe(4); + out.writeUInt32BE(c, 0); + return out; +} diff --git a/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/mod.js b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/mod.js new file mode 100644 index 000000000..a91197aef --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/mod.js @@ -0,0 +1,15 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2017 Calvin Metcalf. All rights reserved. MIT license. + +import { publicEncrypt } from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/public_encrypt.js"; +import { privateDecrypt } from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/private_decrypt.js"; + +export { privateDecrypt, publicEncrypt }; + +export function privateEncrypt(key, buf) { + return publicEncrypt(key, buf, true); +} + +export function publicDecrypt(key, buf) { + return privateDecrypt(key, buf, true); +} diff --git a/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/private_decrypt.js b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/private_decrypt.js new file mode 100644 index 000000000..9b485b3db --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/private_decrypt.js @@ -0,0 +1,111 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2017 Calvin Metcalf. All rights reserved. MIT license. + +import parseKeys from "internal:deno_node/polyfills/_crypto/crypto_browserify/parse_asn1/mod.js"; +import { createHash } from "internal:deno_node/polyfills/internal/crypto/hash.ts"; +import mgf from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/mgf.js"; +import { xor } from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/xor.js"; +import { BN } from "internal:deno_node/polyfills/_crypto/crypto_browserify/bn.js/bn.js"; +import { withPublic } from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/with_public.js"; +import crt from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_rsa.js"; +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +export function privateDecrypt(privateKey, enc, reverse) { + let padding; + if (privateKey.padding) { + padding = privateKey.padding; + } else if (reverse) { + padding = 1; + } else { + padding = 4; + } + + const key = parseKeys(privateKey); + const k = key.modulus.byteLength(); + if (enc.length > k || new BN(enc).cmp(key.modulus) >= 0) { + throw new Error("decryption error"); + } + let msg; + if (reverse) { + msg = withPublic(new BN(enc), key); + } else { + msg = crt(enc, key); + } + const zBuffer = Buffer.alloc(k - msg.length); + msg = Buffer.concat([zBuffer, msg], k); + if (padding === 4) { + return oaep(key, msg); + } else if (padding === 1) { + return pkcs1(key, msg, reverse); + } else if (padding === 3) { + return msg; + } else { + throw new Error("unknown padding"); + } +} + +function oaep(key, msg) { + const k = key.modulus.byteLength(); + const iHash = createHash("sha1").update(Buffer.alloc(0)).digest(); + const hLen = iHash.length; + if (msg[0] !== 0) { + throw new Error("decryption error"); + } + const maskedSeed = msg.slice(1, hLen + 1); + const maskedDb = msg.slice(hLen + 1); + const seed = xor(maskedSeed, mgf(maskedDb, hLen)); + const db = xor(maskedDb, mgf(seed, k - hLen - 1)); + if (compare(iHash, db.slice(0, hLen))) { + throw new Error("decryption error"); + } + let i = hLen; + while (db[i] === 0) { + i++; + } + if (db[i++] !== 1) { + throw new Error("decryption error"); + } + return db.slice(i); +} + +function pkcs1(_key, msg, reverse) { + const p1 = msg.slice(0, 2); + let i = 2; + let status = 0; + while (msg[i++] !== 0) { + if (i >= msg.length) { + status++; + break; + } + } + const ps = msg.slice(2, i - 1); + + if ( + (p1.toString("hex") !== "0002" && !reverse) || + (p1.toString("hex") !== "0001" && reverse) + ) { + status++; + } + if (ps.length < 8) { + status++; + } + if (status) { + throw new Error("decryption error"); + } + return msg.slice(i); +} +function compare(a, b) { + a = Buffer.from(a); + b = Buffer.from(b); + let dif = 0; + let len = a.length; + if (a.length !== b.length) { + dif++; + len = Math.min(a.length, b.length); + } + let i = -1; + while (++i < len) { + dif += a[i] ^ b[i]; + } + return dif; +} diff --git a/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/public_encrypt.js b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/public_encrypt.js new file mode 100644 index 000000000..9642128ba --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/public_encrypt.js @@ -0,0 +1,104 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2017 Calvin Metcalf. All rights reserved. MIT license. + +import parseKeys from "internal:deno_node/polyfills/_crypto/crypto_browserify/parse_asn1/mod.js"; +import { randomBytes } from "internal:deno_node/polyfills/_crypto/crypto_browserify/randombytes.ts"; +import { createHash } from "internal:deno_node/polyfills/internal/crypto/hash.ts"; +import mgf from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/mgf.js"; +import { xor } from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/xor.js"; +import { BN } from "internal:deno_node/polyfills/_crypto/crypto_browserify/bn.js/bn.js"; +import { withPublic } from "internal:deno_node/polyfills/_crypto/crypto_browserify/public_encrypt/with_public.js"; +import crt from "internal:deno_node/polyfills/_crypto/crypto_browserify/browserify_rsa.js"; +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +export function publicEncrypt(publicKey, msg, reverse) { + let padding; + if (publicKey.padding) { + padding = publicKey.padding; + } else if (reverse) { + padding = 1; + } else { + padding = 4; + } + const key = parseKeys(publicKey); + let paddedMsg; + if (padding === 4) { + paddedMsg = oaep(key, msg); + } else if (padding === 1) { + paddedMsg = pkcs1(key, msg, reverse); + } else if (padding === 3) { + paddedMsg = new BN(msg); + if (paddedMsg.cmp(key.modulus) >= 0) { + throw new Error("data too long for modulus"); + } + } else { + throw new Error("unknown padding"); + } + if (reverse) { + return crt(paddedMsg, key); + } else { + return withPublic(paddedMsg, key); + } +} + +function oaep(key, msg) { + const k = key.modulus.byteLength(); + const mLen = msg.length; + const iHash = createHash("sha1").update(Buffer.alloc(0)).digest(); + const hLen = iHash.length; + const hLen2 = 2 * hLen; + if (mLen > k - hLen2 - 2) { + throw new Error("message too long"); + } + const ps = Buffer.alloc(k - mLen - hLen2 - 2); + const dblen = k - hLen - 1; + const seed = randomBytes(hLen); + const maskedDb = xor( + Buffer.concat([iHash, ps, Buffer.alloc(1, 1), msg], dblen), + mgf(seed, dblen), + ); + const maskedSeed = xor(seed, mgf(maskedDb, hLen)); + return new BN(Buffer.concat([Buffer.alloc(1), maskedSeed, maskedDb], k)); +} +function pkcs1(key, msg, reverse) { + const mLen = msg.length; + const k = key.modulus.byteLength(); + if (mLen > k - 11) { + throw new Error("message too long"); + } + let ps; + if (reverse) { + ps = Buffer.alloc(k - mLen - 3, 0xff); + } else { + ps = nonZero(k - mLen - 3); + } + return new BN( + Buffer.concat([ + Buffer.from([ + 0, + reverse ? 1 : 2, + ]), + ps, + Buffer.alloc(1), + msg, + ], k), + ); +} +function nonZero(len) { + const out = Buffer.allocUnsafe(len); + let i = 0; + let cache = randomBytes(len * 2); + let cur = 0; + let num; + while (i < len) { + if (cur === cache.length) { + cache = randomBytes(len * 2); + cur = 0; + } + num = cache[cur++]; + if (num) { + out[i++] = num; + } + } + return out; +} diff --git a/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/with_public.js b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/with_public.js new file mode 100644 index 000000000..5e94c7bc9 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/with_public.js @@ -0,0 +1,15 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2017 Calvin Metcalf. All rights reserved. MIT license. + +import { BN } from "internal:deno_node/polyfills/_crypto/crypto_browserify/bn.js/bn.js"; +import { Buffer } from "internal:deno_node/polyfills/buffer.ts"; + +export function withPublic(paddedMsg, key) { + return Buffer.from( + paddedMsg + .toRed(BN.mont(key.modulus)) + .redPow(new BN(key.publicExponent)) + .fromRed() + .toArray(), + ); +} diff --git a/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/xor.js b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/xor.js new file mode 100644 index 000000000..25c4b8a40 --- /dev/null +++ b/ext/node/polyfills/_crypto/crypto_browserify/public_encrypt/xor.js @@ -0,0 +1,11 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. +// Copyright 2017 Calvin Metcalf. All rights reserved. MIT license. + +export function xor(a, b) { + const len = a.length; + let i = -1; + while (++i < len) { + a[i] ^= b[i]; + } + return a; +} |