RSAPublicKey.ts (4477B)
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 { PkiObject, PkiObjectParameters } from "./PkiObject"; 7 import * as Schema from "./Schema"; 8 9 export interface IRSAPublicKey { 10 /** 11 * Modulus part of RSA public key 12 */ 13 modulus: asn1js.Integer; 14 /** 15 * Public exponent of RSA public key 16 */ 17 publicExponent: asn1js.Integer; 18 } 19 20 export interface RSAPublicKeyJson { 21 n: string; 22 e: string; 23 } 24 25 export type RSAPublicKeyParameters = PkiObjectParameters & Partial<IRSAPublicKey> & { json?: RSAPublicKeyJson; }; 26 27 const MODULUS = "modulus"; 28 const PUBLIC_EXPONENT = "publicExponent"; 29 const CLEAR_PROPS = [MODULUS, PUBLIC_EXPONENT]; 30 31 /** 32 * Represents the RSAPublicKey structure described in [RFC3447](https://datatracker.ietf.org/doc/html/rfc3447) 33 */ 34 export class RSAPublicKey extends PkiObject implements IRSAPublicKey { 35 36 public static override CLASS_NAME = "RSAPublicKey"; 37 38 public modulus!: asn1js.Integer; 39 public publicExponent!: asn1js.Integer; 40 41 /** 42 * Initializes a new instance of the {@link RSAPublicKey} class 43 * @param parameters Initialization parameters 44 */ 45 constructor(parameters: RSAPublicKeyParameters = {}) { 46 super(); 47 48 49 this.modulus = pvutils.getParametersValue(parameters, MODULUS, RSAPublicKey.defaultValues(MODULUS)); 50 this.publicExponent = pvutils.getParametersValue(parameters, PUBLIC_EXPONENT, RSAPublicKey.defaultValues(PUBLIC_EXPONENT)); 51 52 if (parameters.json) { 53 this.fromJSON(parameters.json); 54 } 55 56 if (parameters.schema) { 57 this.fromSchema(parameters.schema); 58 } 59 } 60 61 /** 62 * Returns default values for all class members 63 * @param memberName String name for a class member 64 * @returns Default value 65 */ 66 public static override defaultValues(memberName: typeof MODULUS | typeof PUBLIC_EXPONENT): asn1js.Integer; 67 public static override defaultValues(memberName: string): any { 68 switch (memberName) { 69 case MODULUS: 70 return new asn1js.Integer(); 71 case PUBLIC_EXPONENT: 72 return new asn1js.Integer(); 73 default: 74 return super.defaultValues(memberName); 75 } 76 } 77 78 /** 79 * @inheritdoc 80 * @asn ASN.1 schema 81 * ```asn 82 * RSAPublicKey ::= Sequence { 83 * modulus Integer, -- n 84 * publicExponent Integer -- e 85 * } 86 *``` 87 */ 88 public static override schema(parameters: Schema.SchemaParameters<{ modulus?: string; publicExponent?: string; }> = {}): Schema.SchemaType { 89 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 90 91 return (new asn1js.Sequence({ 92 name: (names.blockName || EMPTY_STRING), 93 value: [ 94 new asn1js.Integer({ name: (names.modulus || EMPTY_STRING) }), 95 new asn1js.Integer({ name: (names.publicExponent || EMPTY_STRING) }) 96 ] 97 })); 98 } 99 100 public fromSchema(schema: asn1js.AsnType): void { 101 // Clear input data first 102 pvutils.clearProps(schema, CLEAR_PROPS); 103 104 // Check the schema is valid 105 const asn1 = asn1js.compareSchema(schema, 106 schema, 107 RSAPublicKey.schema({ 108 names: { 109 modulus: MODULUS, 110 publicExponent: PUBLIC_EXPONENT 111 } 112 }) 113 ); 114 AsnError.assertSchema(asn1, this.className); 115 116 // Get internal properties from parsed schema 117 this.modulus = asn1.result.modulus.convertFromDER(256); 118 this.publicExponent = asn1.result.publicExponent; 119 } 120 121 public toSchema(): asn1js.Sequence { 122 return (new asn1js.Sequence({ 123 value: [ 124 this.modulus.convertToDER(), 125 this.publicExponent 126 ] 127 })); 128 } 129 130 public toJSON(): RSAPublicKeyJson { 131 return { 132 n: pvtsutils.Convert.ToBase64Url(this.modulus.valueBlock.valueHexView), 133 e: pvtsutils.Convert.ToBase64Url(this.publicExponent.valueBlock.valueHexView), 134 }; 135 } 136 137 /** 138 * Converts JSON value into current object 139 * @param json JSON object 140 */ 141 fromJSON(json: RSAPublicKeyJson): void { 142 ParameterError.assert("json", json, "n", "e"); 143 144 const array = pvutils.stringToArrayBuffer(pvutils.fromBase64(json.n, true)); 145 this.modulus = new asn1js.Integer({ valueHex: array.slice(0, Math.pow(2, pvutils.nearestPowerOf2(array.byteLength))) }); 146 this.publicExponent = new asn1js.Integer({ valueHex: pvutils.stringToArrayBuffer(pvutils.fromBase64(json.e, true)).slice(0, 3) }); 147 } 148 149 }