@irfanshadikrishad/cipher 1.2.0 → 1.3.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 +5 -5
- package/dist/Cipher.d.ts +10 -10
- package/dist/ciphers/ADFGVX.d.ts +1 -1
- package/dist/ciphers/ADFGVX.js +17 -17
- package/dist/ciphers/AES.d.ts +1 -1
- package/dist/ciphers/AES.js +13 -13
- package/dist/ciphers/Alphabet.d.ts +1 -1
- package/dist/ciphers/Alphabet.js +6 -6
- package/dist/ciphers/Atbash.d.ts +1 -1
- package/dist/ciphers/Atbash.js +3 -3
- package/dist/ciphers/Caesar.d.ts +1 -1
- package/dist/ciphers/Caesar.js +5 -5
- package/dist/ciphers/DES.d.ts +1 -1
- package/dist/ciphers/DES.js +9 -9
- package/dist/ciphers/ECC.d.ts +1 -1
- package/dist/ciphers/ECC.js +12 -12
- package/dist/ciphers/Playfair.d.ts +1 -1
- package/dist/ciphers/Playfair.js +9 -9
- package/dist/ciphers/Salsa20.d.ts +1 -1
- package/dist/ciphers/Salsa20.js +11 -11
- package/dist/ciphers/Vigenere.d.ts +1 -1
- package/dist/ciphers/Vigenere.js +11 -11
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -11
- package/package.json +63 -61
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
A versatile and secure cryptographic library for implementing various cipher algorithms in Node.js applications with zero/0 dependencies.
|
|
4
4
|
|
|
5
|
-

|
|
6
|
+

|
|
7
|
+

