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 }