text: // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
  // Copyright 2017 Calvin Metcalf. All rights reserved. MIT license.
  
  import parseKeys from "../parse_asn1/mod.js";
  import { createHash } from "../../hash.ts";
  import mgf from "./mgf.js";
  import { xor } from "./xor.js";
  import { BN } from "../bn.js/bn.js";
  import { withPublic } from "./with_public.js";
  import crt from "../browserify_rsa.js";
  import { Buffer } from "../../../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;
  }
  