Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/js/PKI.js/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 12 kB image not shown  

Quelle  common.ts   Sprache: unbekannt

 
Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

import * as asn1js from "asn1js";
import * as pvutils from "pvutils";
import { AlgorithmIdentifier } from "./AlgorithmIdentifier";
import { EMPTY_BUFFER } from "./constants";
import type { CryptoEngineAlgorithmOperation, CryptoEngineAlgorithmParams, ICryptoEngine } from "./CryptoEngine/CryptoEngineInterface";
import { ArgumentError } from "./errors";

//#region Crypto engine related function
export { ICryptoEngine } from "./CryptoEngine/CryptoEngineInterface";

export interface GlobalCryptoEngine {
  name: string;
  crypto: ICryptoEngine | null;
}
export let engine: GlobalCryptoEngine = {
  name: "none",
  crypto: null,
};

function isCryptoEngine(engine: unknown): engine is ICryptoEngine {
  return engine
    && typeof engine === "object"
    && "crypto" in engine
    ? true
    : false;
}

/**
 * Sets global crypto engine
 * @param name Name of the crypto engine
 * @param crypto
 * @param subtle
 * @deprecated Since version 3.0.0
 */
export function setEngine(name: string, crypto: ICryptoEngine | Crypto, subtle: ICryptoEngine | SubtleCrypto): void;
/**
 * Sets global crypto engine
 * @param name Name of the crypto engine
 * @param crypto Crypto engine. If the parameter is omitted, `CryptoEngine` with `self.crypto` are used
 * @since 3.0.0
 */
export function setEngine(name: string, crypto?: ICryptoEngine): void;
export function setEngine(name: string, ...args: any[]): void {
  let crypto: ICryptoEngine | null = null;
  if (args.length < 2) {
    // v3.0.0 implementation
    if (args.length) {
      crypto = args[0];
    } else {
      // crypto param is omitted, use CryptoEngine(self.crypto)
      crypto = typeof self !== "undefined" && self.crypto ? new CryptoEngine({ name: "browser", crypto: self.crypto }) : null;
    }
  } else {
    // prev implementation
    const cryptoArg = args[0];
    const subtleArg = args[1];
    if (isCryptoEngine(subtleArg)) {
      crypto = subtleArg;
    } else if (isCryptoEngine(cryptoArg)) {
      crypto = cryptoArg;
    } else if ("subtle" in cryptoArg && "getRandomValues" in cryptoArg) {
      crypto = new CryptoEngine({
        crypto: cryptoArg,
      });
    }
  }

  if ((typeof process !== "undefined") && ("pid" in process) && (typeof global !== "undefined") && (typeof window === "undefined")) {
    // We are in Node
    if (typeof (global as any)[process.pid] === "undefined") {
      (global as any)[process.pid] = {};
    }
    else {
      if (typeof (global as any)[process.pid] !== "object") {
        throw new Error(`Name global.${process.pid} already exists and it is not an object`);
      }
    }

    if (typeof (global as any)[process.pid].pkijs === "undefined") {
      (global as any)[process.pid].pkijs = {};
    }
    else {
      if (typeof (global as any)[process.pid].pkijs !== "object") {
        throw new Error(`Name global.${process.pid}.pkijs already exists and it is not an object`);
      }
    }

    (global as any)[process.pid].pkijs.engine = {
      name: name,
      crypto,
    };
  } else {
    // We are in browser
    engine = {
      name: name,
      crypto,
    };
  }
}

export function getEngine(): GlobalCryptoEngine {
  //#region We are in Node
  if ((typeof process !== "undefined") && ("pid" in process) && (typeof global !== "undefined") && (typeof window === "undefined")) {
    let _engine;

    try {
      _engine = (global as any)[process.pid].pkijs.engine;
    }
    catch (ex) {
      throw new Error("Please call 'setEngine' before call to 'getEngine'");
    }

    return _engine;
  }
  //#endregion

  return engine;
}
//#endregion

//#region Declaration of common functions

/**
 * Gets crypto subtle from the current "crypto engine"
 * @param safety
 * @returns Reruns {@link ICryptoEngine} or `null`
 */
export function getCrypto(safety?: boolean): ICryptoEngine | null;
/**
 * Gets crypto subtle from the current "crypto engine"
 * @param safety
 * @returns Reruns {@link ICryptoEngine} or throws en exception
 * @throws Throws {@link Error} if `subtle` is empty
 */
export function getCrypto(safety: true): ICryptoEngine;
export function getCrypto(safety = false): ICryptoEngine | null {
  const _engine = getEngine();

  if (!_engine.crypto && safety) {
    throw new Error("Unable to create WebCrypto object");
  }

  return _engine.crypto;
}

/**
 * Initialize input Uint8Array by random values (with help from current "crypto engine")
 * @param view
 */
export function getRandomValues(view: Uint8Array) {
  return getCrypto(true).getRandomValues(view);
}

