UNPKG

53.2 kBJavaScriptView Raw
1export * from '@virgilsecurity/sdk-crypto';
2import initFoundationModules from '@virgilsecurity/core-foundation/node.asmjs.es.js';
3import { ModuleInitializer } from '@virgilsecurity/init-utils';
4import { NodeBuffer, toBuffer, dataToUint8Array } from '@virgilsecurity/data-utils';
5
6let random;
7let keyProvider;
8const ensureExist = () => {
9 if (!random || !keyProvider) {
10 throw new Error("Cannot use global instances if the 'resetGlobalInstances' function has been called or 'createGlobalInstances' function has not been called yet.");
11 }
12};
13const getRandom = () => {
14 ensureExist();
15 return random;
16};
17const getKeyProvider = () => {
18 ensureExist();
19 return keyProvider;
20};
21const createGlobalInstances = (foundationModules) => {
22 random = new foundationModules.CtrDrbg();
23 try {
24 random.setupDefaults();
25 }
26 catch (error) {
27 random.delete();
28 throw error;
29 }
30 keyProvider = new foundationModules.KeyProvider();
31 keyProvider.random = random;
32 try {
33 keyProvider.setupDefaults();
34 }
35 catch (error) {
36 random.delete();
37 keyProvider.delete();
38 throw error;
39 }
40};
41const resetGlobalInstances = () => {
42 if (!random && !keyProvider) {
43 return;
44 }
45 ensureExist();
46 random.delete();
47 keyProvider.delete();
48 random = undefined;
49 keyProvider = undefined;
50};
51
52const moduleInitializer = new ModuleInitializer();
53const FOUNDATION_MODULE_KEY = 'foundation';
54moduleInitializer.addModule(FOUNDATION_MODULE_KEY, initFoundationModules);
55moduleInitializer.on('load', (name, modules) => {
56 if (name === FOUNDATION_MODULE_KEY) {
57 resetGlobalInstances();
58 createGlobalInstances(modules);
59 }
60});
61moduleInitializer.on('remove', name => {
62 if (name === FOUNDATION_MODULE_KEY) {
63 resetGlobalInstances();
64 }
65});
66const hasFoundationModules = () => moduleInitializer.hasModule(FOUNDATION_MODULE_KEY);
67const getFoundationModules = () => moduleInitializer.getModule(FOUNDATION_MODULE_KEY);
68const setFoundationModules = (foundationModules) => {
69 moduleInitializer.setModule(FOUNDATION_MODULE_KEY, foundationModules);
70};
71const initCrypto = moduleInitializer.loadModules;
72
73var HashAlgorithm;
74(function (HashAlgorithm) {
75 HashAlgorithm["SHA224"] = "SHA224";
76 HashAlgorithm["SHA256"] = "SHA256";
77 HashAlgorithm["SHA384"] = "SHA384";
78 HashAlgorithm["SHA512"] = "SHA512";
79})(HashAlgorithm || (HashAlgorithm = {}));
80
81var KeyPairType;
82(function (KeyPairType) {
83 KeyPairType["DEFAULT"] = "DEFAULT";
84 KeyPairType["ED25519"] = "ED25519";
85 KeyPairType["CURVE25519"] = "CURVE25519";
86 KeyPairType["SECP256R1"] = "SECP256R1";
87 KeyPairType["RSA_2048"] = "RSA_2048";
88 KeyPairType["RSA_3072"] = "RSA_3072";
89 KeyPairType["RSA_4096"] = "RSA_4096";
90 KeyPairType["RSA_8192"] = "RSA_8192";
91 KeyPairType["CURVE25519_ROUND5_ED25519_FALCON"] = "CURVE25519_ROUND5_ED25519_FALCON";
92 KeyPairType["CURVE25519_ED25519"] = "CURVE25519_ED25519";
93})(KeyPairType || (KeyPairType = {}));
94const getKeyPairTypeConfig = (keyPairType) => {
95 const { AlgId } = moduleInitializer.getModule('foundation');
96 switch (keyPairType) {
97 case KeyPairType.DEFAULT:
98 return {
99 type: KeyPairType.DEFAULT,
100 algId: AlgId.ED25519,
101 };
102 case KeyPairType.ED25519:
103 return {
104 type: KeyPairType.ED25519,
105 algId: AlgId.ED25519,
106 };
107 case KeyPairType.CURVE25519:
108 return {
109 type: KeyPairType.CURVE25519,
110 algId: AlgId.CURVE25519,
111 };
112 case KeyPairType.SECP256R1:
113 return {
114 type: KeyPairType.SECP256R1,
115 algId: AlgId.SECP256R1,
116 };
117 case KeyPairType.RSA_2048:
118 return {
119 type: KeyPairType.RSA_2048,
120 algId: AlgId.RSA,
121 bitlen: 2048,
122 };
123 case KeyPairType.RSA_3072:
124 return {
125 type: KeyPairType.RSA_3072,
126 algId: AlgId.RSA,
127 bitlen: 3072,
128 };
129 case KeyPairType.RSA_4096:
130 return {
131 type: KeyPairType.RSA_4096,
132 algId: AlgId.RSA,
133 bitlen: 4096,
134 };
135 case KeyPairType.RSA_8192:
136 return {
137 type: KeyPairType.RSA_8192,
138 algId: AlgId.RSA,
139 bitlen: 8192,
140 };
141 case KeyPairType.CURVE25519_ROUND5_ED25519_FALCON:
142 return {
143 type: KeyPairType.CURVE25519_ROUND5_ED25519_FALCON,
144 cipherAlgIds: [AlgId.CURVE25519, AlgId.ROUND5_ND_1CCA_5D],
145 signerAlgIds: [AlgId.ED25519, AlgId.FALCON],
146 };
147 case KeyPairType.CURVE25519_ED25519:
148 return {
149 type: KeyPairType.CURVE25519_ED25519,
150 cipherAlgIds: [AlgId.CURVE25519, AlgId.NONE],
151 signerAlgIds: [AlgId.ED25519, AlgId.NONE],
152 };
153 default:
154 throw new TypeError(`Unknown key pair type '${keyPairType}'.`);
155 }
156};
157const isRSAKeyPairType = (keyPairType) => keyPairType === KeyPairType.RSA_2048 ||
158 keyPairType === KeyPairType.RSA_3072 ||
159 keyPairType === KeyPairType.RSA_4096 ||
160 keyPairType === KeyPairType.RSA_8192;
161const isCompoundKeyPairType = (keyPairType) => keyPairType === KeyPairType.CURVE25519_ROUND5_ED25519_FALCON ||
162 keyPairType === KeyPairType.CURVE25519_ED25519;
163
164const DATA_SIGNATURE_KEY = NodeBuffer.from('VIRGIL-DATA-SIGNATURE', 'utf8');
165const DATA_SIGNER_ID_KEY = NodeBuffer.from('VIRGIL-DATA-SIGNER-ID', 'utf8');
166const PADDING_LEN = 160;
167const MIN_GROUP_ID_BYTE_LENGTH = 10;
168
169class VirgilPrivateKey {
170 get isDisposed() {
171 return this._isDisposed;
172 }
173 constructor(indentifier, lowLevelPrivateKey) {
174 this.identifier = toBuffer(indentifier);
175 this.lowLevelPrivateKey = lowLevelPrivateKey;
176 this._isDisposed = false;
177 }
178 dispose() {
179 this.lowLevelPrivateKey.delete();
180 this._isDisposed = true;
181 }
182}
183
184class VirgilPublicKey {
185 get isDisposed() {
186 return this._isDisposed;
187 }
188 get key() {
189 const foundationModules = getFoundationModules();
190 const keyAsn1Serializer = new foundationModules.KeyAsn1Serializer();
191 try {
192 keyAsn1Serializer.setupDefaults();
193 return keyAsn1Serializer.serializePublicKey(this.lowLevelPublicKey);
194 }
195 finally {
196 keyAsn1Serializer.delete();
197 }
198 }
199 constructor(identifier, lowLevelPublicKey) {
200 this.identifier = toBuffer(identifier);
201 this.lowLevelPublicKey = lowLevelPublicKey;
202 this._isDisposed = false;
203 }
204 dispose() {
205 this.lowLevelPublicKey.delete();
206 this._isDisposed = true;
207 }
208}
209
210function validatePrivateKey(privateKey) {
211 if (!(privateKey instanceof VirgilPrivateKey)) {
212 throw new TypeError("An argument is not an instance of 'VirgilPrivateKey' class.");
213 }
214 if (privateKey.isDisposed) {
215 throw new TypeError("Cannot use an instance of 'VirgilPrivateKey' class after it was disposed.");
216 }
217}
218function validatePublicKey(publicKey) {
219 if (!(publicKey instanceof VirgilPublicKey)) {
220 throw new TypeError("An argument is not a 'VirgilPublicKey'.");
221 }
222 if (publicKey.isDisposed) {
223 throw new TypeError("Cannot use an instance of 'VirgilPublicKey' class after it was disposed.");
224 }
225}
226function validatePublicKeysArray(publicKeys) {
227 if (!Array.isArray(publicKeys)) {
228 throw new TypeError('An argument is not an array.');
229 }
230 if (!publicKeys.length) {
231 throw new TypeError("An array of 'VirgilPublicKey' instances should not be empty.");
232 }
233 publicKeys.forEach(validatePublicKey);
234}
235function validatePositiveNonZeroNumber(number) {
236 if (typeof number !== 'number') {
237 throw new TypeError('An argument is not a number.');
238 }
239 if (number <= 0) {
240 throw new TypeError(`An argument should be greater that '0', but received '${number}'.`);
241 }
242}
243function validateGroupId(groupId) {
244 if (!(groupId instanceof Uint8Array)) {
245 throw new TypeError("An argument is not an instance of 'Uint8Array' class.");
246 }
247 if (groupId.byteLength < MIN_GROUP_ID_BYTE_LENGTH) {
248 throw new TypeError(`An argument byte length is too small. Expected to be at least '${MIN_GROUP_ID_BYTE_LENGTH}' bytes.`);
249 }
250}
251
252function parseGroupSessionMessage(messageData) {
253 const message = getFoundationModules().GroupSessionMessage.deserialize(messageData);
254 const info = {
255 epochNumber: message.getEpoch(),
256 sessionId: toBuffer(message.getSessionId()).toString('hex'),
257 data: toBuffer(messageData).toString('base64'),
258 };
259 message.delete();
260 return info;
261}
262function getEpochNumberFromEpochMessage(epochMessageData) {
263 const epoch = getFoundationModules().GroupSessionMessage.deserialize(epochMessageData);
264 const epochNumber = epoch.getEpoch();
265 epoch.delete();
266 return epochNumber;
267}
268function createLowLevelSession(epochMessages) {
269 const module = getFoundationModules();
270 const session = new module.GroupSession();
271 session.rng = getRandom();
272 const deleteQueue = [];
273 try {
274 for (const epochMessageData of epochMessages) {
275 const epoch = getFoundationModules().GroupSessionMessage.deserialize(epochMessageData);
276 deleteQueue.push(epoch);
277 session.addEpoch(epoch);
278 }
279 return session;
280 }
281 finally {
282 while (deleteQueue.length) {
283 const obj = deleteQueue.pop();
284 obj && obj.delete();
285 }
286 }
287}
288function computeSessionId(groupId) {
289 const foundation = getFoundationModules();
290 const sha512 = new foundation.Sha512();
291 try {
292 return sha512.hash(groupId).subarray(0, 32);
293 }
294 finally {
295 sha512.delete();
296 }
297}
298function createInitialEpoch(sessionId) {
299 const foundation = getFoundationModules();
300 const ticket = new foundation.GroupSessionTicket();
301 ticket.rng = getRandom();
302 try {
303 ticket.setupTicketAsNew(sessionId);
304 return ticket.getTicketMessage();
305 }
306 finally {
307 ticket.delete();
308 }
309}
310
311function createVirgilGroupSession(epochMessages) {
312 epochMessages = epochMessages
313 .slice()
314 .sort((a, b) => getEpochNumberFromEpochMessage(a) - getEpochNumberFromEpochMessage(b));
315 return {
316 getSessionId() {
317 const session = createLowLevelSession(epochMessages);
318 const id = session.getSessionId();
319 session.delete();
320 return toBuffer(id).toString('hex');
321 },
322 getCurrentEpochNumber() {
323 return getEpochNumberFromEpochMessage(epochMessages[epochMessages.length - 1]);
324 },
325 encrypt(data, signingPrivateKey) {
326 const dataBytes = dataToUint8Array(data, 'utf8');
327 validatePrivateKey(signingPrivateKey);
328 let session;
329 try {
330 session = createLowLevelSession(epochMessages);
331 const message = session.encrypt(dataBytes, signingPrivateKey.lowLevelPrivateKey);
332 const encrypted = message.serialize();
333 message.delete();
334 return toBuffer(encrypted);
335 }
336 finally {
337 session && session.delete();
338 }
339 },
340 decrypt(encryptedData, verifyingPublicKey) {
341 const encryptedDataBytes = dataToUint8Array(encryptedData, 'base64');
342 validatePublicKey(verifyingPublicKey);
343 let session;
344 let message;
345 try {
346 session = createLowLevelSession(epochMessages);
347 message = getFoundationModules().GroupSessionMessage.deserialize(encryptedDataBytes);
348 return toBuffer(session.decrypt(message, verifyingPublicKey.lowLevelPublicKey));
349 }
350 finally {
351 message && message.delete();
352 session && session.delete();
353 }
354 },
355 addNewEpoch() {
356 const session = createLowLevelSession(epochMessages);
357 try {
358 const newEpochTicket = session.createGroupTicket();
359 const newEpoch = newEpochTicket.getTicketMessage();
360 const newEpochMessage = newEpoch.serialize();
361 epochMessages.push(newEpochMessage);
362 newEpoch.delete();
363 newEpochTicket.delete();
364 return parseGroupSessionMessage(newEpochMessage);
365 }
366 finally {
367 session.delete();
368 }
369 },
370 export() {
371 return epochMessages.map(toBuffer);
372 },
373 parseMessage(messageData) {
374 const messageBytes = dataToUint8Array(messageData, 'base64');
375 return parseGroupSessionMessage(messageBytes);
376 },
377 };
378}
379
380const toArray = (val) => {
381 return val == null ? [] : Array.isArray(val) ? val : [val];
382};
383
384var VirgilCryptoErrorStatus;
385(function (VirgilCryptoErrorStatus) {
386 VirgilCryptoErrorStatus["STREAM_ILLEGAL_STATE"] = "STREAM_ILLEGAL_STATE";
387 VirgilCryptoErrorStatus["DATA_NOT_SIGNED"] = "DATA_NOT_SIGNED";
388 VirgilCryptoErrorStatus["SIGNER_NOT_FOUND"] = "SIGNER_NOT_FOUND";
389 VirgilCryptoErrorStatus["INVALID_SIGNATURE"] = "INVALID_SIGNATURE";
390})(VirgilCryptoErrorStatus || (VirgilCryptoErrorStatus = {}));
391class VirgilCryptoError extends Error {
392 constructor(errorStatus, message) {
393 super(message || VirgilCryptoError.DEFAULT_MESSAGE);
394 Object.setPrototypeOf(this, VirgilCryptoError.prototype);
395 this.name = 'VirgilCryptoError';
396 this.status = errorStatus;
397 }
398}
399VirgilCryptoError.DEFAULT_MESSAGE = "Use the 'status' property and 'VirgilCryptoErrorStatus' enum to check for specific error.";
400
401class VirgilStreamCipher {
402 get isRunning() {
403 return this._isRunning;
404 }
405 get isFinished() {
406 return this._isFinished;
407 }
408 get isDisposed() {
409 return this._isDisposed;
410 }
411 constructor(arg0, arg1) {
412 const foundationModules = getFoundationModules();
413 const publicKeys = toArray(arg0);
414 validatePublicKeysArray(publicKeys);
415 this.recipientCipher = new foundationModules.RecipientCipher();
416 this.aes256Gcm = new foundationModules.Aes256Gcm();
417 this.recipientCipher.encryptionCipher = this.aes256Gcm;
418 this.recipientCipher.random = getRandom();
419 publicKeys.forEach(publicKey => {
420 this.recipientCipher.addKeyRecipient(publicKey.identifier, publicKey.lowLevelPublicKey);
421 });
422 if (arg1) {
423 const mySignature = dataToUint8Array(arg1, 'base64');
424 this.messageInfoCustomParams = this.recipientCipher.customParams();
425 this.messageInfoCustomParams.addData(DATA_SIGNATURE_KEY, mySignature);
426 }
427 this._isFinished = false;
428 this._isRunning = false;
429 this._isDisposed = false;
430 }
431 start() {
432 this.ensureLegalState();
433 this.recipientCipher.startEncryption();
434 this._isRunning = true;
435 return toBuffer(this.recipientCipher.packMessageInfo());
436 }
437 update(data) {
438 this.ensureLegalState();
439 this.ensureIsRunning();
440 const myData = dataToUint8Array(data, 'utf8');
441 return toBuffer(this.recipientCipher.processEncryption(myData));
442 }
443 final(dispose = true) {
444 this.ensureLegalState();
445 this.ensureIsRunning();
446 try {
447 return toBuffer(this.recipientCipher.finishEncryption());
448 }
449 finally {
450 this._isFinished = true;
451 this._isRunning = false;
452 if (dispose) {
453 this.dispose();
454 }
455 }
456 }
457 dispose() {
458 if (this.messageInfoCustomParams) {
459 this.messageInfoCustomParams.delete();
460 }
461 this.aes256Gcm.delete();
462 this.recipientCipher.delete();
463 this._isDisposed = true;
464 }
465 ensureLegalState() {
466 if (this._isDisposed) {
467 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use cipher after the 'dispose' method has been called.");
468 }
469 if (this._isFinished) {
470 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use cipher after the 'final' method has been called.");
471 }
472 }
473 ensureIsRunning() {
474 if (!this._isRunning) {
475 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use cipher before the 'start' method.");
476 }
477 }
478}
479
480class VirgilStreamDecipher {
481 get isFinished() {
482 return this._isFinished;
483 }
484 get isDisposed() {
485 return this._isDisposed;
486 }
487 constructor(privateKey) {
488 this._isFinished = false;
489 this._isDisposed = false;
490 const foundationModules = getFoundationModules();
491 validatePrivateKey(privateKey);
492 this.recipientCipher = new foundationModules.RecipientCipher();
493 try {
494 this.recipientCipher.startDecryptionWithKey(privateKey.identifier, privateKey.lowLevelPrivateKey, new Uint8Array());
495 }
496 catch (error) {
497 this.recipientCipher.delete();
498 throw error;
499 }
500 }
501 getSignature() {
502 if (this._isDisposed) {
503 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot get signature after the 'dispose' method has been called.");
504 }
505 if (!this._isFinished) {
506 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot get signature before the 'final' method has been called.");
507 }
508 const messageInfoCustomParams = this.recipientCipher.customParams();
509 try {
510 return toBuffer(messageInfoCustomParams.findData(DATA_SIGNATURE_KEY));
511 }
512 finally {
513 messageInfoCustomParams.delete();
514 }
515 }
516 update(data) {
517 this.ensureLegalState();
518 const myData = dataToUint8Array(data, 'utf8');
519 return toBuffer(this.recipientCipher.processDecryption(myData));
520 }
521 final(dispose = true) {
522 this.ensureLegalState();
523 try {
524 return toBuffer(this.recipientCipher.finishDecryption());
525 }
526 finally {
527 this._isFinished = true;
528 if (dispose) {
529 this.dispose();
530 }
531 }
532 }
533 dispose() {
534 this.recipientCipher.delete();
535 this._isDisposed = true;
536 }
537 ensureLegalState() {
538 if (this._isDisposed) {
539 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use cipher after the 'dispose' method has been called.");
540 }
541 if (this._isFinished) {
542 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use cipher after the 'final' method has been called.");
543 }
544 }
545}
546
547class VirgilStreamDecryptAndVerify {
548 constructor() {
549 const foundation = getFoundationModules();
550 this.paddingParams = foundation.PaddingParams.newWithConstraints(PADDING_LEN, PADDING_LEN);
551 this.recipientCipher = new foundation.RecipientCipher();
552 this.recipientCipher.random = getRandom();
553 this.recipientCipher.paddingParams = this.paddingParams;
554 this._isDisposed = false;
555 this._isFinished = false;
556 }
557 start(privateKey) {
558 this.ensureLegalState();
559 validatePrivateKey(privateKey);
560 this.recipientCipher.startDecryptionWithKey(privateKey.identifier, privateKey.lowLevelPrivateKey, new Uint8Array());
561 }
562 update(data) {
563 this.ensureLegalState();
564 const myData = dataToUint8Array(data);
565 const processEncryption = this.recipientCipher.processDecryption(myData);
566 return toBuffer(processEncryption);
567 }
568 final() {
569 this.ensureLegalState();
570 const finishDecryption = this.recipientCipher.finishDecryption();
571 try {
572 return toBuffer(finishDecryption);
573 }
574 finally {
575 this._isFinished = true;
576 }
577 }
578 verify(arg0, arg1 = true) {
579 const publicKeys = toArray(arg0);
580 validatePublicKeysArray(publicKeys);
581 if (this._isDisposed) {
582 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot verify signature after the 'dispose' method has been called.");
583 }
584 if (!this._isFinished) {
585 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot verify signature before the 'final' method has been called.");
586 }
587 let signerInfoList;
588 try {
589 if (!this.recipientCipher.isDataSigned()) {
590 throw new VirgilCryptoError(VirgilCryptoErrorStatus.DATA_NOT_SIGNED);
591 }
592 signerInfoList = this.recipientCipher.signerInfos();
593 if (!signerInfoList.hasItem()) {
594 throw new VirgilCryptoError(VirgilCryptoErrorStatus.DATA_NOT_SIGNED);
595 }
596 const signerInfo = signerInfoList.item();
597 let signerPublicKey;
598 for (let i = 0; i < publicKeys.length; i += 1) {
599 if (NodeBuffer.compare(signerInfo.signerId(), publicKeys[i].identifier) === 0) {
600 signerPublicKey = publicKeys[i];
601 break;
602 }
603 if (i === publicKeys.length - 1) {
604 throw new VirgilCryptoError(VirgilCryptoErrorStatus.SIGNER_NOT_FOUND);
605 }
606 }
607 if (!this.recipientCipher.verifySignerInfo(signerInfo, signerPublicKey.lowLevelPublicKey)) {
608 throw new VirgilCryptoError(VirgilCryptoErrorStatus.INVALID_SIGNATURE);
609 }
610 }
611 finally {
612 if (signerInfoList) {
613 signerInfoList.delete();
614 }
615 if (arg1) {
616 this.dispose();
617 }
618 }
619 }
620 dispose() {
621 this.paddingParams.delete();
622 this.recipientCipher.delete();
623 this._isDisposed = true;
624 }
625 ensureLegalState() {
626 if (this._isDisposed) {
627 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use cipher after the 'dispose' method has been called.");
628 }
629 if (this._isFinished) {
630 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use cipher after the 'final' method has been called.");
631 }
632 }
633}
634
635class VirgilStreamSignAndEncrypt {
636 get isRunning() {
637 return this._isRunning;
638 }
639 get isFinished() {
640 return this._isFinished;
641 }
642 get isDisposed() {
643 return this._isDisposed;
644 }
645 constructor(arg0, arg1, arg2) {
646 validatePrivateKey(arg0);
647 const publicKeys = toArray(arg1);
648 validatePublicKeysArray(publicKeys);
649 const foundation = getFoundationModules();
650 const random = getRandom();
651 this.recipientCipher = new foundation.RecipientCipher();
652 this.aes256Gcm = new foundation.Aes256Gcm();
653 this.sha512 = new foundation.Sha512();
654 this.recipientCipher.encryptionCipher = this.aes256Gcm;
655 this.recipientCipher.random = random;
656 this.recipientCipher.signerHash = this.sha512;
657 if (arg2) {
658 this.randomPadding = new foundation.RandomPadding();
659 this.randomPadding.random = random;
660 this.recipientCipher.encryptionPadding = this.randomPadding;
661 this.paddingParams = foundation.PaddingParams.newWithConstraints(PADDING_LEN, PADDING_LEN);
662 this.recipientCipher.paddingParams = this.paddingParams;
663 }
664 publicKeys.forEach(publicKey => {
665 this.recipientCipher.addKeyRecipient(publicKey.identifier, publicKey.lowLevelPublicKey);
666 });
667 try {
668 this.recipientCipher.addSigner(arg0.identifier, arg0.lowLevelPrivateKey);
669 this._isDisposed = false;
670 this._isRunning = false;
671 this._isFinished = false;
672 }
673 catch (error) {
674 this.dispose();
675 throw error;
676 }
677 }
678 start(length) {
679 this.ensureLegalState();
680 this.recipientCipher.startSignedEncryption(length);
681 const messageInfo = this.recipientCipher.packMessageInfo();
682 this._isRunning = true;
683 return toBuffer(messageInfo);
684 }
685 update(data) {
686 this.ensureLegalState();
687 this.ensureIsRunning();
688 const myData = dataToUint8Array(data);
689 const processEncryption = this.recipientCipher.processEncryption(myData);
690 return toBuffer(processEncryption);
691 }
692 final(dispose = true) {
693 this.ensureLegalState();
694 this.ensureIsRunning();
695 const finishEncryption = this.recipientCipher.finishEncryption();
696 const messageInfoFooter = this.recipientCipher.packMessageInfoFooter();
697 try {
698 return NodeBuffer.concat([finishEncryption, messageInfoFooter]);
699 }
700 finally {
701 this._isFinished = true;
702 this._isRunning = false;
703 if (dispose) {
704 this.dispose();
705 }
706 }
707 }
708 dispose() {
709 this.sha512.delete();
710 this.aes256Gcm.delete();
711 if (this.randomPadding) {
712 this.randomPadding.delete();
713 }
714 if (this.paddingParams) {
715 this.paddingParams.delete();
716 }
717 this.recipientCipher.delete();
718 this._isDisposed = true;
719 }
720 ensureLegalState() {
721 if (this._isDisposed) {
722 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use cipher after the 'dispose' method has been called.");
723 }
724 if (this._isFinished) {
725 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use cipher after the 'final' method has been called.");
726 }
727 }
728 ensureIsRunning() {
729 if (!this._isRunning) {
730 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use cipher before the 'start' method.");
731 }
732 }
733}
734
735class VirgilStreamSigner {
736 get isDisposed() {
737 return this._isDisposed;
738 }
739 constructor() {
740 this._isDisposed = false;
741 const foundationModules = getFoundationModules();
742 this.signer = new foundationModules.Signer();
743 this.sha512 = new foundationModules.Sha512();
744 this.signer.hash = this.sha512;
745 this.signer.random = getRandom();
746 this.signer.reset();
747 }
748 update(data) {
749 if (this._isDisposed) {
750 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use signer after the 'dispose' method has been called.");
751 }
752 const myData = dataToUint8Array(data, 'utf8');
753 this.signer.appendData(myData);
754 return this;
755 }
756 sign(privateKey, final = true) {
757 if (this._isDisposed) {
758 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. The VirgilStreamSigner has been disposed. Pass 'false' as the second argument to the 'sign' method if you need to generate more than one signature.");
759 }
760 validatePrivateKey(privateKey);
761 const result = this.signer.sign(privateKey.lowLevelPrivateKey);
762 if (final) {
763 this.dispose();
764 }
765 return toBuffer(result);
766 }
767 dispose() {
768 this.sha512.delete();
769 this.signer.delete();
770 this._isDisposed = true;
771 }
772}
773
774class VirgilStreamVerifier {
775 get isDisposed() {
776 return this._isDisposed;
777 }
778 constructor(signature) {
779 this._isDisposed = false;
780 const foundationModules = getFoundationModules();
781 const mySignature = dataToUint8Array(signature, 'base64');
782 this.verifier = new foundationModules.Verifier();
783 try {
784 this.verifier.reset(mySignature);
785 }
786 catch (error) {
787 this.verifier.delete();
788 throw error;
789 }
790 }
791 update(data) {
792 if (this._isDisposed) {
793 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. Cannot use signer after the 'dispose' method has been called.");
794 }
795 const myData = dataToUint8Array(data, 'utf8');
796 this.verifier.appendData(myData);
797 return this;
798 }
799 verify(publicKey, final = true) {
800 if (this._isDisposed) {
801 throw new VirgilCryptoError(VirgilCryptoErrorStatus.STREAM_ILLEGAL_STATE, "Illegal state. The VirgilStreamVerifier has been disposed. Pass 'false' as the second argument to the 'verify' method if you need to verify with more than one public key.");
802 }
803 validatePublicKey(publicKey);
804 const result = this.verifier.verify(publicKey.lowLevelPublicKey);
805 if (final) {
806 this.dispose();
807 }
808 return result;
809 }
810 dispose() {
811 this.verifier.delete();
812 this._isDisposed = true;
813 }
814}
815
816class VirgilCrypto {
817 constructor(options = {}) {
818 this.hashAlgorithm = HashAlgorithm;
819 this.keyPairType = KeyPairType;
820 this.defaultKeyPairType = options.defaultKeyPairType || KeyPairType.DEFAULT;
821 this.useSha256Identifiers = options.useSha256Identifiers || false;
822 }
823 generateKeys(type) {
824 const keyPairType = type ? type : this.defaultKeyPairType;
825 const keyPairTypeConfig = getKeyPairTypeConfig(keyPairType);
826 return this.generateKeyPair(getKeyProvider(), keyPairTypeConfig);
827 }
828 generateKeysFromKeyMaterial(keyMaterial, type) {
829 const keyPairType = type ? type : this.defaultKeyPairType;
830 const keyPairTypeConfig = getKeyPairTypeConfig(keyPairType);
831 const myKeyMaterial = dataToUint8Array(keyMaterial, 'base64');
832 const foundation = getFoundationModules();
833 const keyMaterialRng = new foundation.KeyMaterialRng();
834 keyMaterialRng.resetKeyMaterial(myKeyMaterial);
835 const keyProvider = new foundation.KeyProvider();
836 keyProvider.random = keyMaterialRng;
837 try {
838 keyProvider.setupDefaults();
839 }
840 catch (error) {
841 keyMaterialRng.delete();
842 keyProvider.delete();
843 throw error;
844 }
845 try {
846 return this.generateKeyPair(keyProvider, keyPairTypeConfig);
847 }
848 finally {
849 keyMaterialRng.delete();
850 keyProvider.delete();
851 }
852 }
853 importPrivateKey(rawPrivateKey) {
854 const keyProvider = getKeyProvider();
855 const serializedPrivateKey = dataToUint8Array(rawPrivateKey, 'base64');
856 const lowLevelPrivateKey = keyProvider.importPrivateKey(serializedPrivateKey);
857 const lowLevelPublicKey = lowLevelPrivateKey.extractPublicKey();
858 try {
859 const serializedPublicKey = keyProvider.exportPublicKey(lowLevelPublicKey);
860 const identifier = this.calculateKeyPairIdentifier(serializedPublicKey);
861 return new VirgilPrivateKey(identifier, lowLevelPrivateKey);
862 }
863 finally {
864 lowLevelPublicKey.delete();
865 }
866 }
867 exportPrivateKey(privateKey) {
868 validatePrivateKey(privateKey);
869 const keyProvider = getKeyProvider();
870 const publicKeyData = keyProvider.exportPrivateKey(privateKey.lowLevelPrivateKey);
871 return toBuffer(publicKeyData);
872 }
873 importPublicKey(rawPublicKey) {
874 const serializedPublicKey = dataToUint8Array(rawPublicKey, 'base64');
875 const keyProvider = getKeyProvider();
876 const lowLevelPublicKey = keyProvider.importPublicKey(serializedPublicKey);
877 const identifier = this.calculateKeyPairIdentifier(serializedPublicKey);
878 return new VirgilPublicKey(identifier, lowLevelPublicKey);
879 }
880 exportPublicKey(publicKey) {
881 validatePublicKey(publicKey);
882 const keyProvider = getKeyProvider();
883 const publicKeyData = keyProvider.exportPublicKey(publicKey.lowLevelPublicKey);
884 return toBuffer(publicKeyData);
885 }
886 encrypt(arg0, arg1, arg2) {
887 const data = dataToUint8Array(arg0, 'utf8');
888 const publicKeys = toArray(arg1);
889 validatePublicKeysArray(publicKeys);
890 const foundation = getFoundationModules();
891 const random = getRandom();
892 const recipientCipher = new foundation.RecipientCipher();
893 const aes256Gcm = new foundation.Aes256Gcm();
894 recipientCipher.encryptionCipher = aes256Gcm;
895 recipientCipher.random = random;
896 let randomPadding;
897 let paddingParams;
898 if (arg2) {
899 randomPadding = new foundation.RandomPadding();
900 randomPadding.random = random;
901 recipientCipher.encryptionPadding = randomPadding;
902 paddingParams = foundation.PaddingParams.newWithConstraints(PADDING_LEN, PADDING_LEN);
903 recipientCipher.paddingParams = paddingParams;
904 }
905 publicKeys.forEach(({ identifier }, index) => {
906 recipientCipher.addKeyRecipient(identifier, publicKeys[index].lowLevelPublicKey);
907 });
908 try {
909 recipientCipher.startEncryption();
910 const messageInfo = recipientCipher.packMessageInfo();
911 const processEncryption = recipientCipher.processEncryption(data);
912 const finishEncryption = recipientCipher.finishEncryption();
913 return NodeBuffer.concat([messageInfo, processEncryption, finishEncryption]);
914 }
915 finally {
916 aes256Gcm.delete();
917 if (paddingParams) {
918 paddingParams.delete();
919 }
920 if (randomPadding) {
921 randomPadding.delete();
922 }
923 recipientCipher.delete();
924 }
925 }
926 decrypt(encryptedData, privateKey) {
927 const myData = dataToUint8Array(encryptedData, 'base64');
928 validatePrivateKey(privateKey);
929 const foundation = getFoundationModules();
930 const recipientCipher = new foundation.RecipientCipher();
931 recipientCipher.random = getRandom();
932 const paddingParams = foundation.PaddingParams.newWithConstraints(PADDING_LEN, PADDING_LEN);
933 recipientCipher.paddingParams = paddingParams;
934 try {
935 recipientCipher.startDecryptionWithKey(privateKey.identifier, privateKey.lowLevelPrivateKey, new Uint8Array());
936 const processDecryption = recipientCipher.processDecryption(myData);
937 const finishDecryption = recipientCipher.finishDecryption();
938 return NodeBuffer.concat([processDecryption, finishDecryption]);
939 }
940 finally {
941 paddingParams.delete();
942 recipientCipher.delete();
943 }
944 }
945 calculateHash(data, algorithm = HashAlgorithm.SHA512) {
946 const myData = dataToUint8Array(data, 'utf8');
947 let result;
948 switch (algorithm) {
949 case HashAlgorithm.SHA224:
950 result = this.createHash(myData, getFoundationModules().Sha224);
951 break;
952 case HashAlgorithm.SHA256:
953 result = this.createHash(myData, getFoundationModules().Sha256);
954 break;
955 case HashAlgorithm.SHA384:
956 result = this.createHash(myData, getFoundationModules().Sha384);
957 break;
958 case HashAlgorithm.SHA512:
959 result = this.createHash(myData, getFoundationModules().Sha512);
960 break;
961 default:
962 throw new TypeError('Unknown hash algorithm');
963 }
964 return toBuffer(result);
965 }
966 extractPublicKey(privateKey) {
967 validatePrivateKey(privateKey);
968 const lowLevelPublicKey = privateKey.lowLevelPrivateKey.extractPublicKey();
969 return new VirgilPublicKey(privateKey.identifier, lowLevelPublicKey);
970 }
971 calculateSignature(data, privateKey) {
972 const myData = dataToUint8Array(data, 'utf8');
973 validatePrivateKey(privateKey);
974 const foundation = getFoundationModules();
975 const signer = new foundation.Signer();
976 const sha512 = new foundation.Sha512();
977 signer.random = getRandom();
978 signer.hash = sha512;
979 signer.reset();
980 signer.appendData(myData);
981 try {
982 const signature = signer.sign(privateKey.lowLevelPrivateKey);
983 return toBuffer(signature);
984 }
985 finally {
986 signer.delete();
987 sha512.delete();
988 }
989 }
990 verifySignature(data, signature, publicKey) {
991 const myData = dataToUint8Array(data, 'utf8');
992 const mySignature = dataToUint8Array(signature, 'base64');
993 validatePublicKey(publicKey);
994 const foundation = getFoundationModules();
995 const verifier = new foundation.Verifier();
996 try {
997 verifier.reset(mySignature);
998 }
999 catch (error) {
1000 verifier.delete();
1001 throw error;
1002 }
1003 verifier.appendData(myData);
1004 const result = verifier.verify(publicKey.lowLevelPublicKey);
1005 verifier.delete();
1006 return result;
1007 }
1008 signAndEncrypt(arg0, arg1, arg2, arg3) {
1009 const data = dataToUint8Array(arg0, 'utf8');
1010 validatePrivateKey(arg1);
1011 const publicKeys = toArray(arg2);
1012 validatePublicKeysArray(publicKeys);
1013 const { messageInfo, processEncryption, finishEncryption, messageInfoFooter, } = this._signAndEncrypt(data, arg1, publicKeys, arg3);
1014 return NodeBuffer.concat([messageInfo, processEncryption, finishEncryption, messageInfoFooter]);
1015 }
1016 signThenEncrypt(arg0, arg1, arg2, arg3) {
1017 const data = dataToUint8Array(arg0, 'utf8');
1018 validatePrivateKey(arg1);
1019 const publicKeys = toArray(arg2);
1020 validatePublicKeysArray(publicKeys);
1021 const { messageInfo, processEncryption, finishEncryption } = this._signThenEncrypt(data, arg1, publicKeys, arg3);
1022 return NodeBuffer.concat([messageInfo, processEncryption, finishEncryption]);
1023 }
1024 decryptAndVerify(arg0, arg1, arg2) {
1025 const encryptedData = dataToUint8Array(arg0, 'base64');
1026 validatePrivateKey(arg1);
1027 const publicKeys = toArray(arg2);
1028 validatePublicKeysArray(publicKeys);
1029 return this._decryptAndVerify(encryptedData, new Uint8Array(), arg1, publicKeys);
1030 }
1031 decryptThenVerify(arg0, arg1, arg2) {
1032 const encryptedData = dataToUint8Array(arg0, 'base64');
1033 validatePrivateKey(arg1);
1034 const publicKeys = toArray(arg2);
1035 validatePublicKeysArray(publicKeys);
1036 return this._decryptThenVerify(encryptedData, new Uint8Array(), arg1, publicKeys);
1037 }
1038 getRandomBytes(length) {
1039 validatePositiveNonZeroNumber(length);
1040 const bytes = getRandom().random(length);
1041 return toBuffer(bytes);
1042 }
1043 signThenEncryptDetached(arg0, arg1, arg2, arg3) {
1044 const data = dataToUint8Array(arg0, 'utf8');
1045 validatePrivateKey(arg1);
1046 const publicKeys = toArray(arg2);
1047 validatePublicKeysArray(publicKeys);
1048 const { messageInfo, processEncryption, finishEncryption } = this._signThenEncrypt(data, arg1, publicKeys, arg3);
1049 return {
1050 encryptedData: NodeBuffer.concat([processEncryption, finishEncryption]),
1051 metadata: toBuffer(messageInfo),
1052 };
1053 }
1054 decryptThenVerifyDetached(arg0, arg1, arg2, arg3) {
1055 const encryptedData = dataToUint8Array(arg0, 'base64');
1056 const messageInfo = dataToUint8Array(arg1, 'base64');
1057 validatePrivateKey(arg2);
1058 const publicKeys = toArray(arg3);
1059 validatePublicKeysArray(publicKeys);
1060 return this._decryptThenVerify(encryptedData, messageInfo, arg2, publicKeys);
1061 }
1062 createStreamCipher(arg0, arg1) {
1063 return new VirgilStreamCipher(arg0, arg1);
1064 }
1065 createStreamDecipher(privateKey) {
1066 return new VirgilStreamDecipher(privateKey);
1067 }
1068 createStreamSignAndEncrypt(arg0, arg1, arg2) {
1069 return new VirgilStreamSignAndEncrypt(arg0, arg1, arg2);
1070 }
1071 createStreamDecryptAndVerify() {
1072 return new VirgilStreamDecryptAndVerify();
1073 }
1074 createStreamSigner() {
1075 return new VirgilStreamSigner();
1076 }
1077 createStreamVerifier(signature) {
1078 return new VirgilStreamVerifier(signature);
1079 }
1080 generateGroupSession(groupId) {
1081 const groupIdBytes = dataToUint8Array(groupId, 'utf8');
1082 validateGroupId(groupIdBytes);
1083 const sessionId = computeSessionId(groupIdBytes);
1084 const initialEpoch = createInitialEpoch(sessionId);
1085 const initialEpochMessage = initialEpoch.serialize();
1086 initialEpoch.delete();
1087 return createVirgilGroupSession([initialEpochMessage]);
1088 }
1089 importGroupSession(epochMessages) {
1090 if (!Array.isArray(epochMessages)) {
1091 throw new TypeError('Epoch messages must be an array.');
1092 }
1093 if (epochMessages.length === 0) {
1094 throw new TypeError('Epoch messages must not be empty.');
1095 }
1096 return createVirgilGroupSession(epochMessages.map(it => dataToUint8Array(it, 'base64')));
1097 }
1098 calculateGroupSessionId(groupId) {
1099 const groupIdBytes = dataToUint8Array(groupId, 'utf8');
1100 validateGroupId(groupIdBytes);
1101 return toBuffer(computeSessionId(groupIdBytes)).toString('hex');
1102 }
1103 createHash(data, HashClass) {
1104 const hashInstance = new HashClass();
1105 const hash = hashInstance.hash(data);
1106 hashInstance.delete();
1107 return hash;
1108 }
1109 calculateKeyPairIdentifier(serializedPublicKey) {
1110 if (this.useSha256Identifiers) {
1111 return this.createHash(serializedPublicKey, getFoundationModules().Sha256);
1112 }
1113 return this.createHash(serializedPublicKey, getFoundationModules().Sha512).slice(0, 8);
1114 }
1115 generateKeyPair(keyProvider, keyPairTypeConfig) {
1116 let lowLevelPrivateKey;
1117 if (isCompoundKeyPairType(keyPairTypeConfig.type)) {
1118 const [cipherFirstKeyAlgId, cipherSecondKeyAlgId] = keyPairTypeConfig.cipherAlgIds;
1119 const [signerFirstKeyAlgId, signerSecondKeyAlgId] = keyPairTypeConfig.signerAlgIds;
1120 lowLevelPrivateKey = keyProvider.generateCompoundHybridPrivateKey(cipherFirstKeyAlgId, cipherSecondKeyAlgId, signerFirstKeyAlgId, signerSecondKeyAlgId);
1121 }
1122 else {
1123 if (isRSAKeyPairType(keyPairTypeConfig.type)) {
1124 keyProvider.setRsaParams(keyPairTypeConfig.bitlen);
1125 }
1126 lowLevelPrivateKey = keyProvider.generatePrivateKey(keyPairTypeConfig.algId);
1127 }
1128 const lowLevelPublicKey = lowLevelPrivateKey.extractPublicKey();
1129 let serializedPublicKey;
1130 try {
1131 serializedPublicKey = keyProvider.exportPublicKey(lowLevelPublicKey);
1132 }
1133 catch (error) {
1134 lowLevelPrivateKey.delete();
1135 lowLevelPublicKey.delete();
1136 throw error;
1137 }
1138 const identifier = this.calculateKeyPairIdentifier(serializedPublicKey);
1139 return {
1140 privateKey: new VirgilPrivateKey(identifier, lowLevelPrivateKey),
1141 publicKey: new VirgilPublicKey(identifier, lowLevelPublicKey),
1142 };
1143 }
1144 _signAndEncrypt(data, privateKey, publicKeys, enablePadding) {
1145 const foundation = getFoundationModules();
1146 const random = getRandom();
1147 const recipientCipher = new foundation.RecipientCipher();
1148 const aes256Gcm = new foundation.Aes256Gcm();
1149 const sha512 = new foundation.Sha512();
1150 recipientCipher.encryptionCipher = aes256Gcm;
1151 recipientCipher.random = random;
1152 recipientCipher.signerHash = sha512;
1153 let randomPadding;
1154 let paddingParams;
1155 if (enablePadding) {
1156 randomPadding = new foundation.RandomPadding();
1157 randomPadding.random = random;
1158 recipientCipher.encryptionPadding = randomPadding;
1159 paddingParams = foundation.PaddingParams.newWithConstraints(PADDING_LEN, PADDING_LEN);
1160 recipientCipher.paddingParams = paddingParams;
1161 }
1162 publicKeys.forEach(({ identifier }, index) => {
1163 recipientCipher.addKeyRecipient(identifier, publicKeys[index].lowLevelPublicKey);
1164 });
1165 try {
1166 recipientCipher.addSigner(privateKey.identifier, privateKey.lowLevelPrivateKey);
1167 recipientCipher.startSignedEncryption(data.length);
1168 const messageInfo = recipientCipher.packMessageInfo();
1169 const processEncryption = recipientCipher.processEncryption(data);
1170 const finishEncryption = recipientCipher.finishEncryption();
1171 const messageInfoFooter = recipientCipher.packMessageInfoFooter();
1172 return {
1173 messageInfo,
1174 processEncryption,
1175 finishEncryption,
1176 messageInfoFooter,
1177 };
1178 }
1179 finally {
1180 sha512.delete();
1181 aes256Gcm.delete();
1182 if (randomPadding) {
1183 randomPadding.delete();
1184 }
1185 if (paddingParams) {
1186 paddingParams.delete();
1187 }
1188 recipientCipher.delete();
1189 }
1190 }
1191 _signThenEncrypt(data, privateKey, publicKeys, enablePadding) {
1192 const foundation = getFoundationModules();
1193 const random = getRandom();
1194 const recipientCipher = new foundation.RecipientCipher();
1195 const aes256Gcm = new foundation.Aes256Gcm();
1196 recipientCipher.encryptionCipher = aes256Gcm;
1197 recipientCipher.random = random;
1198 let randomPadding;
1199 let paddingParams;
1200 if (enablePadding) {
1201 randomPadding = new foundation.RandomPadding();
1202 randomPadding.random = random;
1203 recipientCipher.encryptionPadding = randomPadding;
1204 paddingParams = foundation.PaddingParams.newWithConstraints(PADDING_LEN, PADDING_LEN);
1205 recipientCipher.paddingParams = paddingParams;
1206 }
1207 publicKeys.forEach(({ identifier }, index) => {
1208 recipientCipher.addKeyRecipient(identifier, publicKeys[index].lowLevelPublicKey);
1209 });
1210 const messageInfoCustomParams = recipientCipher.customParams();
1211 try {
1212 const signature = this.calculateSignature(data, privateKey);
1213 messageInfoCustomParams.addData(DATA_SIGNATURE_KEY, signature);
1214 messageInfoCustomParams.addData(DATA_SIGNER_ID_KEY, privateKey.identifier);
1215 recipientCipher.startEncryption();
1216 const messageInfo = recipientCipher.packMessageInfo();
1217 const processEncryption = recipientCipher.processEncryption(data);
1218 const finishEncryption = recipientCipher.finishEncryption();
1219 return {
1220 messageInfo,
1221 processEncryption,
1222 finishEncryption,
1223 };
1224 }
1225 finally {
1226 messageInfoCustomParams.delete();
1227 aes256Gcm.delete();
1228 if (randomPadding) {
1229 randomPadding.delete();
1230 }
1231 if (paddingParams) {
1232 paddingParams.delete();
1233 }
1234 recipientCipher.delete();
1235 }
1236 }
1237 _decryptAndVerify(encryptedData, messageInfo, privateKey, publicKeys) {
1238 const foundation = getFoundationModules();
1239 const paddingParams = foundation.PaddingParams.newWithConstraints(PADDING_LEN, PADDING_LEN);
1240 const recipientCipher = new foundation.RecipientCipher();
1241 recipientCipher.random = getRandom();
1242 recipientCipher.paddingParams = paddingParams;
1243 let decryptedData;
1244 try {
1245 recipientCipher.startDecryptionWithKey(privateKey.identifier, privateKey.lowLevelPrivateKey, messageInfo);
1246 const processDecryption = recipientCipher.processDecryption(encryptedData);
1247 const finishDecryption = recipientCipher.finishDecryption();
1248 decryptedData = NodeBuffer.concat([processDecryption, finishDecryption]);
1249 }
1250 catch (error) {
1251 paddingParams.delete();
1252 recipientCipher.delete();
1253 throw error;
1254 }
1255 if (!recipientCipher.isDataSigned()) {
1256 paddingParams.delete();
1257 recipientCipher.delete();
1258 throw new VirgilCryptoError(VirgilCryptoErrorStatus.DATA_NOT_SIGNED);
1259 }
1260 const signerInfoList = recipientCipher.signerInfos();
1261 if (!signerInfoList.hasItem()) {
1262 paddingParams.delete();
1263 signerInfoList.delete();
1264 recipientCipher.delete();
1265 throw new VirgilCryptoError(VirgilCryptoErrorStatus.DATA_NOT_SIGNED);
1266 }
1267 const signerInfo = signerInfoList.item();
1268 let signerPublicKey;
1269 for (let i = 0; i < publicKeys.length; i += 1) {
1270 if (NodeBuffer.compare(signerInfo.signerId(), publicKeys[i].identifier) === 0) {
1271 signerPublicKey = publicKeys[i];
1272 break;
1273 }
1274 if (i === publicKeys.length - 1) {
1275 paddingParams.delete();
1276 signerInfo.delete();
1277 signerInfoList.delete();
1278 recipientCipher.delete();
1279 throw new VirgilCryptoError(VirgilCryptoErrorStatus.SIGNER_NOT_FOUND);
1280 }
1281 }
1282 if (!recipientCipher.verifySignerInfo(signerInfo, signerPublicKey.lowLevelPublicKey)) {
1283 paddingParams.delete();
1284 signerInfo.delete();
1285 signerInfoList.delete();
1286 recipientCipher.delete();
1287 throw new VirgilCryptoError(VirgilCryptoErrorStatus.INVALID_SIGNATURE);
1288 }
1289 paddingParams.delete();
1290 signerInfo.delete();
1291 signerInfoList.delete();
1292 recipientCipher.delete();
1293 return decryptedData;
1294 }
1295 _decryptThenVerify(encryptedData, messageInfo, privateKey, publicKeys) {
1296 const foundation = getFoundationModules();
1297 const paddingParams = foundation.PaddingParams.newWithConstraints(PADDING_LEN, PADDING_LEN);
1298 const recipientCipher = new foundation.RecipientCipher();
1299 recipientCipher.random = getRandom();
1300 recipientCipher.paddingParams = paddingParams;
1301 let decryptedData;
1302 try {
1303 recipientCipher.startDecryptionWithKey(privateKey.identifier, privateKey.lowLevelPrivateKey, messageInfo);
1304 const processDecryption = recipientCipher.processDecryption(encryptedData);
1305 const finishDecryption = recipientCipher.finishDecryption();
1306 decryptedData = NodeBuffer.concat([processDecryption, finishDecryption]);
1307 }
1308 catch (error) {
1309 paddingParams.delete();
1310 recipientCipher.delete();
1311 throw error;
1312 }
1313 const messageInfoCustomParams = recipientCipher.customParams();
1314 let signerPublicKey;
1315 if (publicKeys.length === 1) {
1316 signerPublicKey = publicKeys[0];
1317 }
1318 else {
1319 let signerId;
1320 try {
1321 signerId = messageInfoCustomParams.findData(DATA_SIGNER_ID_KEY);
1322 }
1323 catch (error) {
1324 paddingParams.delete();
1325 recipientCipher.delete();
1326 messageInfoCustomParams.delete();
1327 throw error;
1328 }
1329 for (let i = 0; i < publicKeys.length; i += 1) {
1330 if (NodeBuffer.compare(signerId, publicKeys[i].identifier) === 0) {
1331 signerPublicKey = publicKeys[i];
1332 break;
1333 }
1334 }
1335 if (!signerPublicKey) {
1336 messageInfoCustomParams.delete();
1337 paddingParams.delete();
1338 recipientCipher.delete();
1339 throw new VirgilCryptoError(VirgilCryptoErrorStatus.SIGNER_NOT_FOUND);
1340 }
1341 }
1342 try {
1343 const signature = messageInfoCustomParams.findData(DATA_SIGNATURE_KEY);
1344 const isValid = this.verifySignature(decryptedData, signature, signerPublicKey);
1345 if (!isValid) {
1346 throw new VirgilCryptoError(VirgilCryptoErrorStatus.INVALID_SIGNATURE);
1347 }
1348 return decryptedData;
1349 }
1350 finally {
1351 messageInfoCustomParams.delete();
1352 paddingParams.delete();
1353 recipientCipher.delete();
1354 }
1355 }
1356}
1357
1358export { HashAlgorithm, KeyPairType, VirgilCrypto, VirgilCryptoError, VirgilCryptoErrorStatus, VirgilPrivateKey, VirgilPublicKey, VirgilStreamCipher, VirgilStreamDecipher, VirgilStreamSigner, VirgilStreamVerifier, getFoundationModules, hasFoundationModules, initCrypto, moduleInitializer, setFoundationModules };