tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ECPublicKey.ts (5974B)


      1 import * as asn1js from "asn1js";
      2 import { BufferSourceConverter } from "pvtsutils";
      3 import * as pvutils from "pvutils";
      4 import { EMPTY_BUFFER, EMPTY_STRING } from "./constants";
      5 import { ECNamedCurves } from "./ECNamedCurves";
      6 import { ParameterError } from "./errors";
      7 import { PkiObject, PkiObjectParameters } from "./PkiObject";
      8 import * as Schema from "./Schema";
      9 
     10 const X = "x";
     11 const Y = "y";
     12 const NAMED_CURVE = "namedCurve";
     13 
     14 export interface IECPublicKey {
     15  namedCurve: string;
     16  x: ArrayBuffer;
     17  y: ArrayBuffer;
     18 }
     19 
     20 export interface ECPublicKeyJson {
     21  crv: string;
     22  x: string;
     23  y: string;
     24 }
     25 
     26 export type ECPublicKeyParameters = PkiObjectParameters & Partial<IECPublicKey> & { json?: ECPublicKeyJson; };
     27 
     28 /**
     29 * Represents the PrivateKeyInfo structure described in [RFC5480](https://datatracker.ietf.org/doc/html/rfc5480)
     30 */
     31 export class ECPublicKey extends PkiObject implements IECPublicKey {
     32 
     33  public static override CLASS_NAME = "ECPublicKey";
     34 
     35  public namedCurve!: string;
     36  public x!: ArrayBuffer;
     37  public y!: ArrayBuffer;
     38 
     39  /**
     40   * Initializes a new instance of the {@link ECPublicKey} class
     41   * @param parameters Initialization parameters
     42   */
     43  constructor(parameters: ECPublicKeyParameters = {}) {
     44    super();
     45 
     46    this.x = pvutils.getParametersValue(parameters, X, ECPublicKey.defaultValues(X));
     47    this.y = pvutils.getParametersValue(parameters, Y, ECPublicKey.defaultValues(Y));
     48    this.namedCurve = pvutils.getParametersValue(parameters, NAMED_CURVE, ECPublicKey.defaultValues(NAMED_CURVE));
     49 
     50    if (parameters.json) {
     51      this.fromJSON(parameters.json);
     52    }
     53 
     54    if (parameters.schema) {
     55      this.fromSchema(parameters.schema);
     56    }
     57  }
     58 
     59  /**
     60   * Returns default values for all class members
     61   * @param memberName String name for a class member
     62   * @returns Default value
     63   */
     64  public static override defaultValues(memberName: typeof NAMED_CURVE): string;
     65  public static override defaultValues(memberName: typeof X | typeof Y): ArrayBuffer;
     66  public static override defaultValues(memberName: string): any {
     67    switch (memberName) {
     68      case X:
     69      case Y:
     70        return EMPTY_BUFFER;
     71      case NAMED_CURVE:
     72        return EMPTY_STRING;
     73      default:
     74        return super.defaultValues(memberName);
     75    }
     76  }
     77 
     78 
     79  /**
     80   * Compare values with default values for all class members
     81   * @param memberName String name for a class member
     82   * @param memberValue Value to compare with default value
     83   */
     84  static compareWithDefault<T>(memberName: string, memberValue: T): memberValue is T {
     85    switch (memberName) {
     86      case X:
     87      case Y:
     88        return memberValue instanceof ArrayBuffer &&
     89          (pvutils.isEqualBuffer(memberValue, ECPublicKey.defaultValues(memberName)));
     90      case NAMED_CURVE:
     91        return typeof memberValue === "string" &&
     92          memberValue === ECPublicKey.defaultValues(memberName);
     93      default:
     94        return super.defaultValues(memberName);
     95    }
     96  }
     97 
     98  /**
     99   * Returns value of pre-defined ASN.1 schema for current class
    100   * @param parameters Input parameters for the schema
    101   * @returns ASN.1 schema object
    102   */
    103  public static override schema(): Schema.SchemaType {
    104    return new asn1js.RawData();
    105  }
    106 
    107  public fromSchema(schema1: BufferSource): any {
    108    //#region Check the schema is valid
    109 
    110    const view = BufferSourceConverter.toUint8Array(schema1);
    111    if (view[0] !== 0x04) {
    112      throw new Error("Object's schema was not verified against input data for ECPublicKey");
    113    }
    114    //#endregion
    115 
    116    //#region Get internal properties from parsed schema
    117    const namedCurve = ECNamedCurves.find(this.namedCurve);
    118    if (!namedCurve) {
    119      throw new Error(`Incorrect curve OID: ${this.namedCurve}`);
    120    }
    121    const coordinateLength = namedCurve.size;
    122 
    123    if (view.byteLength !== (coordinateLength * 2 + 1)) {
    124      throw new Error("Object's schema was not verified against input data for ECPublicKey");
    125    }
    126 
    127    this.namedCurve = namedCurve.name;
    128    this.x = view.slice(1, coordinateLength + 1).buffer;
    129    this.y = view.slice(1 + coordinateLength, coordinateLength * 2 + 1).buffer;
    130    //#endregion
    131  }
    132 
    133  public toSchema(): asn1js.RawData {
    134    return new asn1js.RawData({
    135      data: pvutils.utilConcatBuf(
    136        (new Uint8Array([0x04])).buffer,
    137        this.x,
    138        this.y
    139      )
    140    });
    141  }
    142 
    143  public toJSON(): ECPublicKeyJson {
    144    const namedCurve = ECNamedCurves.find(this.namedCurve);
    145 
    146    return {
    147      crv: namedCurve ? namedCurve.name : this.namedCurve,
    148      x: pvutils.toBase64(pvutils.arrayBufferToString(this.x), true, true, false),
    149      y: pvutils.toBase64(pvutils.arrayBufferToString(this.y), true, true, false)
    150    };
    151  }
    152 
    153  /**
    154   * Converts JSON value into current object
    155   * @param json JSON object
    156   */
    157  public fromJSON(json: any): void {
    158    ParameterError.assert("json", json, "crv", "x", "y");
    159 
    160    let coordinateLength = 0;
    161    const namedCurve = ECNamedCurves.find(json.crv);
    162    if (namedCurve) {
    163      this.namedCurve = namedCurve.id;
    164      coordinateLength = namedCurve.size;
    165    }
    166 
    167    // TODO Simplify Base64url encoding
    168    const xConvertBuffer = pvutils.stringToArrayBuffer(pvutils.fromBase64(json.x, true));
    169 
    170    if (xConvertBuffer.byteLength < coordinateLength) {
    171      this.x = new ArrayBuffer(coordinateLength);
    172      const view = new Uint8Array(this.x);
    173      const convertBufferView = new Uint8Array(xConvertBuffer);
    174      view.set(convertBufferView, 1);
    175    } else {
    176      this.x = xConvertBuffer.slice(0, coordinateLength);
    177    }
    178 
    179    // TODO Simplify Base64url encoding
    180    const yConvertBuffer = pvutils.stringToArrayBuffer(pvutils.fromBase64(json.y, true));
    181 
    182    if (yConvertBuffer.byteLength < coordinateLength) {
    183      this.y = new ArrayBuffer(coordinateLength);
    184      const view = new Uint8Array(this.y);
    185      const convertBufferView = new Uint8Array(yConvertBuffer);
    186      view.set(convertBufferView, 1);
    187    } else {
    188      this.y = yConvertBuffer.slice(0, coordinateLength);
    189    }
    190  }
    191 
    192 }