dsh-vault 1.3.0 → 1.4.0-rc.2
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/lib/chacha20.js +79 -0
- package/lib/client.js +1155 -956
- package/lib/client.js.map +1 -1
- package/lib/der.js +54 -0
- package/lib/firefox.js +141 -0
- package/lib/index.js +246 -0
- package/lib/kdbx.js +329 -0
- package/lib/salsa20.js +91 -0
- package/package.json +1 -1
package/lib/chacha20.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChaCha20 stream cipher (IETF variant, 96-bit nonce) for dsh-vault.
|
|
3
|
+
*
|
|
4
|
+
* Node's crypto module has no ChaCha20 primitive, so this implements the
|
|
5
|
+
* standard 20-round construction needed to decrypt KeePass KDBX protected
|
|
6
|
+
* fields (inner random stream id 2) and other plaintext streams.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-vault/chacha20
|
|
9
|
+
*/
|
|
10
|
+
const ROUNDS = 20;
|
|
11
|
+
const STATE_SIZE = 16;
|
|
12
|
+
function rotl(x, n) {
|
|
13
|
+
return ((x << n) | (x >>> (32 - n))) >>> 0;
|
|
14
|
+
}
|
|
15
|
+
function quarterRound(state, a, b, c, d) {
|
|
16
|
+
state[a] = (state[a] + state[b]) >>> 0;
|
|
17
|
+
state[d] = rotl(state[d] ^ state[a], 16);
|
|
18
|
+
state[c] = (state[c] + state[d]) >>> 0;
|
|
19
|
+
state[b] = rotl(state[b] ^ state[c], 12);
|
|
20
|
+
state[a] = (state[a] + state[b]) >>> 0;
|
|
21
|
+
state[d] = rotl(state[d] ^ state[a], 8);
|
|
22
|
+
state[c] = (state[c] + state[d]) >>> 0;
|
|
23
|
+
state[b] = rotl(state[b] ^ state[c], 7);
|
|
24
|
+
}
|
|
25
|
+
function littleEndian(buf, offset) {
|
|
26
|
+
return (buf[offset] |
|
|
27
|
+
(buf[offset + 1] << 8) |
|
|
28
|
+
(buf[offset + 2] << 16) |
|
|
29
|
+
(buf[offset + 3] << 24)) >>> 0;
|
|
30
|
+
}
|
|
31
|
+
function toBytes(word, out, offset) {
|
|
32
|
+
out[offset] = word & 0xff;
|
|
33
|
+
out[offset + 1] = (word >>> 8) & 0xff;
|
|
34
|
+
out[offset + 2] = (word >>> 16) & 0xff;
|
|
35
|
+
out[offset + 3] = (word >>> 24) & 0xff;
|
|
36
|
+
}
|
|
37
|
+
const CONSTANTS = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574];
|
|
38
|
+
/** XOR `input` with the ChaCha20 keystream. `key` is 32 bytes, `nonce` 12 bytes. */
|
|
39
|
+
export function chacha20Xor(input, key, nonce, counter = 0) {
|
|
40
|
+
if (key.length !== 32)
|
|
41
|
+
throw new Error('chacha20: key must be 32 bytes');
|
|
42
|
+
if (nonce.length !== 12)
|
|
43
|
+
throw new Error('chacha20: nonce must be 12 bytes');
|
|
44
|
+
const out = Buffer.alloc(input.length);
|
|
45
|
+
const keyWords = [
|
|
46
|
+
littleEndian(key, 0), littleEndian(key, 4), littleEndian(key, 8), littleEndian(key, 12),
|
|
47
|
+
littleEndian(key, 16), littleEndian(key, 20), littleEndian(key, 24), littleEndian(key, 28),
|
|
48
|
+
];
|
|
49
|
+
const nonceWords = [
|
|
50
|
+
littleEndian(nonce, 0), littleEndian(nonce, 4), littleEndian(nonce, 8),
|
|
51
|
+
];
|
|
52
|
+
const block = Buffer.alloc(64);
|
|
53
|
+
let pos = 0;
|
|
54
|
+
let blockCounter = counter;
|
|
55
|
+
while (pos < input.length) {
|
|
56
|
+
const state = [...CONSTANTS, ...keyWords, blockCounter >>> 0, ...nonceWords];
|
|
57
|
+
const working = [...state];
|
|
58
|
+
for (let i = 0; i < ROUNDS / 2; i++) {
|
|
59
|
+
quarterRound(working, 0, 4, 8, 12);
|
|
60
|
+
quarterRound(working, 1, 5, 9, 13);
|
|
61
|
+
quarterRound(working, 2, 6, 10, 14);
|
|
62
|
+
quarterRound(working, 3, 7, 11, 15);
|
|
63
|
+
quarterRound(working, 0, 5, 10, 15);
|
|
64
|
+
quarterRound(working, 1, 6, 11, 12);
|
|
65
|
+
quarterRound(working, 2, 7, 8, 13);
|
|
66
|
+
quarterRound(working, 3, 4, 9, 14);
|
|
67
|
+
}
|
|
68
|
+
for (let i = 0; i < STATE_SIZE; i++) {
|
|
69
|
+
toBytes((working[i] + state[i]) >>> 0, block, i * 4);
|
|
70
|
+
}
|
|
71
|
+
const chunk = input.length - pos;
|
|
72
|
+
const take = Math.min(64, chunk);
|
|
73
|
+
for (let i = 0; i < take; i++)
|
|
74
|
+
out[pos + i] = input[pos + i] ^ block[i];
|
|
75
|
+
pos += take;
|
|
76
|
+
blockCounter = (blockCounter + 1) >>> 0;
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|