PKCS8ShroudedKeyBag.ts (8262B)
1 import * as asn1js from "asn1js"; 2 import * as pvutils from "pvutils"; 3 import { AlgorithmIdentifier, AlgorithmIdentifierJson, AlgorithmIdentifierSchema } from "./AlgorithmIdentifier"; 4 import { EncryptedData, EncryptedDataEncryptParams } from "./EncryptedData"; 5 import { EncryptedContentInfo } from "./EncryptedContentInfo"; 6 import { PrivateKeyInfo } from "./PrivateKeyInfo"; 7 import * as Schema from "./Schema"; 8 import { AsnError } from "./errors"; 9 import { PkiObject, PkiObjectParameters } from "./PkiObject"; 10 import { EMPTY_STRING } from "./constants"; 11 import * as common from "./common"; 12 13 const ENCRYPTION_ALGORITHM = "encryptionAlgorithm"; 14 const ENCRYPTED_DATA = "encryptedData"; 15 const PARSED_VALUE = "parsedValue"; 16 const CLEAR_PROPS = [ 17 ENCRYPTION_ALGORITHM, 18 ENCRYPTED_DATA, 19 ]; 20 21 export interface IPKCS8ShroudedKeyBag { 22 encryptionAlgorithm: AlgorithmIdentifier; 23 encryptedData: asn1js.OctetString; 24 parsedValue?: PrivateKeyInfo; 25 } 26 27 export type PKCS8ShroudedKeyBagParameters = PkiObjectParameters & Partial<IPKCS8ShroudedKeyBag>; 28 29 export interface PKCS8ShroudedKeyBagJson { 30 encryptionAlgorithm: AlgorithmIdentifierJson; 31 encryptedData: asn1js.OctetStringJson; 32 } 33 34 type PKCS8ShroudedKeyBagMakeInternalValuesParams = Omit<EncryptedDataEncryptParams, "contentToEncrypt">; 35 36 /** 37 * Represents the PKCS8ShroudedKeyBag structure described in [RFC7292](https://datatracker.ietf.org/doc/html/rfc7292) 38 */ 39 export class PKCS8ShroudedKeyBag extends PkiObject implements IPKCS8ShroudedKeyBag { 40 41 public static override CLASS_NAME = "PKCS8ShroudedKeyBag"; 42 43 public encryptionAlgorithm!: AlgorithmIdentifier; 44 public encryptedData!: asn1js.OctetString; 45 public parsedValue?: PrivateKeyInfo; 46 47 /** 48 * Initializes a new instance of the {@link PKCS8ShroudedKeyBag} class 49 * @param parameters Initialization parameters 50 */ 51 constructor(parameters: PKCS8ShroudedKeyBagParameters = {}) { 52 super(); 53 54 this.encryptionAlgorithm = pvutils.getParametersValue(parameters, ENCRYPTION_ALGORITHM, PKCS8ShroudedKeyBag.defaultValues(ENCRYPTION_ALGORITHM)); 55 this.encryptedData = pvutils.getParametersValue(parameters, ENCRYPTED_DATA, PKCS8ShroudedKeyBag.defaultValues(ENCRYPTED_DATA)); 56 if (PARSED_VALUE in parameters) { 57 this.parsedValue = pvutils.getParametersValue(parameters, PARSED_VALUE, PKCS8ShroudedKeyBag.defaultValues(PARSED_VALUE)); 58 } 59 60 if (parameters.schema) { 61 this.fromSchema(parameters.schema); 62 } 63 } 64 65 /** 66 * Returns default values for all class members 67 * @param memberName String name for a class member 68 * @returns Default value 69 */ 70 public static override defaultValues(memberName: typeof ENCRYPTION_ALGORITHM): AlgorithmIdentifier; 71 public static override defaultValues(memberName: typeof ENCRYPTED_DATA): asn1js.OctetString; 72 public static override defaultValues(memberName: typeof PARSED_VALUE): PrivateKeyInfo; 73 public static override defaultValues(memberName: string): any { 74 switch (memberName) { 75 case ENCRYPTION_ALGORITHM: 76 return (new AlgorithmIdentifier()); 77 case ENCRYPTED_DATA: 78 return (new asn1js.OctetString()); 79 case PARSED_VALUE: 80 return {}; 81 default: 82 return super.defaultValues(memberName); 83 } 84 } 85 86 /** 87 * Compare values with default values for all class members 88 * @param memberName String name for a class member 89 * @param memberValue Value to compare with default value 90 */ 91 public static compareWithDefault(memberName: string, memberValue: any): boolean { 92 switch (memberName) { 93 case ENCRYPTION_ALGORITHM: 94 return ((AlgorithmIdentifier.compareWithDefault("algorithmId", memberValue.algorithmId)) && 95 (("algorithmParams" in memberValue) === false)); 96 case ENCRYPTED_DATA: 97 return (memberValue.isEqual(PKCS8ShroudedKeyBag.defaultValues(memberName))); 98 case PARSED_VALUE: 99 return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0)); 100 default: 101 return super.defaultValues(memberName); 102 } 103 } 104 105 /** 106 * @inheritdoc 107 * @asn ASN.1 schema 108 * ```asn 109 * PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo 110 * 111 * EncryptedPrivateKeyInfo ::= SEQUENCE { 112 * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}}, 113 * encryptedData EncryptedData 114 * } 115 * 116 * EncryptedData ::= OCTET STRING 117 *``` 118 */ 119 public static override schema(parameters: Schema.SchemaParameters<{ 120 encryptionAlgorithm?: AlgorithmIdentifierSchema; 121 encryptedData?: string; 122 }> = {}): Schema.SchemaType { 123 /** 124 * @type {Object} 125 * @property {string} [blockName] 126 * @property {string} [encryptionAlgorithm] 127 * @property {string} [encryptedData] 128 */ 129 const names = pvutils.getParametersValue<NonNullable<typeof parameters.names>>(parameters, "names", {}); 130 131 return (new asn1js.Sequence({ 132 name: (names.blockName || EMPTY_STRING), 133 value: [ 134 AlgorithmIdentifier.schema(names.encryptionAlgorithm || { 135 names: { 136 blockName: ENCRYPTION_ALGORITHM 137 } 138 }), 139 new asn1js.Choice({ 140 value: [ 141 new asn1js.OctetString({ name: (names.encryptedData || ENCRYPTED_DATA) }), 142 new asn1js.OctetString({ 143 idBlock: { 144 isConstructed: true 145 }, 146 name: (names.encryptedData || ENCRYPTED_DATA) 147 }) 148 ] 149 }) 150 ] 151 })); 152 } 153 154 public fromSchema(schema: Schema.SchemaType): void { 155 // Clear input data first 156 pvutils.clearProps(schema, CLEAR_PROPS); 157 158 // Check the schema is valid 159 const asn1 = asn1js.compareSchema(schema, 160 schema, 161 PKCS8ShroudedKeyBag.schema({ 162 names: { 163 encryptionAlgorithm: { 164 names: { 165 blockName: ENCRYPTION_ALGORITHM 166 } 167 }, 168 encryptedData: ENCRYPTED_DATA 169 } 170 }) 171 ); 172 AsnError.assertSchema(asn1, this.className); 173 174 // Get internal properties from parsed schema 175 this.encryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.encryptionAlgorithm }); 176 this.encryptedData = asn1.result.encryptedData; 177 } 178 179 public toSchema(): asn1js.Sequence { 180 return (new asn1js.Sequence({ 181 value: [ 182 this.encryptionAlgorithm.toSchema(), 183 this.encryptedData 184 ] 185 })); 186 } 187 188 public toJSON(): PKCS8ShroudedKeyBagJson { 189 return { 190 encryptionAlgorithm: this.encryptionAlgorithm.toJSON(), 191 encryptedData: this.encryptedData.toJSON(), 192 }; 193 } 194 195 protected async parseInternalValues(parameters: { 196 password: ArrayBuffer; 197 }, crypto = common.getCrypto(true)) { 198 //#region Initial variables 199 const cmsEncrypted = new EncryptedData({ 200 encryptedContentInfo: new EncryptedContentInfo({ 201 contentEncryptionAlgorithm: this.encryptionAlgorithm, 202 encryptedContent: this.encryptedData 203 }) 204 }); 205 //#endregion 206 207 //#region Decrypt internal data 208 const decryptedData = await cmsEncrypted.decrypt(parameters, crypto); 209 210 //#endregion 211 212 //#region Initialize PARSED_VALUE with decrypted PKCS#8 private key 213 214 this.parsedValue = PrivateKeyInfo.fromBER(decryptedData); 215 //#endregion 216 } 217 218 public async makeInternalValues(parameters: PKCS8ShroudedKeyBagMakeInternalValuesParams, crypto = common.getCrypto(true)): Promise<void> { 219 //#region Check that we do have PARSED_VALUE 220 if (!this.parsedValue) { 221 throw new Error("Please initialize \"parsedValue\" first"); 222 } 223 //#endregion 224 225 //#region Initial variables 226 const cmsEncrypted = new EncryptedData(); 227 //#endregion 228 229 //#region Encrypt internal data 230 const encryptParams: EncryptedDataEncryptParams = { 231 ...parameters, 232 contentToEncrypt: this.parsedValue.toSchema().toBER(false), 233 }; 234 235 await cmsEncrypted.encrypt(encryptParams, crypto); 236 if (!cmsEncrypted.encryptedContentInfo.encryptedContent) { 237 throw new Error("The filed `encryptedContent` in EncryptedContentInfo is empty"); 238 } 239 240 //#endregion 241 242 //#region Initialize internal values 243 this.encryptionAlgorithm = cmsEncrypted.encryptedContentInfo.contentEncryptionAlgorithm; 244 this.encryptedData = cmsEncrypted.encryptedContentInfo.encryptedContent; 245 //#endregion 246 } 247 248 }