@irfanshadikrishad/cipher 1.5.4 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -16
- package/dist/Cipher.d.ts +70 -0
- package/dist/ciphers/AESGCM.d.ts +11 -0
- package/dist/ciphers/AESGCM.js +40 -0
- package/dist/ciphers/Affine.d.ts +9 -0
- package/dist/ciphers/Affine.js +50 -0
- package/dist/ciphers/Autokey.d.ts +7 -0
- package/dist/ciphers/Autokey.js +55 -0
- package/dist/ciphers/Beaufort.d.ts +8 -0
- package/dist/ciphers/Beaufort.js +35 -0
- package/dist/ciphers/Bifid.d.ts +9 -0
- package/dist/ciphers/Bifid.js +59 -0
- package/dist/ciphers/Blowfish.d.ts +13 -0
- package/dist/ciphers/Blowfish.js +300 -0
- package/dist/ciphers/ChaCha20.d.ts +14 -0
- package/dist/ciphers/ChaCha20.js +97 -0
- package/dist/ciphers/ColumnarTransposition.d.ts +8 -0
- package/dist/ciphers/ColumnarTransposition.js +43 -0
- package/dist/ciphers/RC4.d.ts +8 -0
- package/dist/ciphers/RC4.js +40 -0
- package/dist/ciphers/RSA.d.ts +15 -0
- package/dist/ciphers/RSA.js +50 -0
- package/dist/ciphers/RailFence.d.ts +8 -0
- package/dist/ciphers/RailFence.js +46 -0
- package/dist/index.js +22 -0
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -43,22 +43,31 @@ console.log(caesar.encrypt('hello world')) // Output: "nkrru cuxrj"
|
|
|
43
43
|
|
|
44
44
|
This library provides implementations of various classical and modern ciphers:
|
|
45
45
|
|
|
46
|
-
| Cipher
|
|
47
|
-
|
|
|
48
|
-
| [Caesar Cipher](/docs/en/ciphers/CAESAR.md)
|
|
49
|
-
| [Atbash Cipher](/docs/en/ciphers/ATBASH.md)
|
|
50
|
-
| [
|
|
51
|
-
| [
|
|
52
|
-
| [
|
|
53
|
-
| [
|
|
54
|
-
| [
|
|
55
|
-
| [
|
|
56
|
-
| [
|
|
57
|
-
| [
|
|
58
|
-
| [
|
|
59
|
-
| [
|
|
60
|
-
|
|
61
|
-
|
|
46
|
+
| Cipher | Type | Key required? | Strength | Used In/Notes |
|
|
47
|
+
| ------------------------------------------------------ | ---------------------------------------- | ------------- | --------- | ----------------------------------------------------- |
|
|
48
|
+
| [Caesar Cipher](/docs/en/ciphers/CAESAR.md) | Substitution | No | Low | Ancient Rome, Simple Obsfuscation |
|
|
49
|
+
| [Atbash Cipher](/docs/en/ciphers/ATBASH.md) | Substitution | No | Low | Hebrew Cipher, Basic Encryption |
|
|
50
|
+
| [ROT13](/docs/en/ciphers/ROT13.md) | Substitution (Caesar variant) | No | Very Low | Simple text obfuscation, not secure |
|
|
51
|
+
| [Affine Cipher](/docs/en/ciphers/AFFINE.md) | Substitution | Yes | Low | Generalizes Caesar, teaches modular arithmetic |
|
|
52
|
+
| [Playfair Cipher](/docs/en/ciphers/PLAYFAIR.md) | Diagraph-based | Yes | Medium | Used in WWI & WWII |
|
|
53
|
+
| [Vigenère Cipher](/docs/en/ciphers/VIGENERE.md) | Polyalphabetic | Yes | Medium | Used in Historical Documents |
|
|
54
|
+
| [The Alphabet Cipher](/docs/en/ciphers/ALPHABET.md) | Polyalphabetic | Yes | Medium | Inspired by Vigenere, Cryptography Puzzles |
|
|
55
|
+
| [Beaufort Cipher](/docs/en/ciphers/BEAUFORT.md) | Polyalphabetic (Reciprocal) | Yes | Medium | Vigenere variant where encrypt = decrypt |
|
|
56
|
+
| [Autokey Cipher](/docs/en/ciphers/AUTOKEY.md) | Polyalphabetic | Yes | Medium | Plaintext extends the key, fixes Vigenere weakness |
|
|
57
|
+
| [Rail Fence Cipher](/docs/en/ciphers/RAILFENCE.md) | Transposition | Yes | Low | Zigzag pattern across N rails |
|
|
58
|
+
| [Columnar Transposition](/docs/en/ciphers/COLUMNAR.md) | Transposition | Yes | Medium | Keyword-sorted column reading |
|
|
59
|
+
| [ADFGVX](/docs/en/ciphers/ADFGVX.md) | Polybius Square + Columnar Transposition | Yes | Medium | Used in WWI, Known for 6x6 polybius square |
|
|
60
|
+
| [Nihilist](/docs/en/ciphers/Nihilist.md) | Polybius Square + Addition | Yes | Medium | Used by Russian Nihilists, Polybius + additive cipher |
|
|
61
|
+
| [Bifid Cipher](/docs/en/ciphers/BIFID.md) | Polybius Square + Fractionation | Yes | Medium | Combines coordinates and fractionation |
|
|
62
|
+
| [RC4](/docs/en/ciphers/RC4.md) | Stream Cipher | Yes | Low | Historically widespread, now considered broken |
|
|
63
|
+
| [Salsa20](/docs/en/ciphers/SALSA20.md) | Stream Cipher | Yes | High | Modern Cryptography, Secure Communications |
|
|
64
|
+
| [ChaCha20](/docs/en/ciphers/CHACHA20.md) | Stream Cipher | Yes | High | Successor to Salsa20, used in TLS 1.3 and WireGuard |
|
|
65
|
+
| [Blowfish](/docs/en/ciphers/BLOWFISH.md) | Symmetric Block Cipher | Yes | Medium | Feistel network, variable key length (1–56 bytes) |
|
|
66
|
+
| [DES](/docs/en/ciphers/DES.md) | Symmetric Block Cipher | Yes | Medium | 56-bit key, Used in legacy systems, replaced by AES |
|
|
67
|
+
| [AES](/docs/en/ciphers/AES.md) | Symmetric Block Cipher | Yes | High | Also known as Rijndael (CBC mode) |
|
|
68
|
+
| [AES-GCM](/docs/en/ciphers/AESGCM.md) | Symmetric Block Cipher (AEAD) | Yes | Very High | Authenticated encryption, modern best practice |
|
|
69
|
+
| [ECC](/docs/en/ciphers/ECC.md) | Asymmetric (Public-Key Cryptography) | Yes | Very High | Used in modern systems like Bitcoin, TLS, JWT, etc. |
|
|
70
|
+
| [RSA](/docs/en/ciphers/RSA.md) | Asymmetric (Public-Key Cryptography) | Yes | Very High | Factoring-based, canonical public-key cipher |
|
|
62
71
|
|
|
63
72
|
#### Contribution
|
|
64
73
|
|
package/dist/Cipher.d.ts
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { ADFGVX } from './ciphers/ADFGVX.js';
|
|
2
2
|
import { AES } from './ciphers/AES.js';
|
|
3
|
+
import { AESGCM } from './ciphers/AESGCM.js';
|
|
4
|
+
import { Affine } from './ciphers/Affine.js';
|
|
3
5
|
import { Alphabet } from './ciphers/Alphabet.js';
|
|
4
6
|
import { Atbash } from './ciphers/Atbash.js';
|
|
7
|
+
import { Autokey } from './ciphers/Autokey.js';
|
|
8
|
+
import { Beaufort } from './ciphers/Beaufort.js';
|
|
9
|
+
import { Bifid } from './ciphers/Bifid.js';
|
|
10
|
+
import { Blowfish } from './ciphers/Blowfish.js';
|
|
5
11
|
import { Caesar } from './ciphers/Caesar.js';
|
|
12
|
+
import { ChaCha20 } from './ciphers/ChaCha20.js';
|
|
13
|
+
import { ColumnarTransposition } from './ciphers/ColumnarTransposition.js';
|
|
6
14
|
import { DES } from './ciphers/DES.js';
|
|
7
15
|
import { ECC } from './ciphers/ECC.js';
|
|
8
16
|
import { Nihilist } from './ciphers/Nihilist.js';
|
|
9
17
|
import { Playfair } from './ciphers/Playfair.js';
|
|
18
|
+
import { RailFence } from './ciphers/RailFence.js';
|
|
19
|
+
import { RC4 } from './ciphers/RC4.js';
|
|
10
20
|
import { ROT13 } from './ciphers/ROT13.js';
|
|
21
|
+
import { RSA } from './ciphers/RSA.js';
|
|
11
22
|
import { Salsa20 } from './ciphers/Salsa20.js';
|
|
12
23
|
import { Vigenere } from './ciphers/Vigenere.js';
|
|
13
24
|
export declare abstract class Cipher {
|
|
@@ -73,6 +84,65 @@ export declare abstract class Cipher {
|
|
|
73
84
|
* Nihilist cipher is a manually operated symmetric encryption cipher, originally used by Russian Nihilists in the 1880s to organize terrorism against the tsarist regime.
|
|
74
85
|
*/
|
|
75
86
|
static Nihilist: typeof Nihilist;
|
|
87
|
+
/**
|
|
88
|
+
* Rail Fence cipher is a transposition cipher that writes plaintext in a zigzag pattern across a number of rails, then reads off each rail in order.
|
|
89
|
+
* @param rails Number of rails (must be >= 2)
|
|
90
|
+
*/
|
|
91
|
+
static RailFence: typeof RailFence;
|
|
92
|
+
/**
|
|
93
|
+
* Affine cipher is a substitution cipher where each letter is encrypted using the formula E(x) = (a*x + b) mod 26.
|
|
94
|
+
* @param a Multiplicative key, must be coprime with 26
|
|
95
|
+
* @param b Additive key
|
|
96
|
+
*/
|
|
97
|
+
static Affine: typeof Affine;
|
|
98
|
+
/**
|
|
99
|
+
* Beaufort cipher is a reciprocal polyalphabetic substitution cipher — encrypt and decrypt use the same operation.
|
|
100
|
+
* @param key Keyword string (letters only)
|
|
101
|
+
*/
|
|
102
|
+
static Beaufort: typeof Beaufort;
|
|
103
|
+
/**
|
|
104
|
+
* Autokey cipher is a polyalphabetic cipher where the plaintext extends the key, eliminating the periodic key weakness of Vigenere.
|
|
105
|
+
* @param key Initial keyword string (letters only)
|
|
106
|
+
*/
|
|
107
|
+
static Autokey: typeof Autokey;
|
|
108
|
+
/**
|
|
109
|
+
* Columnar Transposition cipher fills plaintext into a grid row-by-row and reads columns in keyword-sorted order.
|
|
110
|
+
* @param key Keyword string (letters only)
|
|
111
|
+
*/
|
|
112
|
+
static ColumnarTransposition: typeof ColumnarTransposition;
|
|
113
|
+
/**
|
|
114
|
+
* Bifid cipher combines a Polybius square with fractionation to encrypt letters using row and column coordinates.
|
|
115
|
+
* @param key Optional keyword to build the 5x5 Polybius square
|
|
116
|
+
*/
|
|
117
|
+
static Bifid: typeof Bifid;
|
|
118
|
+
/**
|
|
119
|
+
* RC4 (Rivest Cipher 4) is a symmetric stream cipher using key-scheduling and pseudo-random generation arrays.
|
|
120
|
+
* @param key Key string
|
|
121
|
+
*/
|
|
122
|
+
static RC4: typeof RC4;
|
|
123
|
+
/**
|
|
124
|
+
* Blowfish is a symmetric block cipher with a 64-bit block size and variable-length key (1–56 bytes), using a 16-round Feistel network.
|
|
125
|
+
* @param key 1–56 byte key
|
|
126
|
+
*/
|
|
127
|
+
static Blowfish: typeof Blowfish;
|
|
128
|
+
/**
|
|
129
|
+
* ChaCha20 is a modern stream cipher and successor to Salsa20, used in TLS 1.3 and WireGuard.
|
|
130
|
+
* @param key 256-bit key (base64)
|
|
131
|
+
* @param nonce 96-bit nonce (base64)
|
|
132
|
+
* @param counter Initial counter value
|
|
133
|
+
*/
|
|
134
|
+
static ChaCha20: typeof ChaCha20;
|
|
135
|
+
/**
|
|
136
|
+
* AES-GCM is an authenticated encryption (AEAD) mode of AES providing both confidentiality and integrity.
|
|
137
|
+
* @param key 256-bit key (hex)
|
|
138
|
+
* @param nonce 96-bit nonce (hex)
|
|
139
|
+
*/
|
|
140
|
+
static AESGCM: typeof AESGCM;
|
|
141
|
+
/**
|
|
142
|
+
* RSA is an asymmetric public-key cipher based on the difficulty of factoring large integers.
|
|
143
|
+
* Use RSA.generate() to create a key pair.
|
|
144
|
+
*/
|
|
145
|
+
static RSA: typeof RSA;
|
|
76
146
|
abstract encrypt(text: string): string | Promise<string>;
|
|
77
147
|
abstract decrypt(text: string): string | Promise<string>;
|
|
78
148
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
|
+
export declare class AESGCM extends Cipher {
|
|
3
|
+
private keyMaterial;
|
|
4
|
+
private nonce;
|
|
5
|
+
constructor(key: Uint8Array | string, nonce: Uint8Array | string);
|
|
6
|
+
private importKey;
|
|
7
|
+
encrypt(plaintext: string): Promise<string>;
|
|
8
|
+
decrypt(ciphertext: string): Promise<string>;
|
|
9
|
+
static generateKey(): string;
|
|
10
|
+
static generateNonce(): string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { webcrypto } from 'node:crypto';
|
|
3
|
+
import { Cipher } from '../Cipher.js';
|
|
4
|
+
const crypto = webcrypto;
|
|
5
|
+
export class AESGCM extends Cipher {
|
|
6
|
+
constructor(key, nonce) {
|
|
7
|
+
super();
|
|
8
|
+
if (typeof key === 'string')
|
|
9
|
+
key = new Uint8Array(Buffer.from(key, 'hex'));
|
|
10
|
+
if (typeof nonce === 'string')
|
|
11
|
+
nonce = new Uint8Array(Buffer.from(nonce, 'hex'));
|
|
12
|
+
if (key.length !== 32)
|
|
13
|
+
throw new Error('Key must be 32 bytes (256-bit).');
|
|
14
|
+
if (nonce.length !== 12)
|
|
15
|
+
throw new Error('Nonce must be 12 bytes (96-bit).');
|
|
16
|
+
this.keyMaterial = key;
|
|
17
|
+
this.nonce = nonce;
|
|
18
|
+
}
|
|
19
|
+
async importKey() {
|
|
20
|
+
return crypto.subtle.importKey('raw', this.keyMaterial.buffer, { name: 'AES-GCM' }, false, ['encrypt', 'decrypt']);
|
|
21
|
+
}
|
|
22
|
+
async encrypt(plaintext) {
|
|
23
|
+
const key = await this.importKey();
|
|
24
|
+
const encoded = new TextEncoder().encode(plaintext);
|
|
25
|
+
const ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv: this.nonce.buffer }, key, encoded.buffer);
|
|
26
|
+
return Buffer.from(new Uint8Array(ciphertext)).toString('hex');
|
|
27
|
+
}
|
|
28
|
+
async decrypt(ciphertext) {
|
|
29
|
+
const key = await this.importKey();
|
|
30
|
+
const bytes = new Uint8Array(Buffer.from(ciphertext, 'hex'));
|
|
31
|
+
const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: this.nonce.buffer }, key, bytes.buffer);
|
|
32
|
+
return new TextDecoder().decode(decrypted);
|
|
33
|
+
}
|
|
34
|
+
static generateKey() {
|
|
35
|
+
return Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('hex');
|
|
36
|
+
}
|
|
37
|
+
static generateNonce() {
|
|
38
|
+
return Buffer.from(crypto.getRandomValues(new Uint8Array(12))).toString('hex');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
|
+
const VALID_A = new Set([1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25]);
|
|
3
|
+
function modInverse(a, m) {
|
|
4
|
+
for (let x = 1; x < m; x++) {
|
|
5
|
+
if ((a * x) % m === 1)
|
|
6
|
+
return x;
|
|
7
|
+
}
|
|
8
|
+
throw new Error(`No modular inverse for a=${a}`);
|
|
9
|
+
}
|
|
10
|
+
export class Affine extends Cipher {
|
|
11
|
+
constructor(a, b) {
|
|
12
|
+
super();
|
|
13
|
+
if (!VALID_A.has(a)) {
|
|
14
|
+
throw new Error(`'a' must be coprime with 26. Valid values: ${[...VALID_A].join(', ')}`);
|
|
15
|
+
}
|
|
16
|
+
this.a = a;
|
|
17
|
+
this.b = ((b % 26) + 26) % 26;
|
|
18
|
+
this.aInv = modInverse(a, 26);
|
|
19
|
+
}
|
|
20
|
+
encrypt(text) {
|
|
21
|
+
return text
|
|
22
|
+
.split('')
|
|
23
|
+
.map((char) => {
|
|
24
|
+
const code = char.charCodeAt(0);
|
|
25
|
+
if (code >= 65 && code <= 90) {
|
|
26
|
+
return String.fromCharCode(((this.a * (code - 65) + this.b) % 26) + 65);
|
|
27
|
+
}
|
|
28
|
+
else if (code >= 97 && code <= 122) {
|
|
29
|
+
return String.fromCharCode(((this.a * (code - 97) + this.b) % 26) + 97);
|
|
30
|
+
}
|
|
31
|
+
return char;
|
|
32
|
+
})
|
|
33
|
+
.join('');
|
|
34
|
+
}
|
|
35
|
+
decrypt(text) {
|
|
36
|
+
return text
|
|
37
|
+
.split('')
|
|
38
|
+
.map((char) => {
|
|
39
|
+
const code = char.charCodeAt(0);
|
|
40
|
+
if (code >= 65 && code <= 90) {
|
|
41
|
+
return String.fromCharCode(((this.aInv * (code - 65 - this.b + 26)) % 26) + 65);
|
|
42
|
+
}
|
|
43
|
+
else if (code >= 97 && code <= 122) {
|
|
44
|
+
return String.fromCharCode(((this.aInv * (code - 97 - this.b + 26)) % 26) + 97);
|
|
45
|
+
}
|
|
46
|
+
return char;
|
|
47
|
+
})
|
|
48
|
+
.join('');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
|
+
export class Autokey extends Cipher {
|
|
3
|
+
constructor(key) {
|
|
4
|
+
super();
|
|
5
|
+
if (!key || !/^[a-zA-Z]+$/.test(key)) {
|
|
6
|
+
throw new Error('Key must be a non-empty string containing only letters.');
|
|
7
|
+
}
|
|
8
|
+
this.key = key.toUpperCase();
|
|
9
|
+
}
|
|
10
|
+
encrypt(text) {
|
|
11
|
+
const letters = text.split('').filter((c) => /[a-zA-Z]/.test(c));
|
|
12
|
+
const runningKey = (this.key + letters.join('').toUpperCase()).split('');
|
|
13
|
+
let j = 0;
|
|
14
|
+
return text
|
|
15
|
+
.split('')
|
|
16
|
+
.map((char) => {
|
|
17
|
+
const code = char.charCodeAt(0);
|
|
18
|
+
const shift = runningKey[j].charCodeAt(0) - 65;
|
|
19
|
+
if (code >= 65 && code <= 90) {
|
|
20
|
+
j++;
|
|
21
|
+
return String.fromCharCode(((code - 65 + shift) % 26) + 65);
|
|
22
|
+
}
|
|
23
|
+
else if (code >= 97 && code <= 122) {
|
|
24
|
+
j++;
|
|
25
|
+
return String.fromCharCode(((code - 97 + shift) % 26) + 97);
|
|
26
|
+
}
|
|
27
|
+
return char;
|
|
28
|
+
})
|
|
29
|
+
.join('');
|
|
30
|
+
}
|
|
31
|
+
decrypt(text) {
|
|
32
|
+
const runningKey = this.key.split('');
|
|
33
|
+
let j = 0;
|
|
34
|
+
return text
|
|
35
|
+
.split('')
|
|
36
|
+
.map((char) => {
|
|
37
|
+
const code = char.charCodeAt(0);
|
|
38
|
+
const shift = runningKey[j].charCodeAt(0) - 65;
|
|
39
|
+
if (code >= 65 && code <= 90) {
|
|
40
|
+
const plain = ((code - 65 - shift + 26) % 26) + 65;
|
|
41
|
+
runningKey.push(String.fromCharCode(plain));
|
|
42
|
+
j++;
|
|
43
|
+
return String.fromCharCode(plain);
|
|
44
|
+
}
|
|
45
|
+
else if (code >= 97 && code <= 122) {
|
|
46
|
+
const plain = ((code - 97 - shift + 26) % 26) + 97;
|
|
47
|
+
runningKey.push(String.fromCharCode(plain - 32));
|
|
48
|
+
j++;
|
|
49
|
+
return String.fromCharCode(plain);
|
|
50
|
+
}
|
|
51
|
+
return char;
|
|
52
|
+
})
|
|
53
|
+
.join('');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
|
+
export class Beaufort extends Cipher {
|
|
3
|
+
constructor(key) {
|
|
4
|
+
super();
|
|
5
|
+
if (!key || !/^[a-zA-Z]+$/.test(key)) {
|
|
6
|
+
throw new Error('Key must be a non-empty string containing only letters.');
|
|
7
|
+
}
|
|
8
|
+
this.key = key.toUpperCase();
|
|
9
|
+
}
|
|
10
|
+
process(text) {
|
|
11
|
+
let j = 0;
|
|
12
|
+
return text
|
|
13
|
+
.split('')
|
|
14
|
+
.map((char) => {
|
|
15
|
+
const code = char.charCodeAt(0);
|
|
16
|
+
const keyCode = this.key[j % this.key.length].charCodeAt(0) - 65;
|
|
17
|
+
if (code >= 65 && code <= 90) {
|
|
18
|
+
j++;
|
|
19
|
+
return String.fromCharCode(((keyCode - (code - 65) + 26) % 26) + 65);
|
|
20
|
+
}
|
|
21
|
+
else if (code >= 97 && code <= 122) {
|
|
22
|
+
j++;
|
|
23
|
+
return String.fromCharCode(((keyCode - (code - 97) + 26) % 26) + 97);
|
|
24
|
+
}
|
|
25
|
+
return char;
|
|
26
|
+
})
|
|
27
|
+
.join('');
|
|
28
|
+
}
|
|
29
|
+
encrypt(text) {
|
|
30
|
+
return this.process(text);
|
|
31
|
+
}
|
|
32
|
+
decrypt(text) {
|
|
33
|
+
return this.process(text);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
|
+
export class Bifid extends Cipher {
|
|
3
|
+
constructor(key = '') {
|
|
4
|
+
super();
|
|
5
|
+
const seen = new Set();
|
|
6
|
+
const alphabet = [];
|
|
7
|
+
for (const c of key.toUpperCase() + 'ABCDEFGHIKLMNOPQRSTUVWXYZ') {
|
|
8
|
+
const ch = c === 'J' ? 'I' : c;
|
|
9
|
+
if (/[A-Z]/.test(ch) && !seen.has(ch)) {
|
|
10
|
+
seen.add(ch);
|
|
11
|
+
alphabet.push(ch);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
this.square = [];
|
|
15
|
+
this.charPos = new Map();
|
|
16
|
+
for (let r = 0; r < 5; r++) {
|
|
17
|
+
this.square.push(alphabet.slice(r * 5, r * 5 + 5));
|
|
18
|
+
for (let c = 0; c < 5; c++) {
|
|
19
|
+
this.charPos.set(alphabet[r * 5 + c], [r, c]);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
toLetters(text) {
|
|
24
|
+
return text
|
|
25
|
+
.toUpperCase()
|
|
26
|
+
.split('')
|
|
27
|
+
.filter((c) => /[A-Z]/.test(c))
|
|
28
|
+
.map((c) => (c === 'J' ? 'I' : c));
|
|
29
|
+
}
|
|
30
|
+
encrypt(text) {
|
|
31
|
+
const letters = this.toLetters(text);
|
|
32
|
+
const rows = [];
|
|
33
|
+
const cols = [];
|
|
34
|
+
for (const ch of letters) {
|
|
35
|
+
const [r, c] = this.charPos.get(ch);
|
|
36
|
+
rows.push(r);
|
|
37
|
+
cols.push(c);
|
|
38
|
+
}
|
|
39
|
+
// seq = [rows..., cols...], then read pairs
|
|
40
|
+
const seq = [...rows, ...cols];
|
|
41
|
+
const result = [];
|
|
42
|
+
for (let i = 0; i < seq.length; i += 2) {
|
|
43
|
+
result.push(this.square[seq[i]][seq[i + 1]]);
|
|
44
|
+
}
|
|
45
|
+
return result.join('');
|
|
46
|
+
}
|
|
47
|
+
decrypt(text) {
|
|
48
|
+
const letters = this.toLetters(text);
|
|
49
|
+
const n = letters.length;
|
|
50
|
+
const coords = [];
|
|
51
|
+
for (const ch of letters) {
|
|
52
|
+
const [r, c] = this.charPos.get(ch);
|
|
53
|
+
coords.push(r, c);
|
|
54
|
+
}
|
|
55
|
+
const rows = coords.slice(0, n);
|
|
56
|
+
const cols = coords.slice(n);
|
|
57
|
+
return letters.map((_, i) => this.square[rows[i]][cols[i]]).join('');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
|
+
export declare class Blowfish extends Cipher {
|
|
3
|
+
private P;
|
|
4
|
+
private S;
|
|
5
|
+
constructor(key: Uint8Array | string);
|
|
6
|
+
private F;
|
|
7
|
+
private encryptBlock;
|
|
8
|
+
private decryptBlock;
|
|
9
|
+
private expandKey;
|
|
10
|
+
private processBytes;
|
|
11
|
+
encrypt(plaintext: string): string;
|
|
12
|
+
decrypt(ciphertext: string): string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { Cipher } from '../Cipher.js';
|
|
3
|
+
// Blowfish subkey and S-box constants (hexadecimal digits of Pi)
|
|
4
|
+
const P_INIT = [
|
|
5
|
+
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
|
|
6
|
+
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
|
7
|
+
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
|
|
8
|
+
];
|
|
9
|
+
const S_INIT = [
|
|
10
|
+
[
|
|
11
|
+
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
|
|
12
|
+
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
|
13
|
+
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
|
|
14
|
+
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
|
15
|
+
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
|
|
16
|
+
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
|
17
|
+
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
|
|
18
|
+
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
|
19
|
+
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
|
|
20
|
+
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
|
21
|
+
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
|
|
22
|
+
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
|
23
|
+
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
|
|
24
|
+
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
|
25
|
+
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
|
|
26
|
+
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
|
27
|
+
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
|
|
28
|
+
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
|
29
|
+
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
|
|
30
|
+
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
|
31
|
+
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
|
|
32
|
+
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
|
33
|
+
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
|
|
34
|
+
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
|
35
|
+
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
|
|
36
|
+
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
|
37
|
+
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
|
|
38
|
+
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
|
39
|
+
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
|
|
40
|
+
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
|
41
|
+
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
|
|
42
|
+
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
|
43
|
+
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
|
|
44
|
+
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
|
45
|
+
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
|
|
46
|
+
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
|
47
|
+
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
|
|
48
|
+
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
|
49
|
+
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
|
|
50
|
+
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
|
51
|
+
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
|
|
52
|
+
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
|
53
|
+
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
|
|
54
|
+
],
|
|
55
|
+
[
|
|
56
|
+
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
|
|
57
|
+
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
|
58
|
+
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
|
|
59
|
+
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
|
60
|
+
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
|
|
61
|
+
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
|
62
|
+
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
|
|
63
|
+
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
|
64
|
+
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
|
|
65
|
+
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
|
66
|
+
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
|
|
67
|
+
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
|
68
|
+
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
|
|
69
|
+
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
|
70
|
+
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
|
|
71
|
+
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
|
72
|
+
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
|
|
73
|
+
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
|
74
|
+
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
|
|
75
|
+
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
|
76
|
+
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
|
|
77
|
+
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
|
78
|
+
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
|
|
79
|
+
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
|
80
|
+
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
|
|
81
|
+
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
|
82
|
+
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
|
|
83
|
+
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
|
84
|
+
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
|
|
85
|
+
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
|
86
|
+
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
|
|
87
|
+
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
|
88
|
+
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
|
|
89
|
+
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
|
90
|
+
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
|
|
91
|
+
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
|
92
|
+
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
|
|
93
|
+
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
|
94
|
+
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
|
|
95
|
+
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
|
96
|
+
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
|
|
97
|
+
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
|
98
|
+
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
|
|
99
|
+
],
|
|
100
|
+
[
|
|
101
|
+
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
|
|
102
|
+
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
|
103
|
+
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
|
|
104
|
+
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
|
105
|
+
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
|
|
106
|
+
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
|
107
|
+
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
|
|
108
|
+
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
|
109
|
+
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
|
|
110
|
+
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
|
111
|
+
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
|
|
112
|
+
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
|
113
|
+
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
|
|
114
|
+
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
|
115
|
+
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
|
|
116
|
+
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
|
117
|
+
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
|
|
118
|
+
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
|
119
|
+
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
|
|
120
|
+
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
|
121
|
+
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
|
|
122
|
+
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
|
123
|
+
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
|
|
124
|
+
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
|
125
|
+
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
|
|
126
|
+
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
|
127
|
+
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
|
|
128
|
+
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
|
129
|
+
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
|
|
130
|
+
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
|
131
|
+
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
|
|
132
|
+
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
|
133
|
+
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
|
|
134
|
+
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
|
135
|
+
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
|
|
136
|
+
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
|
137
|
+
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
|
|
138
|
+
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
|
139
|
+
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
|
|
140
|
+
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
|
141
|
+
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
|
|
142
|
+
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
|
143
|
+
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
|
|
144
|
+
],
|
|
145
|
+
[
|
|
146
|
+
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
|
|
147
|
+
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
|
148
|
+
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
|
|
149
|
+
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
|
150
|
+
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
|
|
151
|
+
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
|
152
|
+
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
|
|
153
|
+
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
|
154
|
+
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
|
|
155
|
+
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
|
156
|
+
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
|
|
157
|
+
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
|
158
|
+
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
|
|
159
|
+
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
|
160
|
+
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
|
|
161
|
+
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
|
162
|
+
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
|
|
163
|
+
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
|
164
|
+
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
|
|
165
|
+
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
|
166
|
+
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
|
|
167
|
+
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
|
168
|
+
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
|
|
169
|
+
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
|
170
|
+
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
|
|
171
|
+
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
|
172
|
+
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
|
|
173
|
+
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
|
174
|
+
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
|
|
175
|
+
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
|
176
|
+
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
|
|
177
|
+
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
|
178
|
+
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
|
|
179
|
+
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
|
180
|
+
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
|
|
181
|
+
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
|
182
|
+
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
|
|
183
|
+
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
|
184
|
+
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
|
|
185
|
+
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
|
186
|
+
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
|
|
187
|
+
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
|
188
|
+
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
|
|
189
|
+
],
|
|
190
|
+
];
|
|
191
|
+
function toUint32(n) {
|
|
192
|
+
return n >>> 0;
|
|
193
|
+
}
|
|
194
|
+
export class Blowfish extends Cipher {
|
|
195
|
+
constructor(key) {
|
|
196
|
+
super();
|
|
197
|
+
if (typeof key === 'string')
|
|
198
|
+
key = new TextEncoder().encode(key);
|
|
199
|
+
if (key.length < 1 || key.length > 56) {
|
|
200
|
+
throw new Error('Blowfish key must be 1–56 bytes.');
|
|
201
|
+
}
|
|
202
|
+
this.P = [...P_INIT];
|
|
203
|
+
this.S = S_INIT.map((s) => [...s]);
|
|
204
|
+
this.expandKey(key);
|
|
205
|
+
}
|
|
206
|
+
F(x) {
|
|
207
|
+
const a = (x >>> 24) & 0xff;
|
|
208
|
+
const b = (x >>> 16) & 0xff;
|
|
209
|
+
const c = (x >>> 8) & 0xff;
|
|
210
|
+
const d = x & 0xff;
|
|
211
|
+
return toUint32(toUint32(toUint32(this.S[0][a] + this.S[1][b]) ^ this.S[2][c]) +
|
|
212
|
+
this.S[3][d]);
|
|
213
|
+
}
|
|
214
|
+
encryptBlock(xL, xR) {
|
|
215
|
+
for (let i = 0; i < 16; i++) {
|
|
216
|
+
xL = toUint32(xL ^ this.P[i]);
|
|
217
|
+
xR = toUint32(this.F(xL) ^ xR);
|
|
218
|
+
[xL, xR] = [xR, xL];
|
|
219
|
+
}
|
|
220
|
+
;
|
|
221
|
+
[xL, xR] = [xR, xL];
|
|
222
|
+
xR = toUint32(xR ^ this.P[16]);
|
|
223
|
+
xL = toUint32(xL ^ this.P[17]);
|
|
224
|
+
return [xL, xR];
|
|
225
|
+
}
|
|
226
|
+
decryptBlock(xL, xR) {
|
|
227
|
+
for (let i = 17; i > 1; i--) {
|
|
228
|
+
xL = toUint32(xL ^ this.P[i]);
|
|
229
|
+
xR = toUint32(this.F(xL) ^ xR);
|
|
230
|
+
[xL, xR] = [xR, xL];
|
|
231
|
+
}
|
|
232
|
+
;
|
|
233
|
+
[xL, xR] = [xR, xL];
|
|
234
|
+
xR = toUint32(xR ^ this.P[1]);
|
|
235
|
+
xL = toUint32(xL ^ this.P[0]);
|
|
236
|
+
return [xL, xR];
|
|
237
|
+
}
|
|
238
|
+
expandKey(key) {
|
|
239
|
+
let keyPos = 0;
|
|
240
|
+
for (let i = 0; i < 18; i++) {
|
|
241
|
+
let data = 0;
|
|
242
|
+
for (let k = 0; k < 4; k++) {
|
|
243
|
+
data = toUint32((data << 8) | key[keyPos % key.length]);
|
|
244
|
+
keyPos++;
|
|
245
|
+
}
|
|
246
|
+
this.P[i] = toUint32(this.P[i] ^ data);
|
|
247
|
+
}
|
|
248
|
+
let l = 0;
|
|
249
|
+
let r = 0;
|
|
250
|
+
for (let i = 0; i < 18; i += 2) {
|
|
251
|
+
;
|
|
252
|
+
[l, r] = this.encryptBlock(l, r);
|
|
253
|
+
this.P[i] = l;
|
|
254
|
+
this.P[i + 1] = r;
|
|
255
|
+
}
|
|
256
|
+
for (let s = 0; s < 4; s++) {
|
|
257
|
+
for (let i = 0; i < 256; i += 2) {
|
|
258
|
+
;
|
|
259
|
+
[l, r] = this.encryptBlock(l, r);
|
|
260
|
+
this.S[s][i] = l;
|
|
261
|
+
this.S[s][i + 1] = r;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
processBytes(input, mode) {
|
|
266
|
+
const padded = input.length % 8 === 0
|
|
267
|
+
? input
|
|
268
|
+
: (() => {
|
|
269
|
+
const p = new Uint8Array(Math.ceil(input.length / 8) * 8);
|
|
270
|
+
p.set(input);
|
|
271
|
+
return p;
|
|
272
|
+
})();
|
|
273
|
+
const out = new Uint8Array(padded.length);
|
|
274
|
+
const view = new DataView(padded.buffer);
|
|
275
|
+
const outView = new DataView(out.buffer);
|
|
276
|
+
for (let i = 0; i < padded.length; i += 8) {
|
|
277
|
+
const l = view.getUint32(i, false);
|
|
278
|
+
const r = view.getUint32(i + 4, false);
|
|
279
|
+
const [nl, nr] = mode === 'enc' ? this.encryptBlock(l, r) : this.decryptBlock(l, r);
|
|
280
|
+
outView.setUint32(i, nl, false);
|
|
281
|
+
outView.setUint32(i + 4, nr, false);
|
|
282
|
+
}
|
|
283
|
+
return out;
|
|
284
|
+
}
|
|
285
|
+
encrypt(plaintext) {
|
|
286
|
+
const bytes = new TextEncoder().encode(plaintext);
|
|
287
|
+
const lenBuf = new Uint8Array(4);
|
|
288
|
+
new DataView(lenBuf.buffer).setUint32(0, bytes.length, false);
|
|
289
|
+
const combined = new Uint8Array(4 + bytes.length);
|
|
290
|
+
combined.set(lenBuf);
|
|
291
|
+
combined.set(bytes, 4);
|
|
292
|
+
return Buffer.from(this.processBytes(combined, 'enc')).toString('hex');
|
|
293
|
+
}
|
|
294
|
+
decrypt(ciphertext) {
|
|
295
|
+
const bytes = new Uint8Array(Buffer.from(ciphertext, 'hex'));
|
|
296
|
+
const dec = this.processBytes(bytes, 'dec');
|
|
297
|
+
const len = new DataView(dec.buffer).getUint32(0, false);
|
|
298
|
+
return new TextDecoder().decode(dec.slice(4, 4 + len));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
|
+
export declare class ChaCha20 extends Cipher {
|
|
3
|
+
private key;
|
|
4
|
+
private nonce;
|
|
5
|
+
private counter;
|
|
6
|
+
constructor(key: Uint8Array | string, nonce: Uint8Array | string, counter?: number);
|
|
7
|
+
private static rotl;
|
|
8
|
+
private static quarterRound;
|
|
9
|
+
private block;
|
|
10
|
+
encrypt(plaintext: string): string;
|
|
11
|
+
decrypt(ciphertext: string): string;
|
|
12
|
+
static generateKey(): string;
|
|
13
|
+
static generateNonce(): string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { Cipher } from '../Cipher.js';
|
|
4
|
+
export class ChaCha20 extends Cipher {
|
|
5
|
+
constructor(key, nonce, counter = 0) {
|
|
6
|
+
super();
|
|
7
|
+
if (typeof key === 'string')
|
|
8
|
+
key = Buffer.from(key, 'base64');
|
|
9
|
+
if (typeof nonce === 'string')
|
|
10
|
+
nonce = Buffer.from(nonce, 'base64');
|
|
11
|
+
if (key.length !== 32)
|
|
12
|
+
throw new Error('Key must be 32 bytes (256-bit).');
|
|
13
|
+
if (nonce.length !== 12)
|
|
14
|
+
throw new Error('Nonce must be 12 bytes (96-bit).');
|
|
15
|
+
this.key = new Uint32Array(new Uint8Array(key).buffer);
|
|
16
|
+
this.nonce = new Uint32Array(new Uint8Array(nonce).buffer);
|
|
17
|
+
this.counter = counter;
|
|
18
|
+
}
|
|
19
|
+
static rotl(x, n) {
|
|
20
|
+
return ((x << n) | (x >>> (32 - n))) >>> 0;
|
|
21
|
+
}
|
|
22
|
+
static quarterRound(s, a, b, c, d) {
|
|
23
|
+
s[a] = (s[a] + s[b]) >>> 0;
|
|
24
|
+
s[d] = ChaCha20.rotl(s[d] ^ s[a], 16);
|
|
25
|
+
s[c] = (s[c] + s[d]) >>> 0;
|
|
26
|
+
s[b] = ChaCha20.rotl(s[b] ^ s[c], 12);
|
|
27
|
+
s[a] = (s[a] + s[b]) >>> 0;
|
|
28
|
+
s[d] = ChaCha20.rotl(s[d] ^ s[a], 8);
|
|
29
|
+
s[c] = (s[c] + s[d]) >>> 0;
|
|
30
|
+
s[b] = ChaCha20.rotl(s[b] ^ s[c], 7);
|
|
31
|
+
}
|
|
32
|
+
block() {
|
|
33
|
+
// State: constants(0-3), key(4-11), counter(12), nonce(13-15)
|
|
34
|
+
const state = new Uint32Array([
|
|
35
|
+
0x61707865,
|
|
36
|
+
0x3320646e,
|
|
37
|
+
0x79622d32,
|
|
38
|
+
0x6b206574,
|
|
39
|
+
this.key[0],
|
|
40
|
+
this.key[1],
|
|
41
|
+
this.key[2],
|
|
42
|
+
this.key[3],
|
|
43
|
+
this.key[4],
|
|
44
|
+
this.key[5],
|
|
45
|
+
this.key[6],
|
|
46
|
+
this.key[7],
|
|
47
|
+
this.counter >>> 0,
|
|
48
|
+
this.nonce[0],
|
|
49
|
+
this.nonce[1],
|
|
50
|
+
this.nonce[2],
|
|
51
|
+
]);
|
|
52
|
+
const working = new Uint32Array(state);
|
|
53
|
+
for (let i = 0; i < 10; i++) {
|
|
54
|
+
ChaCha20.quarterRound(working, 0, 4, 8, 12);
|
|
55
|
+
ChaCha20.quarterRound(working, 1, 5, 9, 13);
|
|
56
|
+
ChaCha20.quarterRound(working, 2, 6, 10, 14);
|
|
57
|
+
ChaCha20.quarterRound(working, 3, 7, 11, 15);
|
|
58
|
+
ChaCha20.quarterRound(working, 0, 5, 10, 15);
|
|
59
|
+
ChaCha20.quarterRound(working, 1, 6, 11, 12);
|
|
60
|
+
ChaCha20.quarterRound(working, 2, 7, 8, 13);
|
|
61
|
+
ChaCha20.quarterRound(working, 3, 4, 9, 14);
|
|
62
|
+
}
|
|
63
|
+
for (let i = 0; i < 16; i++)
|
|
64
|
+
working[i] = (working[i] + state[i]) >>> 0;
|
|
65
|
+
this.counter++;
|
|
66
|
+
return new Uint8Array(working.buffer);
|
|
67
|
+
}
|
|
68
|
+
encrypt(plaintext) {
|
|
69
|
+
const input = new TextEncoder().encode(plaintext);
|
|
70
|
+
const out = new Uint8Array(input.length);
|
|
71
|
+
for (let i = 0; i < input.length; i += 64) {
|
|
72
|
+
const ks = this.block();
|
|
73
|
+
const len = Math.min(64, input.length - i);
|
|
74
|
+
for (let j = 0; j < len; j++)
|
|
75
|
+
out[i + j] = input[i + j] ^ ks[j];
|
|
76
|
+
}
|
|
77
|
+
return Buffer.from(out).toString('base64');
|
|
78
|
+
}
|
|
79
|
+
decrypt(ciphertext) {
|
|
80
|
+
this.counter = 0;
|
|
81
|
+
const input = new Uint8Array(Buffer.from(ciphertext, 'base64'));
|
|
82
|
+
const out = new Uint8Array(input.length);
|
|
83
|
+
for (let i = 0; i < input.length; i += 64) {
|
|
84
|
+
const ks = this.block();
|
|
85
|
+
const len = Math.min(64, input.length - i);
|
|
86
|
+
for (let j = 0; j < len; j++)
|
|
87
|
+
out[i + j] = input[i + j] ^ ks[j];
|
|
88
|
+
}
|
|
89
|
+
return new TextDecoder().decode(out);
|
|
90
|
+
}
|
|
91
|
+
static generateKey() {
|
|
92
|
+
return Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('base64');
|
|
93
|
+
}
|
|
94
|
+
static generateNonce() {
|
|
95
|
+
return Buffer.from(crypto.getRandomValues(new Uint8Array(12))).toString('base64');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
|
+
export class ColumnarTransposition extends Cipher {
|
|
3
|
+
constructor(key) {
|
|
4
|
+
super();
|
|
5
|
+
if (!key || !/^[a-zA-Z]+$/.test(key)) {
|
|
6
|
+
throw new Error('Key must be a non-empty string containing only letters.');
|
|
7
|
+
}
|
|
8
|
+
this.key = key.toUpperCase();
|
|
9
|
+
}
|
|
10
|
+
sortedOrder() {
|
|
11
|
+
return [...this.key]
|
|
12
|
+
.map((char, i) => ({ char, i }))
|
|
13
|
+
.sort((a, b) => a.char.localeCompare(b.char) || a.i - b.i)
|
|
14
|
+
.map((x) => x.i);
|
|
15
|
+
}
|
|
16
|
+
encrypt(text) {
|
|
17
|
+
const numCols = this.key.length;
|
|
18
|
+
const numRows = Math.ceil(text.length / numCols);
|
|
19
|
+
const grid = Array.from({ length: numRows }, () => Array(numCols).fill(''));
|
|
20
|
+
for (let i = 0; i < text.length; i++) {
|
|
21
|
+
grid[Math.floor(i / numCols)][i % numCols] = text[i];
|
|
22
|
+
}
|
|
23
|
+
return this.sortedOrder()
|
|
24
|
+
.map((col) => grid.map((row) => row[col]).join(''))
|
|
25
|
+
.join('');
|
|
26
|
+
}
|
|
27
|
+
decrypt(text) {
|
|
28
|
+
const numCols = this.key.length;
|
|
29
|
+
const numRows = Math.ceil(text.length / numCols);
|
|
30
|
+
const extra = text.length % numCols;
|
|
31
|
+
const order = this.sortedOrder();
|
|
32
|
+
const colLengths = order.map((col) => extra === 0 ? numRows : col < extra ? numRows : numRows - 1);
|
|
33
|
+
const grid = Array.from({ length: numRows }, () => Array(numCols).fill(''));
|
|
34
|
+
let pos = 0;
|
|
35
|
+
for (let k = 0; k < order.length; k++) {
|
|
36
|
+
const col = order[k];
|
|
37
|
+
for (let row = 0; row < colLengths[k]; row++) {
|
|
38
|
+
grid[row][col] = text[pos++];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return grid.map((row) => row.join('')).join('');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { Cipher } from '../Cipher.js';
|
|
3
|
+
export class RC4 extends Cipher {
|
|
4
|
+
constructor(key) {
|
|
5
|
+
super();
|
|
6
|
+
if (!key)
|
|
7
|
+
throw new Error('Key must be a non-empty string.');
|
|
8
|
+
this.key = new TextEncoder().encode(key);
|
|
9
|
+
}
|
|
10
|
+
keystream(length) {
|
|
11
|
+
const S = Uint8Array.from({ length: 256 }, (_, i) => i);
|
|
12
|
+
let j = 0;
|
|
13
|
+
for (let i = 0; i < 256; i++) {
|
|
14
|
+
j = (j + S[i] + this.key[i % this.key.length]) & 0xff;
|
|
15
|
+
[S[i], S[j]] = [S[j], S[i]];
|
|
16
|
+
}
|
|
17
|
+
const stream = new Uint8Array(length);
|
|
18
|
+
let i = 0;
|
|
19
|
+
j = 0;
|
|
20
|
+
for (let k = 0; k < length; k++) {
|
|
21
|
+
i = (i + 1) & 0xff;
|
|
22
|
+
j = (j + S[i]) & 0xff;
|
|
23
|
+
[S[i], S[j]] = [S[j], S[i]];
|
|
24
|
+
stream[k] = S[(S[i] + S[j]) & 0xff];
|
|
25
|
+
}
|
|
26
|
+
return stream;
|
|
27
|
+
}
|
|
28
|
+
encrypt(plaintext) {
|
|
29
|
+
const bytes = new TextEncoder().encode(plaintext);
|
|
30
|
+
const ks = this.keystream(bytes.length);
|
|
31
|
+
const out = bytes.map((b, i) => b ^ ks[i]);
|
|
32
|
+
return Buffer.from(out).toString('hex');
|
|
33
|
+
}
|
|
34
|
+
decrypt(ciphertext) {
|
|
35
|
+
const bytes = new Uint8Array(Buffer.from(ciphertext, 'hex'));
|
|
36
|
+
const ks = this.keystream(bytes.length);
|
|
37
|
+
const out = bytes.map((b, i) => b ^ ks[i]);
|
|
38
|
+
return new TextDecoder().decode(out);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { webcrypto } from 'node:crypto';
|
|
2
|
+
import { Cipher } from '../Cipher.js';
|
|
3
|
+
type NodeCryptoKey = webcrypto.CryptoKey;
|
|
4
|
+
export declare class RSA extends Cipher {
|
|
5
|
+
private publicKey?;
|
|
6
|
+
private privateKey?;
|
|
7
|
+
constructor(publicKey?: NodeCryptoKey, privateKey?: NodeCryptoKey);
|
|
8
|
+
static generate(modulusLength?: 2048 | 4096): Promise<RSA>;
|
|
9
|
+
encrypt(plaintext: string): Promise<string>;
|
|
10
|
+
decrypt(ciphertext: string): Promise<string>;
|
|
11
|
+
exportPublicKey(): Promise<string>;
|
|
12
|
+
exportPrivateKey(): Promise<string>;
|
|
13
|
+
static importPublicKey(hex: string): Promise<RSA>;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { webcrypto } from 'node:crypto';
|
|
3
|
+
import { Cipher } from '../Cipher.js';
|
|
4
|
+
const crypto = webcrypto;
|
|
5
|
+
export class RSA extends Cipher {
|
|
6
|
+
constructor(publicKey, privateKey) {
|
|
7
|
+
super();
|
|
8
|
+
this.publicKey = publicKey;
|
|
9
|
+
this.privateKey = privateKey;
|
|
10
|
+
}
|
|
11
|
+
static async generate(modulusLength = 2048) {
|
|
12
|
+
const { publicKey, privateKey } = await crypto.subtle.generateKey({
|
|
13
|
+
name: 'RSA-OAEP',
|
|
14
|
+
modulusLength,
|
|
15
|
+
publicExponent: new Uint8Array([1, 0, 1]),
|
|
16
|
+
hash: 'SHA-256',
|
|
17
|
+
}, true, ['encrypt', 'decrypt']);
|
|
18
|
+
return new RSA(publicKey, privateKey);
|
|
19
|
+
}
|
|
20
|
+
async encrypt(plaintext) {
|
|
21
|
+
if (!this.publicKey)
|
|
22
|
+
throw new Error('Public key not set.');
|
|
23
|
+
const encoded = new TextEncoder().encode(plaintext);
|
|
24
|
+
const ciphertext = await crypto.subtle.encrypt({ name: 'RSA-OAEP' }, this.publicKey, encoded.buffer);
|
|
25
|
+
return Buffer.from(new Uint8Array(ciphertext)).toString('hex');
|
|
26
|
+
}
|
|
27
|
+
async decrypt(ciphertext) {
|
|
28
|
+
if (!this.privateKey)
|
|
29
|
+
throw new Error('Private key not set.');
|
|
30
|
+
const bytes = new Uint8Array(Buffer.from(ciphertext, 'hex'));
|
|
31
|
+
const decrypted = await crypto.subtle.decrypt({ name: 'RSA-OAEP' }, this.privateKey, bytes.buffer);
|
|
32
|
+
return new TextDecoder().decode(decrypted);
|
|
33
|
+
}
|
|
34
|
+
async exportPublicKey() {
|
|
35
|
+
if (!this.publicKey)
|
|
36
|
+
throw new Error('No public key available.');
|
|
37
|
+
const spki = await crypto.subtle.exportKey('spki', this.publicKey);
|
|
38
|
+
return Buffer.from(new Uint8Array(spki)).toString('hex');
|
|
39
|
+
}
|
|
40
|
+
async exportPrivateKey() {
|
|
41
|
+
if (!this.privateKey)
|
|
42
|
+
throw new Error('No private key available.');
|
|
43
|
+
const pkcs8 = await crypto.subtle.exportKey('pkcs8', this.privateKey);
|
|
44
|
+
return Buffer.from(new Uint8Array(pkcs8)).toString('hex');
|
|
45
|
+
}
|
|
46
|
+
static async importPublicKey(hex) {
|
|
47
|
+
const key = await crypto.subtle.importKey('spki', new Uint8Array(Buffer.from(hex, 'hex')).buffer, { name: 'RSA-OAEP', hash: 'SHA-256' }, true, ['encrypt']);
|
|
48
|
+
return new RSA(key, undefined);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
|
+
export class RailFence extends Cipher {
|
|
3
|
+
constructor(rails) {
|
|
4
|
+
super();
|
|
5
|
+
if (!Number.isInteger(rails) || rails < 2) {
|
|
6
|
+
throw new Error('Rails must be an integer >= 2.');
|
|
7
|
+
}
|
|
8
|
+
this.rails = rails;
|
|
9
|
+
}
|
|
10
|
+
zigzagIndices(length) {
|
|
11
|
+
const indices = [];
|
|
12
|
+
let rail = 0;
|
|
13
|
+
let direction = 1;
|
|
14
|
+
for (let i = 0; i < length; i++) {
|
|
15
|
+
indices.push(rail);
|
|
16
|
+
if (rail === this.rails - 1)
|
|
17
|
+
direction = -1;
|
|
18
|
+
else if (rail === 0)
|
|
19
|
+
direction = 1;
|
|
20
|
+
rail += direction;
|
|
21
|
+
}
|
|
22
|
+
return indices;
|
|
23
|
+
}
|
|
24
|
+
encrypt(text) {
|
|
25
|
+
const rails = Array.from({ length: this.rails }, () => '');
|
|
26
|
+
const indices = this.zigzagIndices(text.length);
|
|
27
|
+
for (let i = 0; i < text.length; i++) {
|
|
28
|
+
rails[indices[i]] += text[i];
|
|
29
|
+
}
|
|
30
|
+
return rails.join('');
|
|
31
|
+
}
|
|
32
|
+
decrypt(text) {
|
|
33
|
+
const indices = this.zigzagIndices(text.length);
|
|
34
|
+
const counts = Array(this.rails).fill(0);
|
|
35
|
+
for (const r of indices)
|
|
36
|
+
counts[r]++;
|
|
37
|
+
const railStrings = [];
|
|
38
|
+
let pos = 0;
|
|
39
|
+
for (let r = 0; r < this.rails; r++) {
|
|
40
|
+
railStrings.push(text.slice(pos, pos + counts[r]));
|
|
41
|
+
pos += counts[r];
|
|
42
|
+
}
|
|
43
|
+
const railPos = Array(this.rails).fill(0);
|
|
44
|
+
return indices.map((r) => railStrings[r][railPos[r]++]).join('');
|
|
45
|
+
}
|
|
46
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { Cipher } from './Cipher.js';
|
|
2
2
|
import { ADFGVX } from './ciphers/ADFGVX.js';
|
|
3
3
|
import { AES } from './ciphers/AES.js';
|
|
4
|
+
import { AESGCM } from './ciphers/AESGCM.js';
|
|
5
|
+
import { Affine } from './ciphers/Affine.js';
|
|
4
6
|
import { Alphabet } from './ciphers/Alphabet.js';
|
|
5
7
|
import { Atbash } from './ciphers/Atbash.js';
|
|
8
|
+
import { Autokey } from './ciphers/Autokey.js';
|
|
9
|
+
import { Beaufort } from './ciphers/Beaufort.js';
|
|
10
|
+
import { Bifid } from './ciphers/Bifid.js';
|
|
11
|
+
import { Blowfish } from './ciphers/Blowfish.js';
|
|
6
12
|
import { Caesar } from './ciphers/Caesar.js';
|
|
13
|
+
import { ChaCha20 } from './ciphers/ChaCha20.js';
|
|
14
|
+
import { ColumnarTransposition } from './ciphers/ColumnarTransposition.js';
|
|
7
15
|
import { DES } from './ciphers/DES.js';
|
|
8
16
|
import { ECC } from './ciphers/ECC.js';
|
|
9
17
|
import { Nihilist } from './ciphers/Nihilist.js';
|
|
10
18
|
import { Playfair } from './ciphers/Playfair.js';
|
|
19
|
+
import { RailFence } from './ciphers/RailFence.js';
|
|
20
|
+
import { RC4 } from './ciphers/RC4.js';
|
|
11
21
|
import { ROT13 } from './ciphers/ROT13.js';
|
|
22
|
+
import { RSA } from './ciphers/RSA.js';
|
|
12
23
|
import { Salsa20 } from './ciphers/Salsa20.js';
|
|
13
24
|
import { Vigenere } from './ciphers/Vigenere.js';
|
|
14
25
|
Cipher.Caesar = Caesar;
|
|
@@ -23,4 +34,15 @@ Cipher.DES = DES;
|
|
|
23
34
|
Cipher.ECC = ECC;
|
|
24
35
|
Cipher.ROT13 = ROT13;
|
|
25
36
|
Cipher.Nihilist = Nihilist;
|
|
37
|
+
Cipher.RailFence = RailFence;
|
|
38
|
+
Cipher.Affine = Affine;
|
|
39
|
+
Cipher.Beaufort = Beaufort;
|
|
40
|
+
Cipher.Autokey = Autokey;
|
|
41
|
+
Cipher.ColumnarTransposition = ColumnarTransposition;
|
|
42
|
+
Cipher.Bifid = Bifid;
|
|
43
|
+
Cipher.RC4 = RC4;
|
|
44
|
+
Cipher.Blowfish = Blowfish;
|
|
45
|
+
Cipher.ChaCha20 = ChaCha20;
|
|
46
|
+
Cipher.AESGCM = AESGCM;
|
|
47
|
+
Cipher.RSA = RSA;
|
|
26
48
|
export { Cipher };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@irfanshadikrishad/cipher",
|
|
3
3
|
"description": "A versatile and secure cryptographic library for implementing various cipher algorithms in Node.js applications with zero/0 dependencies.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.7.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Irfan Shadik Rishad"
|
|
7
7
|
},
|
|
@@ -48,17 +48,17 @@
|
|
|
48
48
|
"@eslint/js": "^10.0.1",
|
|
49
49
|
"@irfanshadikrishad/prettier": "^1.3.4",
|
|
50
50
|
"@types/jest": "^30.0.0",
|
|
51
|
-
"@types/node": "^25.
|
|
52
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
53
|
-
"@typescript-eslint/parser": "^8.
|
|
54
|
-
"eslint": "^10.
|
|
55
|
-
"globals": "^17.
|
|
51
|
+
"@types/node": "^25.6.0",
|
|
52
|
+
"@typescript-eslint/eslint-plugin": "^8.57.0",
|
|
53
|
+
"@typescript-eslint/parser": "^8.57.0",
|
|
54
|
+
"eslint": "^10.2.0",
|
|
55
|
+
"globals": "^17.5.0",
|
|
56
56
|
"husky": "^9.1.7",
|
|
57
57
|
"jest": "^30.3.0",
|
|
58
|
-
"prettier": "^3.8.
|
|
59
|
-
"ts-jest": "^29.4.
|
|
60
|
-
"typescript": "^
|
|
61
|
-
"typescript-eslint": "^8.57.
|
|
58
|
+
"prettier": "^3.8.3",
|
|
59
|
+
"ts-jest": "^29.4.9",
|
|
60
|
+
"typescript": "^6.0.2",
|
|
61
|
+
"typescript-eslint": "^8.57.0"
|
|
62
62
|
},
|
|
63
63
|
"publishConfig": {
|
|
64
64
|
"access": "public"
|