1 | import { BigInteger, SecureRandom } from 'jsbn';
|
2 | import Rusha from 'rusha';
|
3 | import * as CryptoJSlib from '@goodmind/node-cryptojs-aes';
|
4 | const { CryptoJS } = CryptoJSlib;
|
5 |
|
6 | import { inflate } from 'pako/lib/inflate';
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | import { eGCD_, greater, divide_, str2bigInt, equalsInt, isZero, bigInt2str, copy_, copyInt_, rightShift_, sub_, add_, powMod, bpe, one } from './leemon';
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | const rushaInstance = new Rusha(1024 * 1024);
|
19 |
|
20 | export function bigint(num) {
|
21 | return new BigInteger(num.toString(16), 16);
|
22 | }
|
23 |
|
24 | export function bigStringInt(strNum) {
|
25 | return new BigInteger(strNum, 10);
|
26 | }
|
27 |
|
28 | export function dHexDump(bytes) {
|
29 | const arr = [];
|
30 | for (let i = 0; i < bytes.length; i++) {
|
31 | if (i && !(i % 2)) {
|
32 | if (!(i % 16)) {
|
33 | arr.push('\n');
|
34 | } else if (!(i % 4)) {
|
35 | arr.push(' ');
|
36 | } else {
|
37 | arr.push(' ');
|
38 | }
|
39 | }
|
40 | arr.push((bytes[i] < 16 ? '0' : '') + bytes[i].toString(16));
|
41 | }
|
42 |
|
43 | console.log(arr.join(''));
|
44 | }
|
45 |
|
46 | export function bytesToHex(bytes = []) {
|
47 | const arr = [];
|
48 | for (let i = 0; i < bytes.length; i++) {
|
49 | arr.push((bytes[i] < 16 ? '0' : '') + (bytes[i] || 0).toString(16));
|
50 | }
|
51 | return arr.join('');
|
52 | }
|
53 |
|
54 | export function bytesFromHex(hexString) {
|
55 | const len = hexString.length;
|
56 | let start = 0;
|
57 | const bytes = [];
|
58 |
|
59 | if (hexString.length % 2) {
|
60 | bytes.push(parseInt(hexString.charAt(0), 16));
|
61 | start++;
|
62 | }
|
63 |
|
64 | for (let i = start; i < len; i += 2) {
|
65 | bytes.push(parseInt(hexString.substr(i, 2), 16));
|
66 | }
|
67 |
|
68 | return bytes;
|
69 | }
|
70 |
|
71 | export function bytesToBase64(bytes) {
|
72 | let mod3;
|
73 | let result = '';
|
74 |
|
75 | for (let nLen = bytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
|
76 | mod3 = nIdx % 3;
|
77 | nUint24 |= bytes[nIdx] << (16 >>> mod3 & 24);
|
78 | if (mod3 === 2 || nLen - nIdx === 1) {
|
79 | result += String.fromCharCode(uint6ToBase64(nUint24 >>> 18 & 63), uint6ToBase64(nUint24 >>> 12 & 63), uint6ToBase64(nUint24 >>> 6 & 63), uint6ToBase64(nUint24 & 63));
|
80 | nUint24 = 0;
|
81 | }
|
82 | }
|
83 |
|
84 | return result.replace(/A(?=A$|$)/g, '=');
|
85 | }
|
86 |
|
87 | export function uint6ToBase64(nUint6) {
|
88 | return nUint6 < 26 ? nUint6 + 65 : nUint6 < 52 ? nUint6 + 71 : nUint6 < 62 ? nUint6 - 4 : nUint6 === 62 ? 43 : nUint6 === 63 ? 47 : 65;
|
89 | }
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 | export function bytesCmp(bytes1, bytes2) {
|
138 | const len = bytes1.length;
|
139 | if (len !== bytes2.length) {
|
140 | return false;
|
141 | }
|
142 |
|
143 | for (let i = 0; i < len; i++) {
|
144 | if (bytes1[i] !== bytes2[i]) return false;
|
145 | }
|
146 | return true;
|
147 | }
|
148 |
|
149 | export function bytesXor(bytes1, bytes2) {
|
150 | const len = bytes1.length;
|
151 | const bytes = [];
|
152 |
|
153 | for (let i = 0; i < len; ++i) {
|
154 | bytes[i] = bytes1[i] ^ bytes2[i];
|
155 | }
|
156 |
|
157 | return bytes;
|
158 | }
|
159 |
|
160 | export function bytesToWords(bytes) {
|
161 | if (bytes instanceof ArrayBuffer) {
|
162 | bytes = new Uint8Array(bytes);
|
163 | }
|
164 | const len = bytes.length;
|
165 | const words = [];
|
166 | let i;
|
167 | for (i = 0; i < len; i++) {
|
168 | words[i >>> 2] |= bytes[i] << 24 - i % 4 * 8;
|
169 | }
|
170 |
|
171 | return new CryptoJS.lib.WordArray.init(words, len);
|
172 | }
|
173 |
|
174 | export function bytesFromWords(wordArray) {
|
175 | const words = wordArray.words;
|
176 | const sigBytes = wordArray.sigBytes;
|
177 | const bytes = [];
|
178 |
|
179 | for (let i = 0; i < sigBytes; i++) {
|
180 | bytes.push(words[i >>> 2] >>> 24 - i % 4 * 8 & 0xff);
|
181 | }
|
182 |
|
183 | return bytes;
|
184 | }
|
185 |
|
186 | export function bytesFromBigInt(bigInt, len) {
|
187 | let bytes = bigInt.toByteArray();
|
188 |
|
189 | if (len && bytes.length < len) {
|
190 | const padding = [];
|
191 | for (let i = 0, needPadding = len - bytes.length; i < needPadding; i++) {
|
192 | padding[i] = 0;
|
193 | }
|
194 | if (bytes instanceof ArrayBuffer) {
|
195 | bytes = bufferConcat(padding, bytes);
|
196 | } else {
|
197 | bytes = padding.concat(bytes);
|
198 | }
|
199 | } else {
|
200 | while (!bytes[0] && (!len || bytes.length > len)) {
|
201 | bytes = bytes.slice(1);
|
202 | }
|
203 | }
|
204 |
|
205 | return bytes;
|
206 | }
|
207 |
|
208 | export function bytesFromLeemonBigInt(bigInt, len) {
|
209 | const str = bigInt2str(bigInt, 16);
|
210 | return bytesFromHex(str);
|
211 | }
|
212 |
|
213 | export function bytesToArrayBuffer(b) {
|
214 | return new Uint8Array(b).buffer;
|
215 | }
|
216 |
|
217 | export function convertToArrayBuffer(bytes) {
|
218 |
|
219 | if (bytes instanceof ArrayBuffer) {
|
220 | return bytes;
|
221 | }
|
222 | if (bytes.buffer !== undefined && bytes.buffer.byteLength == bytes.length * bytes.BYTES_PER_ELEMENT) {
|
223 | return bytes.buffer;
|
224 | }
|
225 | return bytesToArrayBuffer(bytes);
|
226 | }
|
227 |
|
228 | export function convertToUint8Array(bytes) {
|
229 | if (bytes.buffer !== undefined) {
|
230 | return bytes;
|
231 | }
|
232 | return new Uint8Array(bytes);
|
233 | }
|
234 |
|
235 | export function convertToByteArray(bytes) {
|
236 | if (Array.isArray(bytes)) {
|
237 | return bytes;
|
238 | }
|
239 | bytes = convertToUint8Array(bytes);
|
240 | const newBytes = [];
|
241 | for (let i = 0, len = bytes.length; i < len; i++) {
|
242 | newBytes.push(bytes[i]);
|
243 | }
|
244 | return newBytes;
|
245 | }
|
246 |
|
247 | export function bytesFromArrayBuffer(buffer) {
|
248 | const byteView = new Uint8Array(buffer);
|
249 | const bytes = Array.from(byteView);
|
250 | return bytes;
|
251 | }
|
252 |
|
253 | export function bufferConcat(buffer1, buffer2) {
|
254 | const l1 = buffer1.byteLength || buffer1.length;
|
255 | const l2 = buffer2.byteLength || buffer2.length;
|
256 | const tmp = new Uint8Array(l1 + l2);
|
257 | tmp.set(buffer1 instanceof ArrayBuffer ? new Uint8Array(buffer1) : buffer1, 0);
|
258 | tmp.set(buffer2 instanceof ArrayBuffer ? new Uint8Array(buffer2) : buffer2, l1);
|
259 |
|
260 | return tmp.buffer;
|
261 | }
|
262 |
|
263 | export function longToInts(sLong) {
|
264 | const divRem = bigStringInt(sLong).divideAndRemainder(bigint(0x100000000));
|
265 |
|
266 | return [divRem[0].intValue(), divRem[1].intValue()];
|
267 | }
|
268 |
|
269 | export function longToBytes(sLong) {
|
270 | return bytesFromWords({ words: longToInts(sLong), sigBytes: 8 }).reverse();
|
271 | }
|
272 |
|
273 | export function longFromInts(high, low) {
|
274 | return bigint(high).shiftLeft(32).add(bigint(low)).toString(10);
|
275 | }
|
276 |
|
277 | export function intToUint(val) {
|
278 | val = parseInt(val);
|
279 | if (val < 0) {
|
280 | val = val + 4294967296;
|
281 | }
|
282 | return val;
|
283 | }
|
284 |
|
285 | export function uintToInt(val) {
|
286 | if (val > 2147483647) {
|
287 | val = val - 4294967296;
|
288 | }
|
289 | return val;
|
290 | }
|
291 |
|
292 | export function sha1HashSync(bytes) {
|
293 |
|
294 | const hashBytes = rushaInstance.rawDigest(bytes).buffer;
|
295 |
|
296 |
|
297 | return hashBytes;
|
298 | }
|
299 |
|
300 | export function sha1BytesSync(bytes) {
|
301 | return bytesFromArrayBuffer(sha1HashSync(bytes));
|
302 | }
|
303 |
|
304 | export function sha256HashSync(bytes) {
|
305 |
|
306 | const hashWords = CryptoJS.SHA256(bytesToWords(bytes));
|
307 |
|
308 |
|
309 | const hashBytes = bytesFromWords(hashWords);
|
310 |
|
311 | return hashBytes;
|
312 | }
|
313 |
|
314 | export function rsaEncrypt(publicKey, bytes) {
|
315 | bytes = addPadding(bytes, 255);
|
316 |
|
317 |
|
318 | const N = new BigInteger(publicKey.modulus, 16);
|
319 | const E = new BigInteger(publicKey.exponent, 16);
|
320 | const X = new BigInteger(bytes);
|
321 | const encryptedBigInt = X.modPowInt(E, N),
|
322 | encryptedBytes = bytesFromBigInt(encryptedBigInt, 256);
|
323 |
|
324 |
|
325 | return encryptedBytes;
|
326 | }
|
327 |
|
328 | export function addPadding(bytes, blockSize, zeroes) {
|
329 | blockSize = blockSize || 16;
|
330 | const len = bytes.byteLength || bytes.length;
|
331 | const needPadding = blockSize - len % blockSize;
|
332 | if (needPadding > 0 && needPadding < blockSize) {
|
333 | const padding = new Array(needPadding);
|
334 | if (zeroes) {
|
335 | for (let i = 0; i < needPadding; i++) {
|
336 | padding[i] = 0;
|
337 | }
|
338 | } else {
|
339 | new SecureRandom().nextBytes(padding);
|
340 | }
|
341 |
|
342 | if (bytes instanceof ArrayBuffer) {
|
343 | bytes = bufferConcat(bytes, padding);
|
344 | } else {
|
345 | bytes = bytes.concat(padding);
|
346 | }
|
347 | }
|
348 |
|
349 | return bytes;
|
350 | }
|
351 |
|
352 | export function aesEncryptSync(bytes, keyBytes, ivBytes) {
|
353 | const len = bytes.byteLength || bytes.length;
|
354 |
|
355 |
|
356 | bytes = addPadding(bytes);
|
357 |
|
358 | const encryptedWords = CryptoJS.AES.encrypt(bytesToWords(bytes), bytesToWords(keyBytes), {
|
359 | iv: bytesToWords(ivBytes),
|
360 | padding: CryptoJS.pad.NoPadding,
|
361 | mode: CryptoJS.mode.IGE
|
362 | }).ciphertext;
|
363 |
|
364 | const encryptedBytes = bytesFromWords(encryptedWords);
|
365 |
|
366 |
|
367 | return encryptedBytes;
|
368 | }
|
369 |
|
370 | export function aesDecryptSync(encryptedBytes, keyBytes, ivBytes) {
|
371 |
|
372 |
|
373 | const decryptedWords = CryptoJS.AES.decrypt({ ciphertext: bytesToWords(encryptedBytes) }, bytesToWords(keyBytes), {
|
374 | iv: bytesToWords(ivBytes),
|
375 | padding: CryptoJS.pad.NoPadding,
|
376 | mode: CryptoJS.mode.IGE
|
377 | });
|
378 |
|
379 | const bytes = bytesFromWords(decryptedWords);
|
380 |
|
381 |
|
382 | return bytes;
|
383 | }
|
384 |
|
385 | export function gzipUncompress(bytes) {
|
386 |
|
387 | const result = inflate(bytes);
|
388 |
|
389 | return result;
|
390 | }
|
391 |
|
392 | export function nextRandomInt(maxValue) {
|
393 | return Math.floor(Math.random() * maxValue);
|
394 | }
|
395 |
|
396 |
|
397 |
|
398 |
|
399 | export function pqPrimeFactorization(pqBytes) {
|
400 | const what = new BigInteger(pqBytes);
|
401 |
|
402 |
|
403 | let result = false;
|
404 |
|
405 |
|
406 |
|
407 |
|
408 |
|
409 |
|
410 |
|
411 | result = pqPrimeLeemon(str2bigInt(what.toString(16), 16, Math.ceil(64 / bpe) + 1));
|
412 |
|
413 |
|
414 |
|
415 |
|
416 |
|
417 | |
418 |
|
419 |
|
420 |
|
421 |
|
422 |
|
423 |
|
424 |
|
425 |
|
426 |
|
427 |
|
428 |
|
429 |
|
430 |
|
431 |
|
432 |
|
433 |
|
434 |
|
435 |
|
436 |
|
437 |
|
438 |
|
439 |
|
440 | return result;
|
441 |
|
442 | }
|
443 |
|
444 |
|
445 |
|
446 |
|
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 |
|
461 |
|
462 |
|
463 |
|
464 |
|
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 |
|
492 |
|
493 |
|
494 |
|
495 |
|
496 |
|
497 |
|
498 |
|
499 |
|
500 |
|
501 |
|
502 |
|
503 |
|
504 | export function pqPrimeJsbn(what) {
|
505 | let it = 0,
|
506 | g;
|
507 | for (let i = 0; i < 3; i++) {
|
508 | const q = (nextRandomInt(128) & 15) + 17;
|
509 | let x = bigint(nextRandomInt(1000000000) + 1);
|
510 | let y = x.clone();
|
511 | const lim = 1 << i + 18;
|
512 |
|
513 | for (let j = 1; j < lim; j++) {
|
514 | ++it;
|
515 | let a = x.clone();
|
516 | let b = x.clone();
|
517 | let c = bigint(q);
|
518 |
|
519 | while (!b.equals(BigInteger.ZERO)) {
|
520 | if (!b.and(BigInteger.ONE).equals(BigInteger.ZERO)) {
|
521 | c = c.add(a);
|
522 | if (c.compareTo(what) > 0) {
|
523 | c = c.subtract(what);
|
524 | }
|
525 | }
|
526 | a = a.add(a);
|
527 | if (a.compareTo(what) > 0) {
|
528 | a = a.subtract(what);
|
529 | }
|
530 | b = b.shiftRight(1);
|
531 | }
|
532 |
|
533 | x = c.clone();
|
534 | const z = x.compareTo(y) < 0 ? y.subtract(x) : x.subtract(y);
|
535 | g = z.gcd(what);
|
536 | if (!g.equals(BigInteger.ONE)) {
|
537 | break;
|
538 | }
|
539 | if ((j & j - 1) == 0) {
|
540 | y = x.clone();
|
541 | }
|
542 | }
|
543 | if (g.compareTo(BigInteger.ONE) > 0) {
|
544 | break;
|
545 | }
|
546 | }
|
547 |
|
548 | let f = what.divide(g),
|
549 | P,
|
550 | Q;
|
551 |
|
552 | if (g.compareTo(f) > 0) {
|
553 | P = f;
|
554 | Q = g;
|
555 | } else {
|
556 | P = g;
|
557 | Q = f;
|
558 | }
|
559 |
|
560 | return [bytesFromBigInt(P), bytesFromBigInt(Q), it];
|
561 | }
|
562 |
|
563 |
|
564 |
|
565 |
|
566 |
|
567 |
|
568 |
|
569 |
|
570 |
|
571 |
|
572 |
|
573 |
|
574 |
|
575 |
|
576 |
|
577 |
|
578 |
|
579 |
|
580 |
|
581 |
|
582 |
|
583 |
|
584 |
|
585 |
|
586 |
|
587 |
|
588 |
|
589 |
|
590 |
|
591 |
|
592 |
|
593 |
|
594 |
|
595 |
|
596 |
|
597 |
|
598 |
|
599 |
|
600 |
|
601 |
|
602 |
|
603 |
|
604 |
|
605 |
|
606 |
|
607 |
|
608 |
|
609 |
|
610 |
|
611 |
|
612 |
|
613 |
|
614 |
|
615 |
|
616 |
|
617 |
|
618 |
|
619 |
|
620 |
|
621 |
|
622 |
|
623 |
|
624 |
|
625 |
|
626 |
|
627 |
|
628 |
|
629 |
|
630 |
|
631 |
|
632 |
|
633 |
|
634 |
|
635 |
|
636 |
|
637 |
|
638 |
|
639 |
|
640 |
|
641 |
|
642 |
|
643 |
|
644 |
|
645 |
|
646 |
|
647 |
|
648 |
|
649 |
|
650 |
|
651 |
|
652 |
|
653 |
|
654 |
|
655 |
|
656 |
|
657 |
|
658 |
|
659 |
|
660 |
|
661 |
|
662 |
|
663 |
|
664 |
|
665 |
|
666 |
|
667 |
|
668 |
|
669 |
|
670 |
|
671 |
|
672 |
|
673 |
|
674 |
|
675 |
|
676 |
|
677 |
|
678 |
|
679 |
|
680 |
|
681 |
|
682 |
|
683 |
|
684 |
|
685 |
|
686 |
|
687 |
|
688 |
|
689 |
|
690 |
|
691 |
|
692 |
|
693 |
|
694 |
|
695 |
|
696 |
|
697 |
|
698 |
|
699 |
|
700 |
|
701 |
|
702 |
|
703 |
|
704 | export function pqPrimeLeemon(what) {
|
705 | const minBits = 64;
|
706 | const minLen = Math.ceil(minBits / bpe) + 1;
|
707 | let it = 0;
|
708 | let q, lim;
|
709 | const a = new Array(minLen);
|
710 | const b = new Array(minLen);
|
711 | const c = new Array(minLen);
|
712 | const g = new Array(minLen);
|
713 | const z = new Array(minLen);
|
714 | const x = new Array(minLen);
|
715 | const y = new Array(minLen);
|
716 |
|
717 | for (let i = 0; i < 3; i++) {
|
718 | q = (nextRandomInt(128) & 15) + 17;
|
719 | copyInt_(x, nextRandomInt(1000000000) + 1);
|
720 | copy_(y, x);
|
721 | lim = 1 << i + 18;
|
722 |
|
723 | for (let j = 1; j < lim; j++) {
|
724 | ++it;
|
725 | copy_(a, x);
|
726 | copy_(b, x);
|
727 | copyInt_(c, q);
|
728 |
|
729 | while (!isZero(b)) {
|
730 | if (b[0] & 1) {
|
731 | add_(c, a);
|
732 | if (greater(c, what)) {
|
733 | sub_(c, what);
|
734 | }
|
735 | }
|
736 | add_(a, a);
|
737 | if (greater(a, what)) {
|
738 | sub_(a, what);
|
739 | }
|
740 | rightShift_(b, 1);
|
741 | }
|
742 |
|
743 | copy_(x, c);
|
744 | if (greater(x, y)) {
|
745 | copy_(z, x);
|
746 | sub_(z, y);
|
747 | } else {
|
748 | copy_(z, y);
|
749 | sub_(z, x);
|
750 | }
|
751 | eGCD_(z, what, g, a, b);
|
752 | if (!equalsInt(g, 1)) {
|
753 | break;
|
754 | }
|
755 | if ((j & j - 1) === 0) {
|
756 | copy_(y, x);
|
757 | }
|
758 | }
|
759 | if (greater(g, one)) {
|
760 | break;
|
761 | }
|
762 | }
|
763 |
|
764 | divide_(what, g, x, y);
|
765 |
|
766 | const [P, Q] = greater(g, x) ? [x, g] : [g, x];
|
767 |
|
768 |
|
769 |
|
770 | return [bytesFromLeemonBigInt(P), bytesFromLeemonBigInt(Q), it];
|
771 | }
|
772 |
|
773 | export function bytesModPow(x, y, m) {
|
774 | try {
|
775 | const xBigInt = str2bigInt(bytesToHex(x), 16);
|
776 | const yBigInt = str2bigInt(bytesToHex(y), 16);
|
777 | const mBigInt = str2bigInt(bytesToHex(m), 16);
|
778 | const resBigInt = powMod(xBigInt, yBigInt, mBigInt);
|
779 |
|
780 | return bytesFromHex(bigInt2str(resBigInt, 16));
|
781 | } catch (e) {
|
782 | console.error('mod pow error', e);
|
783 | }
|
784 |
|
785 | return bytesFromBigInt(new BigInteger(x).modPow(new BigInteger(y), new BigInteger(m)), 256);
|
786 | }
|
787 |
|
\ | No newline at end of file |