/**
 * Get OID for each specific algorithm
 * @param algorithm WebCrypto Algorithm
 * @param safety if `true` throws exception on unknown algorithm
 * @param target name of the target
 * @throws Throws {@link Error} exception if unknown WebCrypto algorithm
 */
export function getOIDByAlgorithm(algorithm: Algorithm, safety?: boolean, target?: string) {
  return getCrypto(true).getOIDByAlgorithm(algorithm, safety, target);
}

/**
 * Get default algorithm parameters for each kind of operation
 * @param algorithmName Algorithm name to get common parameters for
 * @param operation Kind of operation: "sign", "encrypt", "generateKey", "importKey", "exportKey", "verify"
 */
// TODO Add safety
export function getAlgorithmParameters(algorithmName: string, operation: CryptoEngineAlgorithmOperation): CryptoEngineAlgorithmParams {
  return getCrypto(true).getAlgorithmParameters(algorithmName, operation);
}

/**
 * Create CMS ECDSA signature from WebCrypto ECDSA signature
 * @param signatureBuffer WebCrypto result of "sign" function
 */
export function createCMSECDSASignature(signatureBuffer: ArrayBuffer): ArrayBuffer {
  //#region Initial check for correct length
  if ((signatureBuffer.byteLength % 2) !== 0)
    return EMPTY_BUFFER;
  //#endregion

  //#region Initial variables
  const length = signatureBuffer.byteLength / 2; // There are two equal parts inside incoming ArrayBuffer

  const rBuffer = new ArrayBuffer(length);
  const rView = new Uint8Array(rBuffer);
  rView.set(new Uint8Array(signatureBuffer, 0, length));

  const rInteger = new asn1js.Integer({ valueHex: rBuffer });

  const sBuffer = new ArrayBuffer(length);
  const sView = new Uint8Array(sBuffer);
  sView.set(new Uint8Array(signatureBuffer, length, length));

  const sInteger = new asn1js.Integer({ valueHex: sBuffer });
  //#endregion

  return (new asn1js.Sequence({
    value: [
      rInteger.convertToDER(),
      sInteger.convertToDER()
    ]
  })).toBER(false);
}

/**
 * Create a single ArrayBuffer from CMS ECDSA signature
 * @param cmsSignature ASN.1 SEQUENCE contains CMS ECDSA signature
 * @param pointSize Size of EC point. Use {@link ECNamedCurves.find} to get correct point size
 * @returns WebCrypto signature
 */
export function createECDSASignatureFromCMS(cmsSignature: asn1js.AsnType, pointSize: number): ArrayBuffer {
  // Check input variables
  if (!(cmsSignature instanceof asn1js.Sequence
    && cmsSignature.valueBlock.value.length === 2
    && cmsSignature.valueBlock.value[0] instanceof asn1js.Integer
    && cmsSignature.valueBlock.value[1] instanceof asn1js.Integer))
    return EMPTY_BUFFER;

  const rValueView = cmsSignature.valueBlock.value[0].convertFromDER().valueBlock.valueHexView;
  const sValueView = cmsSignature.valueBlock.value[1].convertFromDER().valueBlock.valueHexView;

  const res = new Uint8Array(pointSize * 2);

  res.set(rValueView, pointSize - rValueView.byteLength);
  res.set(sValueView, (2 * pointSize) - sValueView.byteLength);

  return res.buffer;
}

/**
 * Gets WebCrypto algorithm by well-known OID
 * @param oid algorithm identifier
 * @param safety if true throws exception on unknown algorithm identifier
 * @param target name of the target
 * @returns WebCrypto algorithm or an empty object
 */
export function getAlgorithmByOID<T extends Algorithm = Algorithm>(oid: string, safety?: boolean, target?: string): T | object;
export function getAlgorithmByOID<T extends Algorithm = Algorithm>(oid: string, safety: true, target?: string): T;
export function getAlgorithmByOID(oid: string, safety = false, target?: string): any {
  return getCrypto(true).getAlgorithmByOID(oid, safety, target);
}

/**
 * Getting hash algorithm by signature algorithm
 * @param signatureAlgorithm Signature algorithm
 */
export function getHashAlgorithm(signatureAlgorithm: AlgorithmIdentifier): string {
  return getCrypto(true).getHashAlgorithm(signatureAlgorithm);
}

/**
 * ANS X9.63 Key Derivation Function having a "Counter" as a parameter
 * @param hashFunction Used hash function
 * @param zBuffer ArrayBuffer containing ECDH shared secret to derive from
 * @param Counter
 * @param SharedInfo Usually DER encoded "ECC_CMS_SharedInfo" structure
 * @param crypto Crypto engine
 */
