tor-browser

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

RSAPrivateKey.ts (12143B)


      1 import * as asn1js from "asn1js";
      2 import * as pvtsutils from "pvtsutils";
      3 import * as pvutils from "pvutils";
      4 import { EMPTY_STRING } from "./constants";
      5 import { AsnError, ParameterError } from "./errors";
      6 import { OtherPrimeInfo, OtherPrimeInfoJson, OtherPrimeInfoSchema } from "./OtherPrimeInfo";
      7 import { PkiObject, PkiObjectParameters } from "./PkiObject";
      8 import * as Schema from "./Schema";
      9 
     10 const VERSION = "version";
     11 const MODULUS = "modulus";
     12 const PUBLIC_EXPONENT = "publicExponent";
     13 const PRIVATE_EXPONENT = "privateExponent";
     14 const PRIME1 = "prime1";
     15 const PRIME2 = "prime2";
     16 const EXPONENT1 = "exponent1";
     17 const EXPONENT2 = "exponent2";
     18 const COEFFICIENT = "coefficient";
     19 const OTHER_PRIME_INFOS = "otherPrimeInfos";
     20 const CLEAR_PROPS = [
     21  VERSION,
     22  MODULUS,
     23  PUBLIC_EXPONENT,
     24  PRIVATE_EXPONENT,
     25  PRIME1,
     26  PRIME2,
     27  EXPONENT1,
     28  EXPONENT2,
     29  COEFFICIENT,
     30  OTHER_PRIME_INFOS
     31 ];
     32 
     33 export interface IRSAPrivateKey {
     34  version: number;
     35  modulus: asn1js.Integer;
     36  publicExponent: asn1js.Integer;
     37  privateExponent: asn1js.Integer;
     38  prime1: asn1js.Integer;
     39  prime2: asn1js.Integer;
     40  exponent1: asn1js.Integer;
     41  exponent2: asn1js.Integer;
     42  coefficient: asn1js.Integer;
     43  otherPrimeInfos?: OtherPrimeInfo[];
     44 }
     45 
     46 export type RSAPrivateKeyParameters = PkiObjectParameters & Partial<IRSAPrivateKey> & { json?: RSAPrivateKeyJson; };
     47 
     48 export interface RSAPrivateKeyJson {
     49  n: string;
     50  e: string;
     51  d: string;
     52  p: string;
     53  q: string;
     54  dp: string;
     55  dq: string;
     56  qi: string;
     57  oth?: OtherPrimeInfoJson[];
     58 }
     59 
     60 /**
     61 * Represents the PrivateKeyInfo structure described in [RFC3447](https://datatracker.ietf.org/doc/html/rfc3447)
     62 */
     63 export class RSAPrivateKey extends PkiObject implements IRSAPrivateKey {
     64 
     65  public static override CLASS_NAME = "RSAPrivateKey";
     66 
     67  public version!: number;
     68  public modulus!: asn1js.Integer;
     69  public publicExponent!: asn1js.Integer;
     70  public privateExponent!: asn1js.Integer;
     71  public prime1!: asn1js.Integer;
     72  public prime2!: asn1js.Integer;
     73  public exponent1!: asn1js.Integer;
     74  public exponent2!: asn1js.Integer;
     75  public coefficient!: asn1js.Integer;
     76  public otherPrimeInfos?: OtherPrimeInfo[];
     77 
     78  /**
     79   * Initializes a new instance of the {@link RSAPrivateKey} class
     80   * @param parameters Initialization parameters
     81   */
     82  constructor(parameters: RSAPrivateKeyParameters = {}) {
     83    super();
     84 
     85    this.version = pvutils.getParametersValue(parameters, VERSION, RSAPrivateKey.defaultValues(VERSION));
     86    this.modulus = pvutils.getParametersValue(parameters, MODULUS, RSAPrivateKey.defaultValues(MODULUS));
     87    this.publicExponent = pvutils.getParametersValue(parameters, PUBLIC_EXPONENT, RSAPrivateKey.defaultValues(PUBLIC_EXPONENT));
     88    this.privateExponent = pvutils.getParametersValue(parameters, PRIVATE_EXPONENT, RSAPrivateKey.defaultValues(PRIVATE_EXPONENT));
     89    this.prime1 = pvutils.getParametersValue(parameters, PRIME1, RSAPrivateKey.defaultValues(PRIME1));
     90    this.prime2 = pvutils.getParametersValue(parameters, PRIME2, RSAPrivateKey.defaultValues(PRIME2));
     91    this.exponent1 = pvutils.getParametersValue(parameters, EXPONENT1, RSAPrivateKey.defaultValues(EXPONENT1));
     92    this.exponent2 = pvutils.getParametersValue(parameters, EXPONENT2, RSAPrivateKey.defaultValues(EXPONENT2));
     93    this.coefficient = pvutils.getParametersValue(parameters, COEFFICIENT, RSAPrivateKey.defaultValues(COEFFICIENT));
     94    if (OTHER_PRIME_INFOS in parameters) {
     95      this.otherPrimeInfos = pvutils.getParametersValue(parameters, OTHER_PRIME_INFOS, RSAPrivateKey.defaultValues(OTHER_PRIME_INFOS));
     96    }
     97 
     98    if (parameters.json) {
     99      this.fromJSON(parameters.json);
    100    }
    101 
    102    if (parameters.schema) {
    103      this.fromSchema(parameters.schema);
    104    }
    105  }
    106 
    107  /**
    108   * Returns default values for all class members
    109   * @param memberName String name for a class member
    110   * @returns Default value
    111   */
    112  public static override defaultValues(memberName: typeof VERSION): number;
    113  public static override defaultValues(memberName: typeof MODULUS): asn1js.Integer;
    114  public static override defaultValues(memberName: typeof PUBLIC_EXPONENT): asn1js.Integer;
    115  public static override defaultValues(memberName: typeof PRIVATE_EXPONENT): asn1js.Integer;
    116  public static override defaultValues(memberName: typeof PRIME1): asn1js.Integer;
    117  public static override defaultValues(memberName: typeof PRIME2): asn1js.Integer;
    118  public static override defaultValues(memberName: typeof EXPONENT1): asn1js.Integer;
    119  public static override defaultValues(memberName: typeof EXPONENT2): asn1js.Integer;
    120  public static override defaultValues(memberName: typeof COEFFICIENT): asn1js.Integer;
    121  public static override defaultValues(memberName: typeof OTHER_PRIME_INFOS): OtherPrimeInfo[];
    122  public static override defaultValues(memberName: string): any {
    123    switch (memberName) {
    124      case VERSION:
    125        return 0;
    126      case MODULUS:
    127        return new asn1js.Integer();
    128      case PUBLIC_EXPONENT:
    129        return new asn1js.Integer();
    130      case PRIVATE_EXPONENT:
    131        return new asn1js.Integer();
    132      case PRIME1:
    133        return new asn1js.Integer();
    134      case PRIME2:
    135        return new asn1js.Integer();
    136      case EXPONENT1:
    137        return new asn1js.Integer();
    138      case EXPONENT2:
    139        return new asn1js.Integer();
    140      case COEFFICIENT:
    141        return new asn1js.Integer();
    142      case OTHER_PRIME_INFOS:
    143        return [];
    144      default:
    145        return super.defaultValues(memberName);
    146    }
    147  }
    148 
    149  /**
    150   * @inheritdoc
    151   * @asn ASN.1 schema
    152   * ```asn
    153   * RSAPrivateKey ::= Sequence {
    154   *    version           Version,
    155   *    modulus           Integer,  -- n
    156   *    publicExponent    Integer,  -- e
    157   *    privateExponent   Integer,  -- d
    158   *    prime1            Integer,  -- p
    159   *    prime2            Integer,  -- q
    160   *    exponent1         Integer,  -- d mod (p-1)
    161   *    exponent2         Integer,  -- d mod (q-1)
    162   *    coefficient       Integer,  -- (inverse of q) mod p
    163   *    otherPrimeInfos   OtherPrimeInfos OPTIONAL
    164   * }
    165   *
    166   * OtherPrimeInfos ::= Sequence SIZE(1..MAX) OF OtherPrimeInfo
    167   * ```
    168   */
    169  public static override schema(parameters: Schema.SchemaParameters<{
    170    version?: string;
    171    modulus?: string;
    172    publicExponent?: string;
    173    privateExponent?: string;
    174    prime1?: string;
    175    prime2?: string;
    176    exponent1?: string;
    177    exponent2?: string;
    178    coefficient?: string;
    179    otherPrimeInfosName?: string;
    180    otherPrimeInfo?: OtherPrimeInfoSchema;
    181  }> = {}): Schema.SchemaType {
    182    const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {});
    183 
    184    return (new asn1js.Sequence({
    185      name: (names.blockName || EMPTY_STRING),
    186      value: [
    187        new asn1js.Integer({ name: (names.version || EMPTY_STRING) }),
    188        new asn1js.Integer({ name: (names.modulus || EMPTY_STRING) }),
    189        new asn1js.Integer({ name: (names.publicExponent || EMPTY_STRING) }),
    190        new asn1js.Integer({ name: (names.privateExponent || EMPTY_STRING) }),
    191        new asn1js.Integer({ name: (names.prime1 || EMPTY_STRING) }),
    192        new asn1js.Integer({ name: (names.prime2 || EMPTY_STRING) }),
    193        new asn1js.Integer({ name: (names.exponent1 || EMPTY_STRING) }),
    194        new asn1js.Integer({ name: (names.exponent2 || EMPTY_STRING) }),
    195        new asn1js.Integer({ name: (names.coefficient || EMPTY_STRING) }),
    196        new asn1js.Sequence({
    197          optional: true,
    198          value: [
    199            new asn1js.Repeated({
    200              name: (names.otherPrimeInfosName || EMPTY_STRING),
    201              value: OtherPrimeInfo.schema(names.otherPrimeInfo || {})
    202            })
    203          ]
    204        })
    205      ]
    206    }));
    207  }
    208 
    209  public fromSchema(schema: Schema.SchemaType): void {
    210    // Clear input data first
    211    pvutils.clearProps(schema, CLEAR_PROPS);
    212 
    213    // Check the schema is valid
    214    const asn1 = asn1js.compareSchema(schema,
    215      schema,
    216      RSAPrivateKey.schema({
    217        names: {
    218          version: VERSION,
    219          modulus: MODULUS,
    220          publicExponent: PUBLIC_EXPONENT,
    221          privateExponent: PRIVATE_EXPONENT,
    222          prime1: PRIME1,
    223          prime2: PRIME2,
    224          exponent1: EXPONENT1,
    225          exponent2: EXPONENT2,
    226          coefficient: COEFFICIENT,
    227          otherPrimeInfo: {
    228            names: {
    229              blockName: OTHER_PRIME_INFOS
    230            }
    231          }
    232        }
    233      })
    234    );
    235    AsnError.assertSchema(asn1, this.className);
    236 
    237    //#region Get internal properties from parsed schema
    238    this.version = asn1.result.version.valueBlock.valueDec;
    239    this.modulus = asn1.result.modulus.convertFromDER(256);
    240    this.publicExponent = asn1.result.publicExponent;
    241    this.privateExponent = asn1.result.privateExponent.convertFromDER(256);
    242    this.prime1 = asn1.result.prime1.convertFromDER(128);
    243    this.prime2 = asn1.result.prime2.convertFromDER(128);
    244    this.exponent1 = asn1.result.exponent1.convertFromDER(128);
    245    this.exponent2 = asn1.result.exponent2.convertFromDER(128);
    246    this.coefficient = asn1.result.coefficient.convertFromDER(128);
    247 
    248    if (OTHER_PRIME_INFOS in asn1.result)
    249      this.otherPrimeInfos = Array.from(asn1.result.otherPrimeInfos, element => new OtherPrimeInfo({ schema: element }));
    250    //#endregion
    251  }
    252 
    253  public toSchema(): asn1js.Sequence {
    254    //#region Create array for output sequence
    255    const outputArray = [];
    256 
    257    outputArray.push(new asn1js.Integer({ value: this.version }));
    258    outputArray.push(this.modulus.convertToDER());
    259    outputArray.push(this.publicExponent);
    260    outputArray.push(this.privateExponent.convertToDER());
    261    outputArray.push(this.prime1.convertToDER());
    262    outputArray.push(this.prime2.convertToDER());
    263    outputArray.push(this.exponent1.convertToDER());
    264    outputArray.push(this.exponent2.convertToDER());
    265    outputArray.push(this.coefficient.convertToDER());
    266 
    267    if (this.otherPrimeInfos) {
    268      outputArray.push(new asn1js.Sequence({
    269        value: Array.from(this.otherPrimeInfos, o => o.toSchema())
    270      }));
    271    }
    272    //#endregion
    273 
    274    //#region Construct and return new ASN.1 schema for this object
    275    return (new asn1js.Sequence({
    276      value: outputArray
    277    }));
    278    //#endregion
    279  }
    280 
    281  public toJSON(): RSAPrivateKeyJson {
    282    const jwk: RSAPrivateKeyJson = {
    283      n: pvtsutils.Convert.ToBase64Url(this.modulus.valueBlock.valueHexView),
    284      e: pvtsutils.Convert.ToBase64Url(this.publicExponent.valueBlock.valueHexView),
    285      d: pvtsutils.Convert.ToBase64Url(this.privateExponent.valueBlock.valueHexView),
    286      p: pvtsutils.Convert.ToBase64Url(this.prime1.valueBlock.valueHexView),
    287      q: pvtsutils.Convert.ToBase64Url(this.prime2.valueBlock.valueHexView),
    288      dp: pvtsutils.Convert.ToBase64Url(this.exponent1.valueBlock.valueHexView),
    289      dq: pvtsutils.Convert.ToBase64Url(this.exponent2.valueBlock.valueHexView),
    290      qi: pvtsutils.Convert.ToBase64Url(this.coefficient.valueBlock.valueHexView),
    291    };
    292    if (this.otherPrimeInfos) {
    293      jwk.oth = Array.from(this.otherPrimeInfos, o => o.toJSON());
    294    }
    295 
    296    return jwk;
    297  }
    298 
    299  /**
    300   * Converts JSON value into current object
    301   * @param json JSON object
    302   */
    303  public fromJSON(json: any): void {
    304    ParameterError.assert("json", json, "n", "e", "d", "p", "q", "dp", "dq", "qi");
    305 
    306    this.modulus = new asn1js.Integer({ valueHex: pvtsutils.Convert.FromBase64Url(json.n) });
    307    this.publicExponent = new asn1js.Integer({ valueHex: pvtsutils.Convert.FromBase64Url(json.e) });
    308    this.privateExponent = new asn1js.Integer({ valueHex: pvtsutils.Convert.FromBase64Url(json.d) });
    309    this.prime1 = new asn1js.Integer({ valueHex: pvtsutils.Convert.FromBase64Url(json.p) });
    310    this.prime2 = new asn1js.Integer({ valueHex: pvtsutils.Convert.FromBase64Url(json.q) });
    311    this.exponent1 = new asn1js.Integer({ valueHex: pvtsutils.Convert.FromBase64Url(json.dp) });
    312    this.exponent2 = new asn1js.Integer({ valueHex: pvtsutils.Convert.FromBase64Url(json.dq) });
    313    this.coefficient = new asn1js.Integer({ valueHex: pvtsutils.Convert.FromBase64Url(json.qi) });
    314    if (json.oth) {
    315      this.otherPrimeInfos = Array.from(json.oth, (element: any) => new OtherPrimeInfo({ json: element }));
    316    }
    317  }
    318 
    319 }