|
|
8
8
|
|
|
9
9
|
#### 🚀 Installation
|
|
10
10
|
|
|
@@ -31,12 +31,12 @@ bun add @irfanshadikrishad/cipher
|
|
|
31
31
|
Import the library and use a cipher algorithm:
|
|
32
32
|
|
|
33
33
|
```ts
|
|
34
|
-
import { Cipher } from
|
|
34
|
+
import { Cipher } from '@irfanshadikrishad/cipher'
|
|
35
35
|
|
|
36
36
|
// Create a Caesar Cipher instance with a shift of 6
|
|
37
37
|
const caesar = new Cipher.Caesar(6)
|
|
38
38
|
|
|
39
|
-
console.log(caesar.encrypt(
|
|
39
|
+
console.log(caesar.encrypt('hello world')) // Output: "nkrru cuxrj"
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
#### 🔐 Supported Ciphers
|
package/dist/Cipher.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { ADFGVX } from './ciphers/ADFGVX.js';
|
|
2
|
+
import { AES } from './ciphers/AES.js';
|
|
3
|
+
import { Alphabet } from './ciphers/Alphabet.js';
|
|
4
|
+
import { Atbash } from './ciphers/Atbash.js';
|
|
5
|
+
import { Caesar } from './ciphers/Caesar.js';
|
|
6
|
+
import { DES } from './ciphers/DES.js';
|
|
7
|
+
import { ECC } from './ciphers/ECC.js';
|
|
8
|
+
import { Playfair } from './ciphers/Playfair.js';
|
|
9
|
+
import { Salsa20 } from './ciphers/Salsa20.js';
|
|
10
|
+
import { Vigenere } from './ciphers/Vigenere.js';
|
|
11
11
|
export declare abstract class Cipher {
|
|
12
12
|
/**
|
|
13
13
|
* Caesar cipher is a substitution cipher where each letter in the plaintext is shifted a certain number of places down the alphabet.
|
package/dist/ciphers/ADFGVX.d.ts
CHANGED
package/dist/ciphers/ADFGVX.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Cipher } from
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
2
|
export class ADFGVX extends Cipher {
|
|
3
3
|
constructor(key, codeword) {
|
|
4
4
|
super();
|
|
5
|
-
this.key =
|
|
6
|
-
this.codeword =
|
|
5
|
+
this.key = 'CIPHER';
|
|
6
|
+
this.codeword = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
7
7
|
this.polybiusSquare = new Map();
|
|
8
8
|
this.reverseSquare = new Map();
|
|
9
|
-
this.adfgvx = [
|
|
9
|
+
this.adfgvx = ['A', 'D', 'F', 'G', 'V', 'X'];
|
|
10
10
|
if (key)
|
|
11
11
|
this.key = key.toUpperCase();
|
|
12
12
|
if (codeword)
|
|
@@ -20,8 +20,8 @@ export class ADFGVX extends Cipher {
|
|
|
20
20
|
uniqueLetters.push(char);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
const remainingChars =
|
|
24
|
-
.split(
|
|
23
|
+
const remainingChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
|
24
|
+
.split('')
|
|
25
25
|
.filter((char) => !uniqueLetters.includes(char));
|
|
26
26
|
const alphabet = [...uniqueLetters, ...remainingChars];
|
|
27
27
|
let index = 0;
|
|
@@ -42,7 +42,7 @@ export class ADFGVX extends Cipher {
|
|
|
42
42
|
.map((item) => item.index);
|
|
43
43
|
const numCols = this.key.length;
|
|
44
44
|
const numRows = Math.ceil(text.length / numCols);
|
|
45
|
-
const grid = Array.from({ length: numRows }, () => new Array(numCols).fill(
|
|
45
|
+
const grid = Array.from({ length: numRows }, () => new Array(numCols).fill(''));
|
|
46
46
|
if (!decrypt) {
|
|
47
47
|
let charIndex = 0;
|
|
48
48
|
for (let row = 0; row < numRows; row++) {
|
|
@@ -53,8 +53,8 @@ export class ADFGVX extends Cipher {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
return keyOrder
|
|
56
|
-
.map((col) => grid.map((row) => row[col]).join(
|
|
57
|
-
.join(
|
|
56
|
+
.map((col) => grid.map((row) => row[col]).join(''))
|
|
57
|
+
.join('');
|
|
58
58
|
}
|
|
59
59
|
else {
|
|
60
60
|
const sortedKeyOrder = [...keyOrder].sort((a, b) => this.key[a].localeCompare(this.key[b]));
|
|
@@ -66,23 +66,23 @@ export class ADFGVX extends Cipher {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
-
return grid.flat().join(
|
|
69
|
+
return grid.flat().join('');
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
encrypt(text) {
|
|
73
|
-
const plaintext = text.replace(/[^A-Za-z0-9]/g,
|
|
73
|
+
const plaintext = text.replace(/[^A-Za-z0-9]/g, '').toUpperCase();
|
|
74
74
|
const polybiusText = plaintext
|
|
75
|
-
.split(
|
|
76
|
-
.map((char) => this.polybiusSquare.get(char) ||
|
|
77
|
-
.join(
|
|
75
|
+
.split('')
|
|
76
|
+
.map((char) => this.polybiusSquare.get(char) || '')
|
|
77
|
+
.join('');
|
|
78
78
|
return this.columnarTranspose(polybiusText);
|
|
79
79
|
}
|
|
80
80
|
decrypt(text) {
|
|
81
|
-
const encrypted = text.replace(/[^A-Za-z0-9]/g,
|
|
81
|
+
const encrypted = text.replace(/[^A-Za-z0-9]/g, '').toUpperCase();
|
|
82
82
|
const intermediate = this.columnarTranspose(encrypted, true);
|
|
83
83
|
const polybiusText = intermediate.match(/.{1,2}/g)?.map((char) => {
|
|
84
|
-
return this.reverseSquare.get(char) ||
|
|
84
|
+
return this.reverseSquare.get(char) || '';
|
|
85
85
|
}) || [];
|
|
86
|
-
return polybiusText.join(
|
|
86
|
+
return polybiusText.join('');
|
|
87
87
|
}
|
|
88
88
|
}
|
package/dist/ciphers/AES.d.ts
CHANGED
package/dist/ciphers/AES.js
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { Cipher } from '../Cipher.js';
|
|
4
4
|
export class AES extends Cipher {
|
|
5
5
|
constructor(key, iv) {
|
|
6
6
|
super();
|
|
7
|
-
this.key = Buffer.from(key,
|
|
8
|
-
this.iv = Buffer.from(iv,
|
|
7
|
+
this.key = Buffer.from(key, 'hex');
|
|
8
|
+
this.iv = Buffer.from(iv, 'hex');
|
|
9
9
|
if (this.key.length !== 32) {
|
|
10
|
-
throw new Error(
|
|
10
|
+
throw new Error('Invalid key length: AES-256 requires a 32-byte key');
|
|
11
11
|
}
|
|
12
12
|
if (this.iv.length !== 16) {
|
|
13
|
-
throw new Error(
|
|
13
|
+
throw new Error('Invalid IV length: AES requires a 16-byte IV');
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
encrypt(plaintext) {
|
|
17
|
-
const cipher = crypto.createCipheriv(
|
|
18
|
-
let encrypted = cipher.update(plaintext,
|
|
19
|
-
encrypted += cipher.final(
|
|
17
|
+
const cipher = crypto.createCipheriv('aes-256-cbc', this.key, this.iv);
|
|
18
|
+
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
|
|
19
|
+
encrypted += cipher.final('hex');
|
|
20
20
|
return encrypted;
|
|
21
21
|
}
|
|
22
22
|
decrypt(ciphertext) {
|
|
23
|
-
const decipher = crypto.createDecipheriv(
|
|
24
|
-
let decrypted = decipher.update(ciphertext,
|
|
25
|
-
decrypted += decipher.final(
|
|
23
|
+
const decipher = crypto.createDecipheriv('aes-256-cbc', this.key, this.iv);
|
|
24
|
+
let decrypted = decipher.update(ciphertext, 'hex', 'utf8');
|
|
25
|
+
decrypted += decipher.final('utf8');
|
|
26
26
|
return decrypted;
|
|
27
27
|
}
|
|
28
28
|
}
|
package/dist/ciphers/Alphabet.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Cipher } from
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
2
|
export class Alphabet extends Cipher {
|
|
3
3
|
constructor(keyword) {
|
|
4
4
|
super();
|
|
@@ -12,7 +12,7 @@ export class Alphabet extends Cipher {
|
|
|
12
12
|
encrypt(message) {
|
|
13
13
|
message = message.toLowerCase();
|
|
14
14
|
const table = Alphabet.getVigenereTable();
|
|
15
|
-
let result =
|
|
15
|
+
let result = '';
|
|
16
16
|
for (let i = 0; i < message.length; i++) {
|
|
17
17
|
const msgChar = message[i];
|
|
18
18
|
const keyChar = this.keyword[i % this.keyword.length];
|
|
@@ -34,7 +34,7 @@ export class Alphabet extends Cipher {
|
|
|
34
34
|
decrypt(ciphertext) {
|
|
35
35
|
ciphertext = ciphertext.toLowerCase();
|
|
36
36
|
const table = Alphabet.getVigenereTable();
|
|
37
|
-
let result =
|
|
37
|
+
let result = '';
|
|
38
38
|
for (let i = 0; i < ciphertext.length; i++) {
|
|
39
39
|
const cipherChar = ciphertext[i];
|
|
40
40
|
const keyChar = this.keyword[i % this.keyword.length];
|
|
@@ -56,10 +56,10 @@ export class Alphabet extends Cipher {
|
|
|
56
56
|
for (let i = 0; i < 26; i++) {
|
|
57
57
|
table[i] = Alphabet.alphabet
|
|
58
58
|
.slice(i)
|
|
59
|
-
.split(
|
|
60
|
-
.concat(Alphabet.alphabet.slice(0, i).split(
|
|
59
|
+
.split('')
|
|
60
|
+
.concat(Alphabet.alphabet.slice(0, i).split(''));
|
|
61
61
|
}
|
|
62
62
|
return table;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
Alphabet.alphabet =
|
|
65
|
+
Alphabet.alphabet = 'abcdefghijklmnopqrstuvwxyz';
|
package/dist/ciphers/Atbash.d.ts
CHANGED
package/dist/ciphers/Atbash.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Cipher } from
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
2
|
export class Atbash extends Cipher {
|
|
3
3
|
encrypt(text) {
|
|
4
4
|
return text
|
|
5
|
-
.split(
|
|
5
|
+
.split('')
|
|
6
6
|
.map((char) => {
|
|
7
7
|
const code = char.charCodeAt(0);
|
|
8
8
|
if (code >= 65 && code <= 90) {
|
|
@@ -13,7 +13,7 @@ export class Atbash extends Cipher {
|
|
|
13
13
|
}
|
|
14
14
|
return char;
|
|
15
15
|
})
|
|
16
|
-
.join(
|
|
16
|
+
.join('');
|
|
17
17
|
}
|
|
18
18
|
decrypt(text) {
|
|
19
19
|
// Since Atbash is a reciprocal cipher, encryption and decryption are identical.
|
package/dist/ciphers/Caesar.d.ts
CHANGED
package/dist/ciphers/Caesar.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Cipher } from
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
2
|
export class Caesar extends Cipher {
|
|
3
3
|
constructor(shift) {
|
|
4
4
|
super();
|
|
@@ -6,7 +6,7 @@ export class Caesar extends Cipher {
|
|
|
6
6
|
}
|
|
7
7
|
encrypt(text) {
|
|
8
8
|
return text
|
|
9
|
-
.split(
|
|
9
|
+
.split('')
|
|
10
10
|
.map((char) => {
|
|
11
11
|
const code = char.charCodeAt(0);
|
|
12
12
|
if (code >= 65 && code <= 90) {
|
|
@@ -17,11 +17,11 @@ export class Caesar extends Cipher {
|
|
|
17
17
|
}
|
|
18
18
|
return char;
|
|
19
19
|
})
|
|
20
|
-
.join(
|
|
20
|
+
.join('');
|
|
21
21
|
}
|
|
22
22
|
decrypt(text) {
|
|
23
23
|
return text
|
|
24
|
-
.split(
|
|
24
|
+
.split('')
|
|
25
25
|
.map((char) => {
|
|
26
26
|
const code = char.charCodeAt(0);
|
|
27
27
|
if (code >= 65 && code <= 90) {
|
|
@@ -32,6 +32,6 @@ export class Caesar extends Cipher {
|
|
|
32
32
|
}
|
|
33
33
|
return char;
|
|
34
34
|
})
|
|
35
|
-
.join(
|
|
35
|
+
.join('');
|
|
36
36
|
}
|
|
37
37
|
}
|
package/dist/ciphers/DES.d.ts
CHANGED
package/dist/ciphers/DES.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { Cipher } from '../Cipher.js';
|
|
3
3
|
const IP = [
|
|
4
4
|
// Initial Permutation
|
|
5
5
|
58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38,
|
|
@@ -18,7 +18,7 @@ export class DES extends Cipher {
|
|
|
18
18
|
constructor(key) {
|
|
19
19
|
super();
|
|
20
20
|
if (key.length !== 8)
|
|
21
|
-
throw new Error(
|
|
21
|
+
throw new Error('DES key must be exactly 8 characters.');
|
|
22
22
|
this.key = this.stringToBigInt(key);
|
|
23
23
|
}
|
|
24
24
|
encrypt(text) {
|
|
@@ -30,15 +30,15 @@ export class DES extends Cipher {
|
|
|
30
30
|
const permuted = this.permute(input, IP);
|
|
31
31
|
const encrypted = this.feistel(permuted);
|
|
32
32
|
const finalPerm = this.permute(encrypted, FP);
|
|
33
|
-
encryptedBlocks.push(finalPerm.toString(16).padStart(16,
|
|
33
|
+
encryptedBlocks.push(finalPerm.toString(16).padStart(16, '0'));
|
|
34
34
|
}
|
|
35
|
-
return encryptedBlocks.join(
|
|
35
|
+
return encryptedBlocks.join(''); // Concatenate hex strings
|
|
36
36
|
}
|
|
37
37
|
decrypt(text) {
|
|
38
|
-
let decryptedText =
|
|
38
|
+
let decryptedText = '';
|
|
39
39
|
for (let i = 0; i < text.length; i += 16) {
|
|
40
40
|
// 16 hex chars = 8 bytes
|
|
41
|
-
const block = BigInt(
|
|
41
|
+
const block = BigInt('0x' + text.substring(i, i + 16));
|
|
42
42
|
const permuted = this.permute(block, IP);
|
|
43
43
|
const decrypted = this.feistel(permuted);
|
|
44
44
|
const finalPerm = this.permute(decrypted, FP);
|
|
@@ -79,9 +79,9 @@ export class DES extends Cipher {
|
|
|
79
79
|
return output;
|
|
80
80
|
}
|
|
81
81
|
stringToBigInt(str) {
|
|
82
|
-
return BigInt(
|
|
82
|
+
return BigInt('0x' + Buffer.from(str, 'utf8').toString('hex'));
|
|
83
83
|
}
|
|
84
84
|
bigIntToString(num) {
|
|
85
|
-
return Buffer.from(num.toString(16).padStart(16,
|
|
85
|
+
return Buffer.from(num.toString(16).padStart(16, '0'), 'hex').toString('utf8');
|
|
86
86
|
}
|
|
87
87
|
}
|
package/dist/ciphers/ECC.d.ts
CHANGED
package/dist/ciphers/ECC.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import crypto from
|
|
2
|
-
import { Cipher } from
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import { Cipher } from '../Cipher.js';
|
|
3
3
|
export class ECC extends Cipher {
|
|
4
4
|
constructor(recipientPublicKey, ownPrivateKey) {
|
|
5
5
|
super();
|
|
@@ -7,16 +7,16 @@ export class ECC extends Cipher {
|
|
|
7
7
|
this.ownPrivateKey = ownPrivateKey;
|
|
8
8
|
}
|
|
9
9
|
static async generate() {
|
|
10
|
-
const { publicKey, privateKey } = await crypto.subtle.generateKey({ name:
|
|
10
|
+
const { publicKey, privateKey } = await crypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey', 'deriveBits']);
|
|
11
11
|
return new ECC(publicKey, privateKey);
|
|
12
12
|
}
|
|
13
13
|
async encrypt(plaintext) {
|
|
14
14
|
if (!this.recipientPublicKey)
|
|
15
|
-
throw new Error(
|
|
15
|
+
throw new Error('Recipient public key not set');
|
|
16
16
|
const ephemeral = await ECC.generate();
|
|
17
|
-
const sharedKey = await crypto.subtle.deriveKey({ name:
|
|
17
|
+
const sharedKey = await crypto.subtle.deriveKey({ name: 'ECDH', public: this.recipientPublicKey }, ephemeral.ownPrivateKey, { name: 'AES-GCM', length: 256 }, false, ['encrypt']);
|
|
18
18
|
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
19
|
-
const encrypted = await crypto.subtle.encrypt({ name:
|
|
19
|
+
const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, sharedKey, new TextEncoder().encode(plaintext));
|
|
20
20
|
const payload = {
|
|
21
21
|
iv: ECC.bufToHex(iv),
|
|
22
22
|
ciphertext: ECC.bufToHex(new Uint8Array(encrypted)),
|
|
@@ -26,24 +26,24 @@ export class ECC extends Cipher {
|
|
|
26
26
|
}
|
|
27
27
|
async decrypt(data) {
|
|
28
28
|
if (!this.ownPrivateKey)
|
|
29
|
-
throw new Error(
|
|
29
|
+
throw new Error('Own private key not set');
|
|
30
30
|
const { iv, ciphertext, ephemeralPublicHex } = JSON.parse(data);
|
|
31
31
|
const ephemeralPubKey = await ECC.importPublicKey(ephemeralPublicHex);
|
|
32
|
-
const sharedKey = await crypto.subtle.deriveKey({ name:
|
|
33
|
-
const decrypted = await crypto.subtle.decrypt({ name:
|
|
32
|
+
const sharedKey = await crypto.subtle.deriveKey({ name: 'ECDH', public: ephemeralPubKey }, this.ownPrivateKey, { name: 'AES-GCM', length: 256 }, false, ['decrypt']);
|
|
33
|
+
const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: ECC.hexToBuf(iv) }, sharedKey, ECC.hexToBuf(ciphertext));
|
|
34
34
|
return new TextDecoder().decode(decrypted);
|
|
35
35
|
}
|
|
36
36
|
async exportPublicKey() {
|
|
37
|
-
const raw = await crypto.subtle.exportKey(
|
|
37
|
+
const raw = await crypto.subtle.exportKey('raw', this.recipientPublicKey || this.ownPrivateKey);
|
|
38
38
|
return ECC.bufToHex(new Uint8Array(raw));
|
|
39
39
|
}
|
|
40
40
|
static async importPublicKey(hex) {
|
|
41
41
|
const raw = ECC.hexToBuf(hex);
|
|
42
|
-
return crypto.subtle.importKey(
|
|
42
|
+
return crypto.subtle.importKey('raw', raw, { name: 'ECDH', namedCurve: 'P-256' }, true, []);
|
|
43
43
|
}
|
|
44
44
|
// Helpers
|
|
45
45
|
static bufToHex(buf) {
|
|
46
|
-
return [...buf].map((b) => b.toString(16).padStart(2,
|
|
46
|
+
return [...buf].map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
47
47
|
}
|
|
48
48
|
static hexToBuf(hex) {
|
|
49
49
|
const bytes = new Uint8Array(hex.length / 2);
|
package/dist/ciphers/Playfair.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { Cipher } from
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
2
|
export class Playfair extends Cipher {
|
|
3
3
|
constructor(key) {
|
|
4
4
|
super();
|
|
5
5
|
this.keyMatrix = this.generateKeyMatrix(key);
|
|
6
6
|
}
|
|
7
7
|
generateKeyMatrix(key) {
|
|
8
|
-
key = key.toUpperCase().replace(/J/g,
|
|
8
|
+
key = key.toUpperCase().replace(/J/g, 'I');
|
|
9
9
|
const seen = new Set();
|
|
10
10
|
const matrix = [];
|
|
11
|
-
const alphabet =
|
|
11
|
+
const alphabet = 'ABCDEFGHIKLMNOPQRSTUVWXYZ';
|
|
12
12
|
key += alphabet;
|
|
13
13
|
for (const char of key) {
|
|
14
14
|
if (!seen.has(char) && alphabet.includes(char)) {
|
|
@@ -31,14 +31,14 @@ export class Playfair extends Cipher {
|
|
|
31
31
|
prepareText(text) {
|
|
32
32
|
text = text
|
|
33
33
|
.toUpperCase()
|
|
34
|
-
.replace(/J/g,
|
|
35
|
-
.replace(/[^A-Z]/g,
|
|
36
|
-
let result =
|
|
34
|
+
.replace(/J/g, 'I')
|
|
35
|
+
.replace(/[^A-Z]/g, '');
|
|
36
|
+
let result = '';
|
|
37
37
|
for (let i = 0; i < text.length; i += 2) {
|
|
38
38
|
const a = text[i];
|
|
39
|
-
const b = text[i + 1] ||
|
|
39
|
+
const b = text[i + 1] || 'X';
|
|
40
40
|
if (a === b) {
|
|
41
|
-
result += a +
|
|
41
|
+
result += a + 'X';
|
|
42
42
|
i--;
|
|
43
43
|
}
|
|
44
44
|
else {
|
|
@@ -48,7 +48,7 @@ export class Playfair extends Cipher {
|
|
|
48
48
|
return result;
|
|
49
49
|
}
|
|
50
50
|
processPairs(text, encrypt) {
|
|
51
|
-
let result =
|
|
51
|
+
let result = '';
|
|
52
52
|
const shift = encrypt ? 1 : -1;
|
|
53
53
|
for (let i = 0; i < text.length; i += 2) {
|
|
54
54
|
const [row1, col1] = this.findPosition(text[i]);
|
package/dist/ciphers/Salsa20.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import crypto from
|
|
3
|
-
import {
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { Cipher } from '../Cipher.js';
|
|
4
4
|
export class Salsa20 extends Cipher {
|
|
5
5
|
constructor(key, nonce, counter = 0) {
|
|
6
6
|
super();
|
|
7
|
-
if (typeof key ===
|
|
8
|
-
key = Buffer.from(key,
|
|
9
|
-
if (typeof nonce ===
|
|
10
|
-
nonce = Buffer.from(nonce,
|
|
7
|
+
if (typeof key === 'string')
|
|
8
|
+
key = Buffer.from(key, 'base64');
|
|
9
|
+
if (typeof nonce === 'string')
|
|
10
|
+
nonce = Buffer.from(nonce, 'base64');
|
|
11
11
|
if (key.length !== 32)
|
|
12
|
-
throw new Error(
|
|
12
|
+
throw new Error('Key must be 32 bytes (256-bit).');
|
|
13
13
|
if (nonce.length !== 8)
|
|
14
|
-
throw new Error(
|
|
14
|
+
throw new Error('Nonce must be 8 bytes (64-bit).');
|
|
15
15
|
this.key = new Uint32Array(new Uint8Array(key).buffer);
|
|
16
16
|
this.nonce = new Uint32Array(new Uint8Array(nonce).buffer);
|
|
17
17
|
this.counter = counter;
|
|
@@ -86,9 +86,9 @@ export class Salsa20 extends Cipher {
|
|
|
86
86
|
return Salsa20.encodeBase64(crypto.getRandomValues(new Uint8Array(8)));
|
|
87
87
|
}
|
|
88
88
|
static encodeBase64(uint8array) {
|
|
89
|
-
return Buffer.from(uint8array).toString(
|
|
89
|
+
return Buffer.from(uint8array).toString('base64');
|
|
90
90
|
}
|
|
91
91
|
static decodeBase64(base64) {
|
|
92
|
-
return new Uint8Array(Buffer.from(base64,
|
|
92
|
+
return new Uint8Array(Buffer.from(base64, 'base64'));
|
|
93
93
|
}
|
|
94
94
|
}
|
package/dist/ciphers/Vigenere.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { Cipher } from
|
|
1
|
+
import { Cipher } from '../Cipher.js';
|
|
2
2
|
export class Vigenere extends Cipher {
|
|
3
3
|
constructor(key) {
|
|
4
4
|
super();
|
|
5
5
|
if (!key || !/^[a-zA-Z]+$/.test(key)) {
|
|
6
|
-
throw new Error(
|
|
6
|
+
throw new Error('Key must be a non-empty string containing only letters.');
|
|
7
7
|
}
|
|
8
8
|
this.key = key.toUpperCase();
|
|
9
9
|
}
|
|
10
10
|
repeatKey(text) {
|
|
11
|
-
let repeatedKey =
|
|
11
|
+
let repeatedKey = '';
|
|
12
12
|
for (let i = 0, j = 0; i < text.length; i++) {
|
|
13
13
|
const char = text[i];
|
|
14
14
|
if (/[a-zA-Z]/.test(char)) {
|
|
@@ -24,16 +24,16 @@ export class Vigenere extends Cipher {
|
|
|
24
24
|
encrypt(text) {
|
|
25
25
|
const key = this.repeatKey(text);
|
|
26
26
|
return text
|
|
27
|
-
.split(
|
|
27
|
+
.split('')
|
|
28
28
|
.map((char, i) => {
|
|
29
|
-
if (char >=
|
|
29
|
+
if (char >= 'A' && char <= 'Z') {
|
|
30
30
|
return String.fromCharCode(((char.charCodeAt(0) -
|
|
31
31
|
65 +
|
|
32
32
|
(key[i].toUpperCase().charCodeAt(0) - 65)) %
|
|
33
33
|
26) +
|
|
34
34
|
65);
|
|
35
35
|
}
|
|
36
|
-
else if (char >=
|
|
36
|
+
else if (char >= 'a' && char <= 'z') {
|
|
37
37
|
return String.fromCharCode(((char.charCodeAt(0) -
|
|
38
38
|
97 +
|
|
39
39
|
(key[i].toLowerCase().charCodeAt(0) - 97)) %
|
|
@@ -42,14 +42,14 @@ export class Vigenere extends Cipher {
|
|
|
42
42
|
}
|
|
43
43
|
return char;
|
|
44
44
|
})
|
|
45
|
-
.join(
|
|
45
|
+
.join('');
|
|
46
46
|
}
|
|
47
47
|
decrypt(text) {
|
|
48
48
|
const key = this.repeatKey(text);
|
|
49
49
|
return text
|
|
50
|
-
.split(
|
|
50
|
+
.split('')
|
|
51
51
|
.map((char, i) => {
|
|
52
|
-
if (char >=
|
|
52
|
+
if (char >= 'A' && char <= 'Z') {
|
|
53
53
|
return String.fromCharCode(((char.charCodeAt(0) -
|
|
54
54
|
65 -
|
|
55
55
|
(key[i].toUpperCase().charCodeAt(0) - 65) +
|
|
@@ -57,7 +57,7 @@ export class Vigenere extends Cipher {
|
|
|
57
57
|
26) +
|
|
58
58
|
65);
|
|
59
59
|
}
|
|
60
|
-
else if (char >=
|
|
60
|
+
else if (char >= 'a' && char <= 'z') {
|
|
61
61
|
return String.fromCharCode(((char.charCodeAt(0) -
|
|
62
62
|
97 -
|
|
63
63
|
(key[i].toLowerCase().charCodeAt(0) - 97) +
|
|
@@ -67,6 +67,6 @@ export class Vigenere extends Cipher {
|
|
|
67
67
|
}
|
|
68
68
|
return char;
|
|
69
69
|
})
|
|
70
|
-
.join(
|
|
70
|
+
.join('');
|
|
71
71
|
}
|
|
72
72
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Cipher } from
|
|
1
|
+
import { Cipher } from './Cipher.js';
|
|
2
2
|
export { Cipher };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { Cipher } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
1
|
+
import { Cipher } from './Cipher.js';
|
|
2
|
+
import { ADFGVX } from './ciphers/ADFGVX.js';
|
|
3
|
+
import { AES } from './ciphers/AES.js';
|
|
4
|
+
import { Alphabet } from './ciphers/Alphabet.js';
|
|
5
|
+
import { Atbash } from './ciphers/Atbash.js';
|
|
6
|
+
import { Caesar } from './ciphers/Caesar.js';
|
|
7
|
+
import { DES } from './ciphers/DES.js';
|
|
8
|
+
import { ECC } from './ciphers/ECC.js';
|
|
9
|
+
import { Playfair } from './ciphers/Playfair.js';
|
|
10
|
+
import { Salsa20 } from './ciphers/Salsa20.js';
|
|
11
|
+
import { Vigenere } from './ciphers/Vigenere.js';
|
|
12
12
|
Cipher.Caesar = Caesar;
|
|
13
13
|
Cipher.Atbash = Atbash;
|
|
14
14
|
Cipher.Playfair = Playfair;
|
package/package.json
CHANGED
|
@@ -1,63 +1,65 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
2
|
+
"name": "@irfanshadikrishad/cipher",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "A versatile and secure cryptographic library for implementing various cipher algorithms in Node.js applications with zero/0 dependencies.",
|
|
5
|
+
"homepage": "https://github.com/irfanshadikrishad/cipher#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/irfanshadikrishad/cipher/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/irfanshadikrishad/cipher.git"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"directories": {
|
|
17
|
+
"test": "test",
|
|
18
|
+
"lib": "src"
|
|
19
|
+
},
|
|
20
|
+
"license": "MPL-2.0",
|
|
21
|
+
"author": {
|
|
22
|
+
"name": "Irfan Shadik Rishad"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"bin": {
|
|
30
|
+
"cipher": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "rm -rf ./dist && tsc",
|
|
34
|
+
"build:watch": "rm -rf ./dist && tsc -w",
|
|
35
|
+
"format": "prettier . --write",
|
|
36
|
+
"lint": "eslint . --ext .ts",
|
|
37
|
+
"lint:fix": "eslint . --ext .ts --fix",
|
|
38
|
+
"test": "jest ./tests",
|
|
39
|
+
"prepare": "husky",
|
|
40
|
+
"all": "npm run build && npm run format && npm run lint && npm run test"
|
|
41
|
+
},
|
|
42
|
+
"prettier": "@irfanshadikrishad/prettier",
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@eslint/js": "^9.29.0",
|
|
45
|
+
"@irfanshadikrishad/prettier": "^1.1.0",
|
|
46
|
+
"@types/jest": "^30.0.0",
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "^8.34.0",
|
|
48
|
+
"@typescript-eslint/parser": "^8.34.0",
|
|
49
|
+
"eslint": "^9.29.0",
|
|
50
|
+
"globals": "^16.2.0",
|
|
51
|
+
"husky": "^9.1.7",
|
|
52
|
+
"jest": "^30.0.2",
|
|
53
|
+
"prettier": "^3.5.3",
|
|
54
|
+
"ts-jest": "^29.4.0",
|
|
55
|
+
"typescript": "^5.8.3",
|
|
56
|
+
"typescript-eslint": "^8.34.0"
|
|
57
|
+
},
|
|
58
|
+
"keywords": [
|
|
59
|
+
"security",
|
|
60
|
+
"cipher",
|
|
61
|
+
"cryptography",
|
|
62
|
+
"encryption",
|
|
63
|
+
"decryption"
|
|
64
|
+
]
|
|
63
65
|
}
|