UNPKG

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