async function kdfWithCounter(hashFunction: string, zBuffer: ArrayBuffer, Counter: number, SharedInfo: ArrayBuffer, crypto: ICryptoEngine): Promise<{ counter: number; result: ArrayBuffer; }> {
  //#region Check of input parameters
  switch (hashFunction.toUpperCase()) {
    case "SHA-1":
    case "SHA-256":
    case "SHA-384":
    case "SHA-512":
      break;
    default:
      throw new ArgumentError(`Unknown hash function: ${hashFunction}`);
  }

  ArgumentError.assert(zBuffer, "zBuffer", "ArrayBuffer");
  if (zBuffer.byteLength === 0)
    throw new ArgumentError("'zBuffer' has zero length, error");

  ArgumentError.assert(SharedInfo, "SharedInfo", "ArrayBuffer");
  if (Counter > 255)
    throw new ArgumentError("Please set 'Counter' argument to value less or equal to 255");
  //#endregion

  //#region Initial variables
  const counterBuffer = new ArrayBuffer(4);
  const counterView = new Uint8Array(counterBuffer);
  counterView[0] = 0x00;
  counterView[1] = 0x00;
  counterView[2] = 0x00;
  counterView[3] = Counter;

  let combinedBuffer = EMPTY_BUFFER;
  //#endregion

  //#region Create a combined ArrayBuffer for digesting
  combinedBuffer = pvutils.utilConcatBuf(combinedBuffer, zBuffer);
  combinedBuffer = pvutils.utilConcatBuf(combinedBuffer, counterBuffer);
  combinedBuffer = pvutils.utilConcatBuf(combinedBuffer, SharedInfo);
  //#endregion

  //#region Return digest of combined ArrayBuffer and information about current counter
  const result = await crypto.digest(
    { name: hashFunction },
    combinedBuffer);

  return {
    counter: Counter,
    result
  };
  //#endregion
}

/**
 * ANS X9.63 Key Derivation Function
 * @param hashFunction Used hash function
 * @param Zbuffer ArrayBuffer containing ECDH shared secret to derive from
 * @param keydatalen Length (!!! in BITS !!!) of used kew derivation function
 * @param SharedInfo Usually DER encoded "ECC_CMS_SharedInfo" structure
 * @param crypto Crypto engine
 */
export async function kdf(hashFunction: string, Zbuffer: ArrayBuffer, keydatalen: number, SharedInfo: ArrayBuffer, crypto = getCrypto(true)) {
  //#region Initial variables
  let hashLength = 0;
  let maxCounter = 1;
  //#endregion

  //#region Check of input parameters
  switch (hashFunction.toUpperCase()) {
    case "SHA-1":
      hashLength = 160; // In bits
      break;
    case "SHA-256":
      hashLength = 256; // In bits
      break;
    case "SHA-384":
      hashLength = 384; // In bits
      break;
    case "SHA-512":
      hashLength = 512; // In bits
      break;
    default:
      throw new ArgumentError(`Unknown hash function: ${hashFunction}`);
  }

  ArgumentError.assert(Zbuffer, "Zbuffer", "ArrayBuffer");
  if (Zbuffer.byteLength === 0)
    throw new ArgumentError("'Zbuffer' has zero length, error");
  ArgumentError.assert(SharedInfo, "SharedInfo", "ArrayBuffer");
  //#endregion

  //#region Calculated maximum value of "Counter" variable
  const quotient = keydatalen / hashLength;

  if (Math.floor(quotient) > 0) {
    maxCounter = Math.floor(quotient);

    if ((quotient - maxCounter) > 0)
      maxCounter++;
  }
  //#endregion

  //#region Create an array of "kdfWithCounter"
  const incomingResult = [];
  for (let i = 1; i <= maxCounter; i++)
    incomingResult.push(await kdfWithCounter(hashFunction, Zbuffer, i, SharedInfo, crypto));
  //#endregion

  //#region Return combined digest with specified length
  //#region Initial variables
  let combinedBuffer = EMPTY_BUFFER;
  let currentCounter = 1;
  let found = true;
  //#endregion

  //#region Combine all buffer together
  while (found) {
    found = false;

    for (const result of incomingResult) {
      if (result.counter === currentCounter) {
        combinedBuffer = pvutils.utilConcatBuf(combinedBuffer, result.result);
        found = true;
        break;
      }
    }

    currentCounter++;
  }
  //#endregion

  //#region Create output buffer with specified length
  keydatalen >>= 3; // Divide by 8 since "keydatalen" is in bits

  if (combinedBuffer.byteLength > keydatalen) {
    const newBuffer = new ArrayBuffer(keydatalen);
    const newView = new Uint8Array(newBuffer);
    const combinedView = new Uint8Array(combinedBuffer);

    for (let i = 0; i < keydatalen; i++)
      newView[i] = combinedView[i];

    return newBuffer;
  }

  return combinedBuffer; // Since the situation when "combinedBuffer.byteLength < keydatalen" here we have only "combinedBuffer.byteLength === keydatalen"
  //#endregion
  //#endregion
}
//#endregion

import { CryptoEngine } from "./CryptoEngine/CryptoEngine";

[ Dauer der Verarbeitung: 0.35 Sekunden  ]