k9crypt 1.1.6 → 1.1.7
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 +3 -2
- package/package.json +3 -6
- package/src/constants.js +5 -3
- package/src/index.js +14 -11
- package/src/utils/compression.js +11 -7
- package/src/utils/encryption.js +52 -43
- package/src/utils/hashing.js +33 -4
- package/src/utils/math.js +5 -8
package/README.md
CHANGED
|
@@ -6,9 +6,10 @@ This is a special encryption algorithm created for K9Crypt.
|
|
|
6
6
|
|
|
7
7
|
## Updates
|
|
8
8
|
|
|
9
|
-
**v1.1.
|
|
9
|
+
**v1.1.7**
|
|
10
10
|
|
|
11
|
-
-
|
|
11
|
+
- The Argon2 hashing system has now been integrated, offering support for both SHA512 and Argon2.
|
|
12
|
+
- Encryption performance has been optimized, significantly increasing speed.
|
|
12
13
|
|
|
13
14
|
## Installation
|
|
14
15
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "k9crypt",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"description": "A special encryption algorithm created for K9Crypt.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -18,12 +18,9 @@
|
|
|
18
18
|
"author": "K9Crypt Team",
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"
|
|
21
|
+
"argon2": "^0.44.0",
|
|
22
22
|
"crypto-js": "^4.2.0",
|
|
23
|
-
"
|
|
24
|
-
"lzma-native": "^8.0.6",
|
|
25
|
-
"node-forge": "^1.3.1",
|
|
26
|
-
"xxhash": "^0.3.0"
|
|
23
|
+
"lzma-native": "^8.0.6"
|
|
27
24
|
},
|
|
28
25
|
"repository": {
|
|
29
26
|
"type": "git",
|
package/src/constants.js
CHANGED
|
@@ -3,8 +3,10 @@ module.exports = {
|
|
|
3
3
|
IV_SIZE: 16,
|
|
4
4
|
KEY_SIZE: 32,
|
|
5
5
|
TAG_SIZE: 16,
|
|
6
|
-
PBKDF2_ITERATIONS:
|
|
7
|
-
HASH_SEED:
|
|
6
|
+
PBKDF2_ITERATIONS: 50000,
|
|
7
|
+
HASH_SEED: 0xcafebabe,
|
|
8
8
|
PEPPER: 'veryLongAndComplexPepperValue123!@#$%^&*()_+[]{}|;:,.<>?',
|
|
9
9
|
HMAC_KEY: 'veryLongAndComplexHMACKeyValue456!@#$%^&*()_+[]{}|;:,.<>?',
|
|
10
|
-
|
|
10
|
+
ARGON2_SALT_SIZE: 16,
|
|
11
|
+
ARGON2_HASH_LENGTH: 64
|
|
12
|
+
};
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@ const { compress, decompress } = require('./utils/compression');
|
|
|
3
3
|
const { deriveKey } = require('./utils/keyDerivation');
|
|
4
4
|
const { encrypt, decrypt } = require('./utils/encryption');
|
|
5
5
|
const { hash, verifyHash } = require('./utils/hashing');
|
|
6
|
-
const { SALT_SIZE, IV_SIZE, TAG_SIZE } = require('./constants');
|
|
6
|
+
const { SALT_SIZE, IV_SIZE, TAG_SIZE, ARGON2_SALT_SIZE, ARGON2_HASH_LENGTH } = require('./constants');
|
|
7
7
|
|
|
8
8
|
class K9crypt {
|
|
9
9
|
constructor(secretKey) {
|
|
@@ -25,10 +25,11 @@ class K9crypt {
|
|
|
25
25
|
const compressed = await compress(plaintext);
|
|
26
26
|
const salt = crypto.randomBytes(SALT_SIZE);
|
|
27
27
|
const key = await deriveKey(this.secretKey, salt);
|
|
28
|
-
const { iv1, iv2, iv3, iv4, iv5, encrypted, tag1 } = encrypt(compressed, key);
|
|
29
|
-
const dataToHash = Buffer.concat([salt, iv1, iv2, iv3, iv4, iv5, encrypted, tag1]);
|
|
30
|
-
const
|
|
31
|
-
const
|
|
28
|
+
const { iv1, iv2, iv3, iv4, iv5, encrypted, tag1 } = await encrypt(compressed, key);
|
|
29
|
+
const dataToHash = Buffer.concat([ salt, iv1, iv2, iv3, iv4, iv5, encrypted, tag1 ]);
|
|
30
|
+
const argon2Salt = crypto.randomBytes(ARGON2_SALT_SIZE);
|
|
31
|
+
const dataHash = await hash(dataToHash, argon2Salt);
|
|
32
|
+
const result = Buffer.concat([ salt, iv1, iv2, iv3, iv4, iv5, encrypted, tag1, argon2Salt, dataHash ]);
|
|
32
33
|
return result.toString('base64');
|
|
33
34
|
} catch (error) {
|
|
34
35
|
console.log('Encryption failed');
|
|
@@ -44,17 +45,19 @@ class K9crypt {
|
|
|
44
45
|
const iv3 = data.slice(SALT_SIZE + 2 * IV_SIZE, SALT_SIZE + 3 * IV_SIZE);
|
|
45
46
|
const iv4 = data.slice(SALT_SIZE + 3 * IV_SIZE, SALT_SIZE + 4 * IV_SIZE);
|
|
46
47
|
const iv5 = data.slice(SALT_SIZE + 4 * IV_SIZE, SALT_SIZE + 5 * IV_SIZE);
|
|
47
|
-
const encrypted = data.slice(SALT_SIZE + 5 * IV_SIZE, -TAG_SIZE - 64);
|
|
48
|
-
const tag1 = data.slice(-TAG_SIZE - 64, -64);
|
|
49
|
-
const dataHash = data.slice(-64);
|
|
50
48
|
|
|
51
|
-
const
|
|
52
|
-
|
|
49
|
+
const dataHash = data.slice(-ARGON2_HASH_LENGTH);
|
|
50
|
+
const argon2Salt = data.slice(-ARGON2_HASH_LENGTH - ARGON2_SALT_SIZE, -ARGON2_HASH_LENGTH);
|
|
51
|
+
const tag1 = data.slice(-ARGON2_HASH_LENGTH - ARGON2_SALT_SIZE - TAG_SIZE, -ARGON2_HASH_LENGTH - ARGON2_SALT_SIZE);
|
|
52
|
+
const encrypted = data.slice(SALT_SIZE + 5 * IV_SIZE, -ARGON2_HASH_LENGTH - ARGON2_SALT_SIZE - TAG_SIZE);
|
|
53
|
+
|
|
54
|
+
const dataToVerify = data.slice(0, -ARGON2_HASH_LENGTH - ARGON2_SALT_SIZE);
|
|
55
|
+
if (!(await verifyHash(dataToVerify, dataHash, argon2Salt))) {
|
|
53
56
|
console.log('Data integrity check failed');
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
const key = await deriveKey(this.secretKey, salt);
|
|
57
|
-
const decrypted = decrypt(encrypted, key, iv1, iv2, iv3, iv4, iv5, tag1);
|
|
60
|
+
const decrypted = await decrypt(encrypted, key, iv1, iv2, iv3, iv4, iv5, tag1);
|
|
58
61
|
const decompressed = await decompress(decrypted);
|
|
59
62
|
return decompressed.toString('utf8');
|
|
60
63
|
} catch (error) {
|
package/src/utils/compression.js
CHANGED
|
@@ -6,20 +6,24 @@ exports.compress = async (data) => {
|
|
|
6
6
|
const brotliParams = {
|
|
7
7
|
params: {
|
|
8
8
|
[zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,
|
|
9
|
-
[zlib.constants.BROTLI_PARAM_QUALITY]:
|
|
9
|
+
[zlib.constants.BROTLI_PARAM_QUALITY]: 4,
|
|
10
10
|
[zlib.constants.BROTLI_PARAM_SIZE_HINT]: Buffer.byteLength(data, 'utf8'),
|
|
11
11
|
[zlib.constants.BROTLI_PARAM_LGWIN]: 24
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
const brotliCompressed = await new Promise((resolve, reject) => {
|
|
16
|
-
zlib.brotliCompress(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
zlib.brotliCompress(
|
|
17
|
+
Buffer.from(data, 'utf8'),
|
|
18
|
+
brotliParams,
|
|
19
|
+
(err, compressed) => {
|
|
20
|
+
if (err) reject(err);
|
|
21
|
+
else resolve(compressed);
|
|
22
|
+
}
|
|
23
|
+
);
|
|
20
24
|
});
|
|
21
25
|
|
|
22
|
-
const lzmaCompressed = await lzma.compress(brotliCompressed,
|
|
26
|
+
const lzmaCompressed = await lzma.compress(brotliCompressed, 3);
|
|
23
27
|
return lzmaCompressed;
|
|
24
28
|
} catch (error) {
|
|
25
29
|
throw new Error(`Compression error: ${error.message}`);
|
|
@@ -41,4 +45,4 @@ exports.decompress = async (data) => {
|
|
|
41
45
|
} catch (error) {
|
|
42
46
|
throw new Error(`Decompression error: ${error.message}`);
|
|
43
47
|
}
|
|
44
|
-
};
|
|
48
|
+
};
|
package/src/utils/encryption.js
CHANGED
|
@@ -1,52 +1,61 @@
|
|
|
1
1
|
const crypto = require('crypto');
|
|
2
|
+
const { Readable } = require('stream');
|
|
2
3
|
const { IV_SIZE } = require('../constants');
|
|
3
4
|
const { reverseBuffer } = require('./math');
|
|
4
5
|
|
|
5
6
|
exports.encrypt = (data, key) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const iv1 = crypto.randomBytes(IV_SIZE);
|
|
9
|
+
const cipher1 = crypto.createCipheriv('aes-256-gcm', key, iv1);
|
|
10
|
+
|
|
11
|
+
const iv2 = crypto.randomBytes(IV_SIZE);
|
|
12
|
+
const cipher2 = crypto.createCipheriv('aes-256-cbc', key, iv2);
|
|
13
|
+
|
|
14
|
+
const iv3 = crypto.randomBytes(IV_SIZE);
|
|
15
|
+
const cipher3 = crypto.createCipheriv('aes-256-cfb', key, iv3);
|
|
16
|
+
|
|
17
|
+
const iv4 = crypto.randomBytes(IV_SIZE);
|
|
18
|
+
const cipher4 = crypto.createCipheriv('aes-256-ofb', key, iv4);
|
|
19
|
+
|
|
20
|
+
const iv5 = crypto.randomBytes(IV_SIZE);
|
|
21
|
+
const cipher5 = crypto.createCipheriv('aes-256-ctr', key, iv5);
|
|
22
|
+
|
|
23
|
+
const readable = Readable.from(data);
|
|
24
|
+
const chunks = [];
|
|
25
|
+
|
|
26
|
+
const stream = readable.pipe(cipher1).pipe(cipher2).pipe(cipher3).pipe(cipher4).pipe(cipher5);
|
|
27
|
+
|
|
28
|
+
stream.on('data', (chunk) => chunks.push(chunk));
|
|
29
|
+
stream.on('error', (err) => reject(err));
|
|
30
|
+
stream.on('end', () => {
|
|
31
|
+
const encrypted = Buffer.concat(chunks);
|
|
32
|
+
const tag1 = cipher1.getAuthTag();
|
|
33
|
+
const permutedEncrypted = reverseBuffer(encrypted);
|
|
34
|
+
resolve({ iv1, iv2, iv3, iv4, iv5, encrypted: permutedEncrypted, tag1 });
|
|
35
|
+
});
|
|
36
|
+
});
|
|
30
37
|
};
|
|
31
38
|
|
|
32
39
|
exports.decrypt = (encrypted, key, iv1, iv2, iv3, iv4, iv5, tag1) => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
const originalEncrypted = reverseBuffer(encrypted);
|
|
42
|
+
|
|
43
|
+
const decipher5 = crypto.createDecipheriv('aes-256-ctr', key, iv5);
|
|
44
|
+
const decipher4 = crypto.createDecipheriv('aes-256-ofb', key, iv4);
|
|
45
|
+
const decipher3 = crypto.createDecipheriv('aes-256-cfb', key, iv3);
|
|
46
|
+
const decipher2 = crypto.createDecipheriv('aes-256-cbc', key, iv2);
|
|
47
|
+
const decipher1 = crypto.createDecipheriv('aes-256-gcm', key, iv1);
|
|
48
|
+
decipher1.setAuthTag(tag1);
|
|
49
|
+
|
|
50
|
+
const readable = Readable.from(originalEncrypted);
|
|
51
|
+
const chunks = [];
|
|
52
|
+
|
|
53
|
+
const stream = readable.pipe(decipher5).pipe(decipher4).pipe(decipher3).pipe(decipher2).pipe(decipher1);
|
|
54
|
+
|
|
55
|
+
stream.on('data', (chunk) => chunks.push(chunk));
|
|
56
|
+
stream.on('error', (err) => reject(err));
|
|
57
|
+
stream.on('end', () => {
|
|
58
|
+
resolve(Buffer.concat(chunks));
|
|
59
|
+
});
|
|
60
|
+
});
|
|
52
61
|
};
|
package/src/utils/hashing.js
CHANGED
|
@@ -1,13 +1,42 @@
|
|
|
1
1
|
const crypto = require('crypto');
|
|
2
|
-
const
|
|
2
|
+
const argon2 = require('argon2');
|
|
3
|
+
const { HMAC_KEY, ARGON2_HASH_LENGTH } = require('../constants');
|
|
3
4
|
const { reverseHash } = require('./math');
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
const ARGON2_OPTIONS = {
|
|
7
|
+
timeCost: 1,
|
|
8
|
+
memoryCost: 12288,
|
|
9
|
+
parallelism: 4,
|
|
10
|
+
type: argon2.argon2id,
|
|
11
|
+
hashLength: ARGON2_HASH_LENGTH
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
exports.hash = async (data, salt) => {
|
|
6
15
|
const hmac = crypto.createHmac('sha512', HMAC_KEY);
|
|
7
16
|
hmac.update(data);
|
|
8
17
|
const digest = hmac.digest();
|
|
18
|
+
const reversedSha512Hash = reverseHash(digest);
|
|
19
|
+
|
|
20
|
+
const argon2Hash = await argon2.hash(reversedSha512Hash, {
|
|
21
|
+
...ARGON2_OPTIONS,
|
|
22
|
+
salt,
|
|
23
|
+
raw: true
|
|
24
|
+
});
|
|
9
25
|
|
|
10
|
-
return
|
|
26
|
+
return argon2Hash;
|
|
11
27
|
};
|
|
12
28
|
|
|
13
|
-
exports.verifyHash = (data, hash) =>
|
|
29
|
+
exports.verifyHash = async (data, hash, salt) => {
|
|
30
|
+
const hmac = crypto.createHmac('sha512', HMAC_KEY);
|
|
31
|
+
hmac.update(data);
|
|
32
|
+
const digest = hmac.digest();
|
|
33
|
+
const reversedSha512Hash = reverseHash(digest);
|
|
34
|
+
|
|
35
|
+
const expectedHash = await argon2.hash(reversedSha512Hash, {
|
|
36
|
+
...ARGON2_OPTIONS,
|
|
37
|
+
salt,
|
|
38
|
+
raw: true
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return crypto.timingSafeEqual(hash, expectedHash);
|
|
42
|
+
};
|
package/src/utils/math.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
exports.reverseBuffer = (data
|
|
2
|
-
|
|
3
|
-
return Buffer.from(data.toString('hex').split('').reverse().join(''), 'hex');
|
|
4
|
-
}
|
|
5
|
-
return Buffer.from(data.toString('hex').split('').reverse().join(''), 'hex');
|
|
1
|
+
exports.reverseBuffer = (data) => {
|
|
2
|
+
return Buffer.from(data).reverse();
|
|
6
3
|
};
|
|
7
4
|
|
|
8
5
|
exports.reverseHash = (hash) => {
|
|
9
|
-
return Buffer.from(hash
|
|
6
|
+
return Buffer.from(hash).reverse();
|
|
10
7
|
};
|
|
11
8
|
|
|
12
9
|
exports.enhanceKey = (key) => {
|
|
13
|
-
return Buffer.from(key
|
|
14
|
-
};
|
|
10
|
+
return Buffer.from(key).reverse();
|
|
11
|
+
};
|