/// <reference types="node" />

declare module "node-forge" {
    type Byte = number;
    type Bytes = string;
    type Hex = string;
    type Base64 = string;
    type Utf8 = string;
    type OID = string;
    type Encoding = "raw" | "utf8";

    namespace jsbn {
        interface RandomGenerator {
            nextBytes(bytes: number[]): void;
        }
        class BigInteger {
            static ZERO: BigInteger;
            static ONE: BigInteger;
            constructor(a: null);
            constructor(a: number, c: RandomGenerator);
            constructor(a: number, b: number, c: RandomGenerator);
            constructor(a: string, b?: number);
            constructor(a: number[], b?: number);
            constructor(a: BigInteger);
            data: number[];
            t: number;
            s: number;
            am(i: number, x: number, w: BigInteger, j: number, c: number, n: number): number;
            toString(b?: number): string;
            bitLength(): number;
            negate(): BigInteger;
            abs(): BigInteger;
            compareTo(a: BigInteger): number;
            bitLength(): number;
            mod(a: BigInteger): BigInteger;
            modPowInt(e: number, m: BigInteger): BigInteger;
            clone(): BigInteger;
            intValue(): number;
            byteValue(): number;
            shortValue(): number;
            signum(): number;
            toByteArray(): number[];
            equals(a: BigInteger): boolean;
            min(a: BigInteger): BigInteger;
            max(a: BigInteger): BigInteger;
            and(a: BigInteger): BigInteger;
            or(a: BigInteger): BigInteger;
            xor(a: BigInteger): BigInteger;
            andNot(a: BigInteger): BigInteger;
            not(): BigInteger;
            shiftLeft(n: number): BigInteger;
            shiftRight(n: number): BigInteger;
            getLowestSetBit(): number;
            bitCount(): number;
            testBit(n: number): boolean;
            clearBit(n: number): BigInteger;
            flipBit(n: number): BigInteger;
            add(a: BigInteger): BigInteger;
            subtract(a: BigInteger): BigInteger;
            multiply(a: BigInteger): BigInteger;
            squareTo(a: BigInteger): BigInteger;
            divide(a: BigInteger): BigInteger;
            remainder(a: BigInteger): BigInteger;
            divideAndRemainder(a: BigInteger): BigInteger[]; // Array of 2 items
            pow(e: number): BigInteger;
            modPow(e: BigInteger, m: BigInteger): BigInteger;
            gcd(a: BigInteger): BigInteger;
            modInverse(m: BigInteger): BigInteger;
            isProbablePrime(t: number): boolean;
        }
    }

    namespace rc2 {
        type pad_function = (blockSize: number, buffer: util.ByteBuffer, decrypt: boolean) => boolean;
        interface cipher {
            start(iv: util.ByteBuffer | string | null, output?: util.ByteBuffer): void;
            update(input: util.ByteBuffer): void;
            finish(pad?: pad_function): boolean;
            output: util.ByteBuffer;
        }

        function expandKey(key: string | util.ByteBuffer, effKeyBits?: number): util.ByteBuffer;
        function startEncrypting(
            key: string | util.ByteBuffer,
            iv: util.ByteBuffer | Byte[] | Bytes,
            output: util.ByteBuffer | null,
        ): rc2.cipher;
        function createEncryptionCipher(key: string | util.ByteBuffer, bits?: number): rc2.cipher;
        function startDecrypting(
            key: string | util.ByteBuffer,
            iv: util.ByteBuffer | Byte[] | Bytes,
            output: util.ByteBuffer | null,
        ): rc2.cipher;
        function createDecryptionCipher(key: string | util.ByteBuffer, bits?: number): rc2.cipher;
    }

    namespace kem {
        namespace rsa {
            interface kem {
                /**
                 * Generates a secret key and its encapsulation.
                 *
                 * @param publicKey the RSA public key to encrypt with.
                 * @param keyLength the length, in bytes, of the secret key to generate.
                 */
                encrypt(publicKey: pki.rsa.PublicKey, keyLength: number): EncryptResult;
                /**
                 * Decrypts an encapsulated secret key.
                 *
                 * @param privateKey the RSA private key to decrypt with.
                 * @param encapsulation the ciphertext for generating the secret key, as a binary-encoded
                 * string of bytes.
                 * @param keyLength the length, in bytes, of the secret key to generate.
                 *
                 * @return the secret key as a binary-encoded string of bytes.
                 */
                decrypt(privateKey: pki.rsa.PrivateKey, encapsulation: string, keyLength: number): string;
            }

            interface random {
                getBytesSync(count: number): Bytes;
            }

            interface Options {
                /**
                 * A custom crypto-secure pseudo-random number generator to use.
                 */
                prng?: random | undefined;
            }

            /**
             * Creates an RSA KEM API object for generating a secret asymmetric key.
             *
             * The symmetric key may be generated via a call to 'encrypt', which will
             * produce a ciphertext to be transmitted to the recipient and a key to be
             * kept secret. The ciphertext is a parameter to be passed to 'decrypt' which
             * will produce the same secret key for the recipient to use to decrypt a
             * message that was encrypted with the secret key.
             *
             * @param kdf the KDF API to use (eg: `new forge.kem.kdf1()`).
             * @param options the options to use.
             */
            function create(kdf: KDF, options?: Options): kem;
        }

        interface EncryptResult {
            /**
             * The ciphertext for generating the secret key, as a binary-encoded string of bytes.
             */
            encapsulation: string;
            /**
             * The secret key to use for encrypting a message.
             */
            key: string;
        }

        interface KDF {
            /**
             * Generate a key of the specified length.
             *
             * @param x the binary-encoded byte string to generate a key from.
             * @param length the number of bytes to generate (the size of the key).
             *
             * @return the key as a binary-encoded string.
             */
            generate(x: string, length: number): string;
        }

        /**
         * Creates a key derivation API object that implements KDF1 per ISO 18033-2.
         *
         * @param md the hash API to use.
         * @param digestLength a digest length that must be positive and less than or equal to `md.digestLength`.
         *
         * @return a KDF1 API object.
         */
        class kdf1 implements KDF {
            constructor(md: md.MessageDigest, digestLength?: number);
            