@keynv/core 0.1.0-rc.23
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/LICENSE +21 -0
- package/dist/audit/chain.d.ts +44 -0
- package/dist/audit/chain.d.ts.map +1 -0
- package/dist/audit/chain.js +134 -0
- package/dist/audit/chain.js.map +1 -0
- package/dist/audit/chain.test.d.ts +2 -0
- package/dist/audit/chain.test.d.ts.map +1 -0
- package/dist/audit/chain.test.js +192 -0
- package/dist/audit/chain.test.js.map +1 -0
- package/dist/audit/index.d.ts +5 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +4 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/payload-schemas.d.ts +343 -0
- package/dist/audit/payload-schemas.d.ts.map +1 -0
- package/dist/audit/payload-schemas.js +112 -0
- package/dist/audit/payload-schemas.js.map +1 -0
- package/dist/audit/payload-schemas.test.d.ts +2 -0
- package/dist/audit/payload-schemas.test.d.ts.map +1 -0
- package/dist/audit/payload-schemas.test.js +93 -0
- package/dist/audit/payload-schemas.test.js.map +1 -0
- package/dist/audit/types.d.ts +34 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/audit/types.js +6 -0
- package/dist/audit/types.js.map +1 -0
- package/dist/crypto/envelope.d.ts +55 -0
- package/dist/crypto/envelope.d.ts.map +1 -0
- package/dist/crypto/envelope.js +108 -0
- package/dist/crypto/envelope.js.map +1 -0
- package/dist/crypto/envelope.test.d.ts +2 -0
- package/dist/crypto/envelope.test.d.ts.map +1 -0
- package/dist/crypto/envelope.test.js +163 -0
- package/dist/crypto/envelope.test.js.map +1 -0
- package/dist/crypto/index.d.ts +5 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +4 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/sodium.d.ts +21 -0
- package/dist/crypto/sodium.d.ts.map +1 -0
- package/dist/crypto/sodium.js +43 -0
- package/dist/crypto/sodium.js.map +1 -0
- package/dist/crypto/types.d.ts +37 -0
- package/dist/crypto/types.d.ts.map +1 -0
- package/dist/crypto/types.js +11 -0
- package/dist/crypto/types.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/reference/index.d.ts +4 -0
- package/dist/reference/index.d.ts.map +1 -0
- package/dist/reference/index.js +3 -0
- package/dist/reference/index.js.map +1 -0
- package/dist/reference/parser-property.test.d.ts +2 -0
- package/dist/reference/parser-property.test.d.ts.map +1 -0
- package/dist/reference/parser-property.test.js +115 -0
- package/dist/reference/parser-property.test.js.map +1 -0
- package/dist/reference/parser.d.ts +54 -0
- package/dist/reference/parser.d.ts.map +1 -0
- package/dist/reference/parser.js +144 -0
- package/dist/reference/parser.js.map +1 -0
- package/dist/reference/parser.test.d.ts +2 -0
- package/dist/reference/parser.test.d.ts.map +1 -0
- package/dist/reference/parser.test.js +195 -0
- package/dist/reference/parser.test.js.map +1 -0
- package/dist/reference/types.d.ts +52 -0
- package/dist/reference/types.d.ts.map +1 -0
- package/dist/reference/types.js +11 -0
- package/dist/reference/types.js.map +1 -0
- package/dist/validation/index.d.ts +33 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +45 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/schemas.test.d.ts +2 -0
- package/dist/validation/schemas.test.d.ts.map +1 -0
- package/dist/validation/schemas.test.js +18 -0
- package/dist/validation/schemas.test.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type SealedSecret, type SymmetricKey, type WrappedKey } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates a fresh 32-byte symmetric key.
|
|
4
|
+
*
|
|
5
|
+
* Use for both the master KEK (held by the org owner, encrypts each
|
|
6
|
+
* project's DEK) and per-project DEKs (encrypts secret values).
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateKey(): Promise<SymmetricKey>;
|
|
9
|
+
/**
|
|
10
|
+
* Wraps a DEK with a KEK. Output is the ciphertext + the random nonce
|
|
11
|
+
* used for this wrap operation; both are needed to unwrap.
|
|
12
|
+
*
|
|
13
|
+
* Throws if either key has the wrong length — typed inputs make this
|
|
14
|
+
* a programmer-error indicator, not a user-facing failure.
|
|
15
|
+
*/
|
|
16
|
+
export declare function wrapDek(dek: SymmetricKey, kek: SymmetricKey): Promise<WrappedKey>;
|
|
17
|
+
/**
|
|
18
|
+
* Unwraps a DEK previously produced by `wrapDek`. Throws if
|
|
19
|
+
* authentication fails (wrong KEK, tampered ciphertext, wrong nonce).
|
|
20
|
+
*/
|
|
21
|
+
export declare function unwrapDek(wrapped: WrappedKey, kek: SymmetricKey): Promise<SymmetricKey>;
|
|
22
|
+
/**
|
|
23
|
+
* Encrypts raw secret bytes with the project's DEK. Each call uses a fresh
|
|
24
|
+
* random nonce; identical plaintexts produce different ciphertexts.
|
|
25
|
+
*
|
|
26
|
+
* The caller owns `plaintext` and must zero it after this function returns.
|
|
27
|
+
*/
|
|
28
|
+
export declare function encryptSecretBytes(plaintext: Uint8Array, dek: SymmetricKey): Promise<SealedSecret>;
|
|
29
|
+
/**
|
|
30
|
+
* Decrypts a sealed secret to raw bytes. Throws if authentication fails.
|
|
31
|
+
*
|
|
32
|
+
* The returned buffer contains plaintext. Callers must either zero it in a
|
|
33
|
+
* `finally` block or use `withDecryptedSecretBytes`, which does that for them.
|
|
34
|
+
*/
|
|
35
|
+
export declare function decryptSecretBytes(sealed: SealedSecret, dek: SymmetricKey): Promise<Uint8Array>;
|
|
36
|
+
/**
|
|
37
|
+
* Decrypts secret bytes for the duration of a callback and then zeroes the
|
|
38
|
+
* plaintext buffer even when the callback throws.
|
|
39
|
+
*/
|
|
40
|
+
export declare function withDecryptedSecretBytes<T>(sealed: SealedSecret, dek: SymmetricKey, usePlaintext: (plaintext: Uint8Array) => T | Promise<T>): Promise<T>;
|
|
41
|
+
/**
|
|
42
|
+
* Encrypts a UTF-8 string secret value with the project's DEK.
|
|
43
|
+
*
|
|
44
|
+
* This compatibility wrapper zeroes its encoded byte buffer, but the input
|
|
45
|
+
* string itself remains V8-managed and cannot be reliably wiped.
|
|
46
|
+
*/
|
|
47
|
+
export declare function encryptSecret(value: string, dek: SymmetricKey): Promise<SealedSecret>;
|
|
48
|
+
/**
|
|
49
|
+
* Decrypts a sealed secret to a UTF-8 string.
|
|
50
|
+
*
|
|
51
|
+
* This compatibility wrapper zeroes decrypted bytes after decoding, but the
|
|
52
|
+
* returned string is V8-managed and cannot be reliably wiped by callers.
|
|
53
|
+
*/
|
|
54
|
+
export declare function decryptSecret(sealed: SealedSecret, dek: SymmetricKey): Promise<string>;
|
|
55
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/crypto/envelope.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,CAGzD;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAOvF;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAK7F;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,UAAU,EACrB,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,YAAY,CAAC,CAMvB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,UAAU,CAAC,CAOrB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,CAAC,EAC9C,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,YAAY,EACjB,YAAY,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACtD,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAO3F;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAI5F"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { loadSodium, zero } from './sodium.js';
|
|
2
|
+
import { KEY_BYTES, NONCE_BYTES, } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generates a fresh 32-byte symmetric key.
|
|
5
|
+
*
|
|
6
|
+
* Use for both the master KEK (held by the org owner, encrypts each
|
|
7
|
+
* project's DEK) and per-project DEKs (encrypts secret values).
|
|
8
|
+
*/
|
|
9
|
+
export async function generateKey() {
|
|
10
|
+
const sodium = await loadSodium();
|
|
11
|
+
return sodium.randombytes_buf(KEY_BYTES);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Wraps a DEK with a KEK. Output is the ciphertext + the random nonce
|
|
15
|
+
* used for this wrap operation; both are needed to unwrap.
|
|
16
|
+
*
|
|
17
|
+
* Throws if either key has the wrong length — typed inputs make this
|
|
18
|
+
* a programmer-error indicator, not a user-facing failure.
|
|
19
|
+
*/
|
|
20
|
+
export async function wrapDek(dek, kek) {
|
|
21
|
+
if (dek.length !== KEY_BYTES)
|
|
22
|
+
throw new Error('wrapDek: DEK must be 32 bytes');
|
|
23
|
+
if (kek.length !== KEY_BYTES)
|
|
24
|
+
throw new Error('wrapDek: KEK must be 32 bytes');
|
|
25
|
+
const sodium = await loadSodium();
|
|
26
|
+
const nonce = sodium.randombytes_buf(NONCE_BYTES);
|
|
27
|
+
const ciphertext = sodium.crypto_secretbox_easy(dek, nonce, kek);
|
|
28
|
+
return { ciphertext, nonce };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Unwraps a DEK previously produced by `wrapDek`. Throws if
|
|
32
|
+
* authentication fails (wrong KEK, tampered ciphertext, wrong nonce).
|
|
33
|
+
*/
|
|
34
|
+
export async function unwrapDek(wrapped, kek) {
|
|
35
|
+
if (kek.length !== KEY_BYTES)
|
|
36
|
+
throw new Error('unwrapDek: KEK must be 32 bytes');
|
|
37
|
+
if (wrapped.nonce.length !== NONCE_BYTES)
|
|
38
|
+
throw new Error('unwrapDek: nonce must be 24 bytes');
|
|
39
|
+
const sodium = await loadSodium();
|
|
40
|
+
return sodium.crypto_secretbox_open_easy(wrapped.ciphertext, wrapped.nonce, kek);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Encrypts raw secret bytes with the project's DEK. Each call uses a fresh
|
|
44
|
+
* random nonce; identical plaintexts produce different ciphertexts.
|
|
45
|
+
*
|
|
46
|
+
* The caller owns `plaintext` and must zero it after this function returns.
|
|
47
|
+
*/
|
|
48
|
+
export async function encryptSecretBytes(plaintext, dek) {
|
|
49
|
+
if (dek.length !== KEY_BYTES)
|
|
50
|
+
throw new Error('encryptSecretBytes: DEK must be 32 bytes');
|
|
51
|
+
const sodium = await loadSodium();
|
|
52
|
+
const nonce = sodium.randombytes_buf(NONCE_BYTES);
|
|
53
|
+
const ciphertext = sodium.crypto_secretbox_easy(plaintext, nonce, dek);
|
|
54
|
+
return { ciphertext, nonce };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Decrypts a sealed secret to raw bytes. Throws if authentication fails.
|
|
58
|
+
*
|
|
59
|
+
* The returned buffer contains plaintext. Callers must either zero it in a
|
|
60
|
+
* `finally` block or use `withDecryptedSecretBytes`, which does that for them.
|
|
61
|
+
*/
|
|
62
|
+
export async function decryptSecretBytes(sealed, dek) {
|
|
63
|
+
if (dek.length !== KEY_BYTES)
|
|
64
|
+
throw new Error('decryptSecretBytes: DEK must be 32 bytes');
|
|
65
|
+
if (sealed.nonce.length !== NONCE_BYTES) {
|
|
66
|
+
throw new Error('decryptSecretBytes: nonce must be 24 bytes');
|
|
67
|
+
}
|
|
68
|
+
const sodium = await loadSodium();
|
|
69
|
+
return sodium.crypto_secretbox_open_easy(sealed.ciphertext, sealed.nonce, dek);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Decrypts secret bytes for the duration of a callback and then zeroes the
|
|
73
|
+
* plaintext buffer even when the callback throws.
|
|
74
|
+
*/
|
|
75
|
+
export async function withDecryptedSecretBytes(sealed, dek, usePlaintext) {
|
|
76
|
+
const plaintext = await decryptSecretBytes(sealed, dek);
|
|
77
|
+
try {
|
|
78
|
+
return await usePlaintext(plaintext);
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
zero(plaintext);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Encrypts a UTF-8 string secret value with the project's DEK.
|
|
86
|
+
*
|
|
87
|
+
* This compatibility wrapper zeroes its encoded byte buffer, but the input
|
|
88
|
+
* string itself remains V8-managed and cannot be reliably wiped.
|
|
89
|
+
*/
|
|
90
|
+
export async function encryptSecret(value, dek) {
|
|
91
|
+
const plaintext = new TextEncoder().encode(value);
|
|
92
|
+
try {
|
|
93
|
+
return await encryptSecretBytes(plaintext, dek);
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
zero(plaintext);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Decrypts a sealed secret to a UTF-8 string.
|
|
101
|
+
*
|
|
102
|
+
* This compatibility wrapper zeroes decrypted bytes after decoding, but the
|
|
103
|
+
* returned string is V8-managed and cannot be reliably wiped by callers.
|
|
104
|
+
*/
|
|
105
|
+
export async function decryptSecret(sealed, dek) {
|
|
106
|
+
return withDecryptedSecretBytes(sealed, dek, (plaintext) => new TextDecoder('utf-8', { fatal: true }).decode(plaintext));
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/crypto/envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EACL,SAAS,EACT,WAAW,GAIZ,MAAM,YAAY,CAAC;AAEpB;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,OAAO,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAiB,EAAE,GAAiB;IAChE,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC/E,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IACjE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAmB,EAAE,GAAiB;IACpE,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACjF,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAC/F,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,OAAO,MAAM,CAAC,0BAA0B,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACnF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAAqB,EACrB,GAAiB;IAEjB,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC1F,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,MAAM,CAAC,qBAAqB,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IACvE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC/B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAoB,EACpB,GAAiB;IAEjB,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC1F,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAClC,OAAO,MAAM,CAAC,0BAA0B,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACjF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,MAAoB,EACpB,GAAiB,EACjB,YAAuD;IAEvD,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACxD,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,SAAS,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAa,EAAE,GAAiB;IAClE,MAAM,SAAS,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,OAAO,MAAM,kBAAkB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAClD,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,SAAS,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAoB,EAAE,GAAiB;IACzE,OAAO,wBAAwB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,EAAE,CACzD,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.test.d.ts","sourceRoot":"","sources":["../../src/crypto/envelope.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import fc from 'fast-check';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { KEY_BYTES, NONCE_BYTES, decryptSecret, decryptSecretBytes, encryptSecret, encryptSecretBytes, generateKey, unwrapDek, withDecryptedSecretBytes, wrapDek, } from './index.js';
|
|
4
|
+
describe('generateKey', () => {
|
|
5
|
+
it('produces 32 bytes', async () => {
|
|
6
|
+
const k = await generateKey();
|
|
7
|
+
expect(k).toBeInstanceOf(Uint8Array);
|
|
8
|
+
expect(k.length).toBe(KEY_BYTES);
|
|
9
|
+
});
|
|
10
|
+
it('produces unique keys across calls', async () => {
|
|
11
|
+
const a = await generateKey();
|
|
12
|
+
const b = await generateKey();
|
|
13
|
+
expect(Buffer.from(a).equals(Buffer.from(b))).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
describe('wrapDek / unwrapDek', () => {
|
|
17
|
+
it('round-trips a DEK through a KEK', async () => {
|
|
18
|
+
const kek = await generateKey();
|
|
19
|
+
const dek = await generateKey();
|
|
20
|
+
const wrapped = await wrapDek(dek, kek);
|
|
21
|
+
expect(wrapped.nonce.length).toBe(NONCE_BYTES);
|
|
22
|
+
expect(wrapped.ciphertext.length).toBeGreaterThan(0);
|
|
23
|
+
const unwrapped = await unwrapDek(wrapped, kek);
|
|
24
|
+
expect(Buffer.from(unwrapped).equals(Buffer.from(dek))).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it('produces a different nonce on each wrap', async () => {
|
|
27
|
+
const kek = await generateKey();
|
|
28
|
+
const dek = await generateKey();
|
|
29
|
+
const a = await wrapDek(dek, kek);
|
|
30
|
+
const b = await wrapDek(dek, kek);
|
|
31
|
+
expect(Buffer.from(a.nonce).equals(Buffer.from(b.nonce))).toBe(false);
|
|
32
|
+
expect(Buffer.from(a.ciphertext).equals(Buffer.from(b.ciphertext))).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
it('rejects unwrap with the wrong KEK', async () => {
|
|
35
|
+
const kek = await generateKey();
|
|
36
|
+
const wrongKek = await generateKey();
|
|
37
|
+
const dek = await generateKey();
|
|
38
|
+
const wrapped = await wrapDek(dek, kek);
|
|
39
|
+
await expect(unwrapDek(wrapped, wrongKek)).rejects.toThrow();
|
|
40
|
+
});
|
|
41
|
+
it('rejects unwrap with tampered ciphertext', async () => {
|
|
42
|
+
const kek = await generateKey();
|
|
43
|
+
const dek = await generateKey();
|
|
44
|
+
const wrapped = await wrapDek(dek, kek);
|
|
45
|
+
const tampered = new Uint8Array(wrapped.ciphertext);
|
|
46
|
+
tampered[0] = (tampered[0] ?? 0) ^ 0xff;
|
|
47
|
+
await expect(unwrapDek({ ...wrapped, ciphertext: tampered }, kek)).rejects.toThrow();
|
|
48
|
+
});
|
|
49
|
+
it('rejects unwrap with tampered nonce', async () => {
|
|
50
|
+
const kek = await generateKey();
|
|
51
|
+
const dek = await generateKey();
|
|
52
|
+
const wrapped = await wrapDek(dek, kek);
|
|
53
|
+
const tampered = new Uint8Array(wrapped.nonce);
|
|
54
|
+
tampered[0] = (tampered[0] ?? 0) ^ 0xff;
|
|
55
|
+
await expect(unwrapDek({ ...wrapped, nonce: tampered }, kek)).rejects.toThrow();
|
|
56
|
+
});
|
|
57
|
+
it('throws when called with wrong-length keys', async () => {
|
|
58
|
+
const dek = await generateKey();
|
|
59
|
+
const tooShort = new Uint8Array(16);
|
|
60
|
+
await expect(wrapDek(dek, tooShort)).rejects.toThrow(/32 bytes/);
|
|
61
|
+
await expect(wrapDek(tooShort, dek)).rejects.toThrow(/32 bytes/);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe('encryptSecret / decryptSecret', () => {
|
|
65
|
+
it('round-trips raw byte inputs without requiring a JS string', async () => {
|
|
66
|
+
const dek = await generateKey();
|
|
67
|
+
const value = new Uint8Array([0, 1, 2, 3, 255]);
|
|
68
|
+
const sealed = await encryptSecretBytes(value, dek);
|
|
69
|
+
const plaintext = await decryptSecretBytes(sealed, dek);
|
|
70
|
+
expect(Buffer.from(plaintext).equals(Buffer.from(value))).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
it('zeroes decrypted bytes after the callback completes', async () => {
|
|
73
|
+
const dek = await generateKey();
|
|
74
|
+
const value = new TextEncoder().encode('short-lived secret');
|
|
75
|
+
const sealed = await encryptSecretBytes(value, dek);
|
|
76
|
+
const captured = [];
|
|
77
|
+
const result = await withDecryptedSecretBytes(sealed, dek, (plaintext) => {
|
|
78
|
+
captured.push(plaintext);
|
|
79
|
+
return new TextDecoder('utf-8', { fatal: true }).decode(plaintext);
|
|
80
|
+
});
|
|
81
|
+
expect(result).toBe('short-lived secret');
|
|
82
|
+
const capturedBytes = captured[0];
|
|
83
|
+
expect(capturedBytes).toBeDefined();
|
|
84
|
+
if (!capturedBytes)
|
|
85
|
+
throw new Error('expected decrypted plaintext buffer');
|
|
86
|
+
expect(Array.from(capturedBytes)).toEqual(new Array(capturedBytes.length).fill(0));
|
|
87
|
+
});
|
|
88
|
+
it('zeroes decrypted bytes even when the callback throws', async () => {
|
|
89
|
+
const dek = await generateKey();
|
|
90
|
+
const value = new TextEncoder().encode('throwing secret');
|
|
91
|
+
const sealed = await encryptSecretBytes(value, dek);
|
|
92
|
+
const captured = [];
|
|
93
|
+
await expect(withDecryptedSecretBytes(sealed, dek, (plaintext) => {
|
|
94
|
+
captured.push(plaintext);
|
|
95
|
+
throw new Error('boom');
|
|
96
|
+
})).rejects.toThrow('boom');
|
|
97
|
+
const capturedBytes = captured[0];
|
|
98
|
+
expect(capturedBytes).toBeDefined();
|
|
99
|
+
if (!capturedBytes)
|
|
100
|
+
throw new Error('expected decrypted plaintext buffer');
|
|
101
|
+
expect(Array.from(capturedBytes)).toEqual(new Array(capturedBytes.length).fill(0));
|
|
102
|
+
});
|
|
103
|
+
it('round-trips an ASCII string', async () => {
|
|
104
|
+
const dek = await generateKey();
|
|
105
|
+
const sealed = await encryptSecret('hello world', dek);
|
|
106
|
+
expect(await decryptSecret(sealed, dek)).toBe('hello world');
|
|
107
|
+
});
|
|
108
|
+
it('round-trips a UTF-8 multibyte string', async () => {
|
|
109
|
+
const dek = await generateKey();
|
|
110
|
+
const value = 'şifre 🔑 пароль';
|
|
111
|
+
const sealed = await encryptSecret(value, dek);
|
|
112
|
+
expect(await decryptSecret(sealed, dek)).toBe(value);
|
|
113
|
+
});
|
|
114
|
+
it('round-trips an empty string', async () => {
|
|
115
|
+
const dek = await generateKey();
|
|
116
|
+
const sealed = await encryptSecret('', dek);
|
|
117
|
+
expect(await decryptSecret(sealed, dek)).toBe('');
|
|
118
|
+
});
|
|
119
|
+
it('round-trips a 16 KB value', async () => {
|
|
120
|
+
const dek = await generateKey();
|
|
121
|
+
const value = 'x'.repeat(16 * 1024);
|
|
122
|
+
const sealed = await encryptSecret(value, dek);
|
|
123
|
+
expect(await decryptSecret(sealed, dek)).toBe(value);
|
|
124
|
+
});
|
|
125
|
+
it('produces a fresh nonce per call (CPA-safe)', async () => {
|
|
126
|
+
const dek = await generateKey();
|
|
127
|
+
const a = await encryptSecret('same', dek);
|
|
128
|
+
const b = await encryptSecret('same', dek);
|
|
129
|
+
expect(Buffer.from(a.ciphertext).equals(Buffer.from(b.ciphertext))).toBe(false);
|
|
130
|
+
});
|
|
131
|
+
it('rejects decrypt with the wrong DEK', async () => {
|
|
132
|
+
const dek = await generateKey();
|
|
133
|
+
const wrongDek = await generateKey();
|
|
134
|
+
const sealed = await encryptSecret('secret', dek);
|
|
135
|
+
await expect(decryptSecret(sealed, wrongDek)).rejects.toThrow();
|
|
136
|
+
});
|
|
137
|
+
it('rejects decrypt with tampered ciphertext', async () => {
|
|
138
|
+
const dek = await generateKey();
|
|
139
|
+
const sealed = await encryptSecret('secret', dek);
|
|
140
|
+
const tampered = new Uint8Array(sealed.ciphertext);
|
|
141
|
+
tampered[0] = (tampered[0] ?? 0) ^ 0x01;
|
|
142
|
+
await expect(decryptSecret({ ...sealed, ciphertext: tampered }, dek)).rejects.toThrow();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe('property tests', () => {
|
|
146
|
+
it('every wrap roundtrips for any DEK/KEK pair', async () => {
|
|
147
|
+
await fc.assert(fc.asyncProperty(fc.uint8Array({ minLength: 32, maxLength: 32 }), async (kekBytes) => {
|
|
148
|
+
const kek = new Uint8Array(kekBytes);
|
|
149
|
+
const dek = await generateKey();
|
|
150
|
+
const wrapped = await wrapDek(dek, kek);
|
|
151
|
+
const unwrapped = await unwrapDek(wrapped, kek);
|
|
152
|
+
expect(Buffer.from(unwrapped).equals(Buffer.from(dek))).toBe(true);
|
|
153
|
+
}), { numRuns: 30 });
|
|
154
|
+
});
|
|
155
|
+
it('every encrypt roundtrips for any UTF-8 string', async () => {
|
|
156
|
+
await fc.assert(fc.asyncProperty(fc.string({ maxLength: 1024 }), async (value) => {
|
|
157
|
+
const dek = await generateKey();
|
|
158
|
+
const sealed = await encryptSecret(value, dek);
|
|
159
|
+
expect(await decryptSecret(sealed, dek)).toBe(value);
|
|
160
|
+
}), { numRuns: 50 });
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
//# sourceMappingURL=envelope.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.test.js","sourceRoot":"","sources":["../../src/crypto/envelope.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { SealedSecret, SymmetricKey, WrappedKey } from './types.js';
|
|
2
|
+
export { KEY_BYTES, NONCE_BYTES } from './types.js';
|
|
3
|
+
export { decryptSecret, decryptSecretBytes, encryptSecret, encryptSecretBytes, generateKey, unwrapDek, withDecryptedSecretBytes, wrapDek, } from './envelope.js';
|
|
4
|
+
export { zero } from './sodium.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,wBAAwB,EACxB,OAAO,GACR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { KEY_BYTES, NONCE_BYTES } from './types.js';
|
|
2
|
+
export { decryptSecret, decryptSecretBytes, encryptSecret, encryptSecretBytes, generateKey, unwrapDek, withDecryptedSecretBytes, wrapDek, } from './envelope.js';
|
|
3
|
+
export { zero } from './sodium.js';
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,wBAAwB,EACxB,OAAO,GACR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface Sodium {
|
|
2
|
+
ready: Promise<void>;
|
|
3
|
+
randombytes_buf(length: number): Uint8Array;
|
|
4
|
+
crypto_secretbox_easy(message: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array;
|
|
5
|
+
crypto_secretbox_open_easy(ciphertext: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array;
|
|
6
|
+
memzero(buf: Uint8Array): void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Returns a fully-initialized libsodium handle. Calling sites must `await`
|
|
10
|
+
* this before using any crypto primitive — libsodium loads its WASM
|
|
11
|
+
* module asynchronously.
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadSodium(): Promise<Sodium>;
|
|
14
|
+
/**
|
|
15
|
+
* Best-effort zeroing of a sensitive buffer. Falls back to a JS-side
|
|
16
|
+
* fill when libsodium's `memzero` is unavailable (it always is in WASM
|
|
17
|
+
* builds, but documenting the fallback explicitly).
|
|
18
|
+
*/
|
|
19
|
+
export declare function zero(buf: Uint8Array): void;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=sodium.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sodium.d.ts","sourceRoot":"","sources":["../../src/crypto/sodium.ts"],"names":[],"mappings":"AAMA,UAAU,MAAM;IACd,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACrB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC;IAC5C,qBAAqB,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,GAAG,UAAU,CAAC;IAC3F,0BAA0B,CACxB,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,UAAU,GACd,UAAU,CAAC;IACd,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;CAChC;AAmBD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAK5C;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAM1C"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// libsodium-wrappers ships an ESM build whose internal `import 'libsodium'`
|
|
2
|
+
// trips up some bundlers; loading via createRequire keeps the module path
|
|
3
|
+
// stable across Node, Bun, and tsx.
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
const moduleRequire = createRequire(import.meta.url);
|
|
7
|
+
function loadSodiumModule() {
|
|
8
|
+
try {
|
|
9
|
+
return moduleRequire('libsodium-wrappers');
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
// Next standalone can preserve workspace-absolute module origins, so fall
|
|
13
|
+
// back to resolving from the runtime app root where copied dependencies live.
|
|
14
|
+
const runtimeRequire = createRequire(join(process.cwd(), 'package.json'));
|
|
15
|
+
return runtimeRequire('libsodium-wrappers');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const sodium = loadSodiumModule();
|
|
19
|
+
let readyPromise = null;
|
|
20
|
+
/**
|
|
21
|
+
* Returns a fully-initialized libsodium handle. Calling sites must `await`
|
|
22
|
+
* this before using any crypto primitive — libsodium loads its WASM
|
|
23
|
+
* module asynchronously.
|
|
24
|
+
*/
|
|
25
|
+
export function loadSodium() {
|
|
26
|
+
if (!readyPromise) {
|
|
27
|
+
readyPromise = sodium.ready.then(() => sodium);
|
|
28
|
+
}
|
|
29
|
+
return readyPromise;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Best-effort zeroing of a sensitive buffer. Falls back to a JS-side
|
|
33
|
+
* fill when libsodium's `memzero` is unavailable (it always is in WASM
|
|
34
|
+
* builds, but documenting the fallback explicitly).
|
|
35
|
+
*/
|
|
36
|
+
export function zero(buf) {
|
|
37
|
+
if (typeof sodium.memzero === 'function') {
|
|
38
|
+
sodium.memzero(buf);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
buf.fill(0);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=sodium.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sodium.js","sourceRoot":"","sources":["../../src/crypto/sodium.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,0EAA0E;AAC1E,oCAAoC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAcjC,MAAM,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAErD,SAAS,gBAAgB;IACvB,IAAI,CAAC;QACH,OAAO,aAAa,CAAC,oBAAoB,CAAW,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,8EAA8E;QAC9E,MAAM,cAAc,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;QAC1E,OAAO,cAAc,CAAC,oBAAoB,CAAW,CAAC;IACxD,CAAC;AACH,CAAC;AAED,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;AAElC,IAAI,YAAY,GAA2B,IAAI,CAAC;AAEhD;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,GAAe;IAClC,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpB,OAAO;IACT,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A 32-byte symmetric key. Used for both KEKs (master key) and DEKs
|
|
3
|
+
* (per-project data-encryption keys).
|
|
4
|
+
*
|
|
5
|
+
* Always wrap real key material in a `Uint8Array` rather than a string —
|
|
6
|
+
* strings are immutable and cannot be reliably zeroed.
|
|
7
|
+
*/
|
|
8
|
+
export type SymmetricKey = Uint8Array;
|
|
9
|
+
/**
|
|
10
|
+
* A wrapped (encrypted) DEK. Produced by `wrapDek(dek, kek)` and stored
|
|
11
|
+
* in the `projects.dek_wrapped` column. Without the KEK that wrapped it,
|
|
12
|
+
* the contents are unrecoverable.
|
|
13
|
+
*/
|
|
14
|
+
export interface WrappedKey {
|
|
15
|
+
readonly ciphertext: Uint8Array;
|
|
16
|
+
readonly nonce: Uint8Array;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* An encrypted secret value. Produced by `encryptSecretBytes(value, dek)` or
|
|
20
|
+
* the string compatibility wrapper `encryptSecret(value, dek)`, and stored in
|
|
21
|
+
* the `secrets.ciphertext` / `secrets.nonce` columns.
|
|
22
|
+
*/
|
|
23
|
+
export interface SealedSecret {
|
|
24
|
+
readonly ciphertext: Uint8Array;
|
|
25
|
+
readonly nonce: Uint8Array;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Symmetric-key length used by libsodium's `crypto_secretbox`
|
|
29
|
+
* (XSalsa20-Poly1305).
|
|
30
|
+
*/
|
|
31
|
+
export declare const KEY_BYTES = 32;
|
|
32
|
+
/**
|
|
33
|
+
* Nonce length for `crypto_secretbox`. Each encryption draws a fresh
|
|
34
|
+
* random nonce of this length.
|
|
35
|
+
*/
|
|
36
|
+
export declare const NONCE_BYTES = 24;
|
|
37
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/crypto/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC;AAEtC;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED;;;GAGG;AACH,eAAO,MAAM,SAAS,KAAK,CAAC;AAE5B;;;GAGG;AACH,eAAO,MAAM,WAAW,KAAK,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symmetric-key length used by libsodium's `crypto_secretbox`
|
|
3
|
+
* (XSalsa20-Poly1305).
|
|
4
|
+
*/
|
|
5
|
+
export const KEY_BYTES = 32;
|
|
6
|
+
/**
|
|
7
|
+
* Nonce length for `crypto_secretbox`. Each encryption draws a fresh
|
|
8
|
+
* random nonce of this length.
|
|
9
|
+
*/
|
|
10
|
+
export const NONCE_BYTES = 24;
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/crypto/types.ts"],"names":[],"mappings":"AA6BA;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC;AAE5B;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAC1C,OAAO,KAAK,UAAU,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reference/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EACL,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,UAAU,GACX,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reference/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EACL,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,UAAU,GACX,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser-property.test.d.ts","sourceRoot":"","sources":["../../src/reference/parser-property.test.ts"],"names":[],"mappings":""}
|