@getmyenv/crypto 0.2.0 → 0.4.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/dist/backup.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import type { BackupContext, BackupValue, EncryptedBackupEnvelope, WrappedProjectKey } from "./types.js";
2
- import { encryptSecret, decryptSecret } from "./envelope.js";
1
+ import type { BackupContext, BackupValue, EncryptedBackupEnvelope, WrappedPrivateKey } from "./types.js";
3
2
  export declare function createBackupEnvelope(input: {
4
3
  projectName: string;
5
- wrappedProjectKey: WrappedProjectKey;
4
+ publicKey: string;
5
+ wrappedPrivateKey: WrappedPrivateKey;
6
6
  contexts: BackupContext[];
7
7
  keys: string[];
8
8
  tags?: Record<string, string>;
@@ -10,6 +10,11 @@ export declare function createBackupEnvelope(input: {
10
10
  }): EncryptedBackupEnvelope;
11
11
  export declare function serializeBackup(envelope: EncryptedBackupEnvelope): string;
12
12
  export declare function parseBackup(raw: string): EncryptedBackupEnvelope;
13
+ /**
14
+ * Open every context key in a backup with the Vault password it was made with.
15
+ * Keyed by context slug. Caller wipes the returned keys when done.
16
+ */
17
+ export declare function openBackupKeys(vaultPassword: string, envelope: EncryptedBackupEnvelope): Promise<Map<string, Uint8Array>>;
13
18
  /**
14
19
  * Decrypt every value in a backup with the Vault password.
15
20
  * Works without getmyenv being reachable.
@@ -24,5 +29,3 @@ export declare function restoreValuesFromBackup(vaultPassword: string, envelope:
24
29
  expiresAt: string | null;
25
30
  }>;
26
31
  }>;
27
- export { encryptSecret, decryptSecret };
28
- //# sourceMappingURL=backup.d.ts.map
package/dist/backup.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BACKUP_FORMAT_VERSION } from "./types.js";
2
- import { encryptSecret, decryptSecret, unwrapProjectKey } from "./envelope.js";
2
+ import { decryptSecret, openSealedKey, parseSealedKey, parseWrappedKey, publicKeyFromPrivate, unwrapPrivateKey, wipe, } from "./envelope.js";
3
3
  export function createBackupEnvelope(input) {
4
4
  const hasTags = input.tags && Object.keys(input.tags).length > 0;
5
5
  return {
@@ -7,7 +7,8 @@ export function createBackupEnvelope(input) {
7
7
  version: BACKUP_FORMAT_VERSION,
8
8
  createdAt: new Date().toISOString(),
9
9
  projectName: input.projectName,
10
- wrappedProjectKey: input.wrappedProjectKey,
10
+ publicKey: input.publicKey,
11
+ wrappedPrivateKey: input.wrappedPrivateKey,
11
12
  contexts: input.contexts,
12
13
  keys: input.keys,
13
14
  ...(hasTags ? { tags: input.tags } : {}),
@@ -25,24 +26,68 @@ export function parseBackup(raw) {
25
26
  if (parsed.version !== BACKUP_FORMAT_VERSION) {
26
27
  throw new Error(`Unsupported backup version: ${String(parsed.version)}`);
27
28
  }
29
+ if (typeof parsed.projectName !== "string" ||
30
+ typeof parsed.publicKey !== "string" ||
31
+ !Array.isArray(parsed.contexts) ||
32
+ !Array.isArray(parsed.keys) ||
33
+ !Array.isArray(parsed.values)) {
34
+ throw new Error("Invalid backup file");
35
+ }
36
+ parseWrappedKey(JSON.stringify(parsed.wrappedPrivateKey));
37
+ for (const c of parsed.contexts) {
38
+ if (!Number.isInteger(c.id) || typeof c.slug !== "string") {
39
+ throw new Error("Invalid backup file");
40
+ }
41
+ if (c.sealedKey !== null)
42
+ parseSealedKey(JSON.stringify(c.sealedKey));
43
+ }
28
44
  return parsed;
29
45
  }
46
+ /**
47
+ * Open every context key in a backup with the Vault password it was made with.
48
+ * Keyed by context slug. Caller wipes the returned keys when done.
49
+ */
50
+ export async function openBackupKeys(vaultPassword, envelope) {
51
+ const privateKey = await unwrapPrivateKey(vaultPassword, envelope.wrappedPrivateKey);
52
+ try {
53
+ if (publicKeyFromPrivate(privateKey) !== envelope.publicKey) {
54
+ throw new Error("Backup key mismatch");
55
+ }
56
+ const keys = new Map();
57
+ for (const c of envelope.contexts) {
58
+ if (c.sealedKey)
59
+ keys.set(c.slug, openSealedKey(c.sealedKey, privateKey, c.id));
60
+ }
61
+ return keys;
62
+ }
63
+ finally {
64
+ wipe(privateKey);
65
+ }
66
+ }
30
67
  /**
31
68
  * Decrypt every value in a backup with the Vault password.
32
69
  * Works without getmyenv being reachable.
33
70
  */
34
71
  export async function restoreValuesFromBackup(vaultPassword, envelope) {
35
- const pek = await unwrapProjectKey(vaultPassword, envelope.wrappedProjectKey);
36
- return {
37
- contexts: envelope.contexts,
38
- keys: envelope.keys,
39
- values: envelope.values.map((v) => ({
40
- key: v.key,
41
- context: v.context,
42
- value: decryptSecret(pek, v.payload),
43
- expiresAt: v.expiresAt,
44
- })),
45
- };
72
+ const contextKeys = await openBackupKeys(vaultPassword, envelope);
73
+ try {
74
+ return {
75
+ contexts: envelope.contexts,
76
+ keys: envelope.keys,
77
+ values: envelope.values.map((v) => {
78
+ const key = contextKeys.get(v.context);
79
+ if (!key)
80
+ throw new Error(`Backup has no key for context ${v.context}`);
81
+ return {
82
+ key: v.key,
83
+ context: v.context,
84
+ value: decryptSecret(key, v.key, v.payload),
85
+ expiresAt: v.expiresAt,
86
+ };
87
+ }),
88
+ };
89
+ }
90
+ finally {
91
+ wipe(...contextKeys.values());
92
+ }
46
93
  }
47
- export { encryptSecret, decryptSecret };
48
- //# sourceMappingURL=backup.js.map
package/dist/bytes.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export declare function bytesToBase64(bytes: Uint8Array): string;
2
2
  export declare function base64ToBytes(b64: string): Uint8Array;
3
+ export declare function bytesToBase64Url(bytes: Uint8Array): string;
4
+ export declare function base64UrlToBytes(b64url: string): Uint8Array;
3
5
  export declare function getRandomBytes(length: number): Uint8Array;
4
6
  export declare function utf8Encode(text: string): Uint8Array;
5
7
  export declare function utf8Decode(bytes: Uint8Array): string;
6
- export declare function concatBytes(...parts: Uint8Array[]): Uint8Array;
7
- //# sourceMappingURL=bytes.d.ts.map
package/dist/bytes.js CHANGED
@@ -19,6 +19,13 @@ export function base64ToBytes(b64) {
19
19
  }
20
20
  return bytes;
21
21
  }
22
+ export function bytesToBase64Url(bytes) {
23
+ return bytesToBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
24
+ }
25
+ export function base64UrlToBytes(b64url) {
26
+ const b64 = b64url.replace(/-/g, "+").replace(/_/g, "/");
27
+ return base64ToBytes(b64 + "=".repeat((4 - (b64.length % 4)) % 4));
28
+ }
22
29
  export function getRandomBytes(length) {
23
30
  const bytes = new Uint8Array(length);
24
31
  if (typeof globalThis.crypto?.getRandomValues === "function") {
@@ -33,14 +40,3 @@ export function utf8Encode(text) {
33
40
  export function utf8Decode(bytes) {
34
41
  return new TextDecoder().decode(bytes);
35
42
  }
36
- export function concatBytes(...parts) {
37
- const total = parts.reduce((n, p) => n + p.length, 0);
38
- const out = new Uint8Array(total);
39
- let offset = 0;
40
- for (const part of parts) {
41
- out.set(part, offset);
42
- offset += part.length;
43
- }
44
- return out;
45
- }
46
- //# sourceMappingURL=bytes.js.map
@@ -1,30 +1,49 @@
1
- import { type EncryptedSecretPayload, type WrappedProjectKey } from "./types.js";
1
+ import { type EncryptedSecretPayload, type SealedKey, type WrappedPrivateKey } from "./types.js";
2
+ /** Overwrite key material in place. */
3
+ export declare function wipe(...buffers: Array<Uint8Array | null | undefined>): void;
4
+ /** A fresh X25519 keypair. Used for server tokens and guest projects. */
5
+ export declare function generateKeypair(): {
6
+ publicKey: string;
7
+ privateKey: Uint8Array;
8
+ };
9
+ export declare function publicKeyFromPrivate(privateKey: Uint8Array): string;
2
10
  /**
3
- * Create a new project encryption key and wrap it with a password-derived KEK.
11
+ * Short, comparable form of a public key: the first 10 bytes of its SHA-256,
12
+ * as five groups of four hex digits. Two people compare it out of band.
4
13
  */
5
- export declare function createWrappedProjectKey(vaultPassword: string): Promise<{
6
- pek: Uint8Array;
7
- wrapped: WrappedProjectKey;
14
+ export declare function publicKeyFingerprint(publicKey: string): string;
15
+ /** Wrap an X25519 private key with a key derived from a password. */
16
+ export declare function wrapPrivateKey(password: string, privateKey: Uint8Array): Promise<WrappedPrivateKey>;
17
+ /** Throws when the password is wrong or the blob was changed. */
18
+ export declare function unwrapPrivateKey(password: string, wrapped: WrappedPrivateKey): Promise<Uint8Array>;
19
+ /** New user keypair, wrapped with the Vault password. */
20
+ export declare function createUserKeys(password: string): Promise<{
21
+ publicKey: string;
22
+ privateKey: Uint8Array;
23
+ wrapped: WrappedPrivateKey;
8
24
  }>;
9
- /**
10
- * Unwrap (decrypt) the project encryption key using the vault password.
11
- */
12
- export declare function unwrapProjectKey(vaultPassword: string, wrapped: WrappedProjectKey): Promise<Uint8Array>;
13
- /**
14
- * Change vault password: unwrap PEK with old password, rewrap with new.
15
- * Secret ciphertext does NOT need to be re-encrypted.
16
- */
17
- export declare function rewrapProjectKey(oldPassword: string, newPassword: string, wrapped: WrappedProjectKey): Promise<WrappedProjectKey>;
18
- /**
19
- * Encrypt a secret value with the project encryption key.
20
- */
21
- export declare function encryptSecret(pek: Uint8Array, plaintext: string): EncryptedSecretPayload;
22
- /**
23
- * Decrypt a secret value with the project encryption key.
24
- */
25
- export declare function decryptSecret(pek: Uint8Array, payload: EncryptedSecretPayload): string;
25
+ /** Change the Vault password. Context keys and values stay the same. */
26
+ export declare function rewrapPrivateKey(oldPassword: string, newPassword: string, wrapped: WrappedPrivateKey): Promise<WrappedPrivateKey>;
27
+ /** Seal a context key to one recipient. Bound to the context id and recipient key. */
28
+ export declare function sealContextKey(contextKey: Uint8Array, recipientPublicKey: string, contextId: number): SealedKey;
29
+ /** Open a sealed context key with the recipient's private key. */
30
+ export declare function openSealedKey(sealed: SealedKey, privateKey: Uint8Array, contextId: number): Uint8Array;
31
+ /** Encrypt a value with its context key. Bound to the variable name. */
32
+ export declare function encryptSecret(contextKey: Uint8Array, name: string, plaintext: string): EncryptedSecretPayload;
33
+ /** Throws when the key is wrong, the name differs, or the payload was changed. */
34
+ export declare function decryptSecret(contextKey: Uint8Array, name: string, payload: EncryptedSecretPayload): string;
26
35
  export declare function serializePayload(payload: EncryptedSecretPayload): string;
27
36
  export declare function parsePayload(raw: string): EncryptedSecretPayload;
28
- export declare function serializeWrappedKey(wrapped: WrappedProjectKey): string;
29
- export declare function parseWrappedKey(raw: string): WrappedProjectKey;
30
- //# sourceMappingURL=envelope.d.ts.map
37
+ export declare function serializeWrappedKey(wrapped: WrappedPrivateKey): string;
38
+ export declare function parseWrappedKey(raw: string): WrappedPrivateKey;
39
+ export declare function serializeSealedKey(sealed: SealedKey): string;
40
+ export declare function parseSealedKey(raw: string): SealedKey;
41
+ /**
42
+ * Server tokens carry their own private key after the dot. Only the part
43
+ * before the dot is sent to the server.
44
+ */
45
+ export declare function joinServerToken(authPart: string, privateKey: Uint8Array): string;
46
+ export declare function splitServerToken(token: string): {
47
+ authPart: string;
48
+ privateKey: Uint8Array | null;
49
+ };
package/dist/envelope.js CHANGED
@@ -1,72 +1,159 @@
1
1
  import { gcm } from "@noble/ciphers/aes.js";
2
- import { ALGORITHM, CRYPTO_FORMAT_VERSION, DEFAULT_KDF_PARAMS, KDF, } from "./types.js";
3
- import { base64ToBytes, bytesToBase64, getRandomBytes, utf8Decode, utf8Encode, } from "./bytes.js";
4
- import { deriveKek, generateProjectKey, generateSalt } from "./kdf.js";
2
+ import { x25519 } from "@noble/curves/ed25519.js";
3
+ import { hkdf } from "@noble/hashes/hkdf.js";
4
+ import { sha256 } from "@noble/hashes/sha2.js";
5
+ import { ALGORITHM, CRYPTO_FORMAT_VERSION, DEFAULT_KDF_PARAMS, KDF, SEAL, } from "./types.js";
6
+ import { base64ToBytes, base64UrlToBytes, bytesToBase64, bytesToBase64Url, getRandomBytes, utf8Decode, utf8Encode, } from "./bytes.js";
7
+ import { assertKdfParams, deriveKek, generateSalt } from "./kdf.js";
5
8
  const NONCE_LENGTH = 12;
6
- function aesGcmEncrypt(key, plaintext) {
9
+ const KEY_LENGTH = 32;
10
+ const AAD_USER_KEY = "getmyenv:v2:userkey";
11
+ const HKDF_INFO_SEAL = "getmyenv:v2:seal";
12
+ /** Overwrite key material in place. */
13
+ export function wipe(...buffers) {
14
+ for (const b of buffers)
15
+ b?.fill(0);
16
+ }
17
+ function aesGcmEncrypt(key, plaintext, aad) {
7
18
  const nonce = getRandomBytes(NONCE_LENGTH);
8
- const aes = gcm(key, nonce);
9
- const ciphertext = aes.encrypt(plaintext);
19
+ const ciphertext = gcm(key, nonce, utf8Encode(aad)).encrypt(plaintext);
10
20
  return { nonce, ciphertext };
11
21
  }
12
- function aesGcmDecrypt(key, nonce, ciphertext) {
13
- const aes = gcm(key, nonce);
14
- return aes.decrypt(ciphertext);
22
+ function aesGcmDecrypt(key, nonce, ciphertext, aad) {
23
+ return gcm(key, nonce, utf8Encode(aad)).decrypt(ciphertext);
24
+ }
25
+ function assertKey(key) {
26
+ if (key.length !== KEY_LENGTH)
27
+ throw new Error("Invalid key length");
28
+ }
29
+ /** A fresh X25519 keypair. Used for server tokens and guest projects. */
30
+ export function generateKeypair() {
31
+ const privateKey = x25519.utils.randomSecretKey();
32
+ return { publicKey: publicKeyFromPrivate(privateKey), privateKey };
33
+ }
34
+ export function publicKeyFromPrivate(privateKey) {
35
+ assertKey(privateKey);
36
+ return bytesToBase64(x25519.getPublicKey(privateKey));
15
37
  }
16
38
  /**
17
- * Create a new project encryption key and wrap it with a password-derived KEK.
39
+ * Short, comparable form of a public key: the first 10 bytes of its SHA-256,
40
+ * as five groups of four hex digits. Two people compare it out of band.
18
41
  */
19
- export async function createWrappedProjectKey(vaultPassword) {
42
+ export function publicKeyFingerprint(publicKey) {
43
+ const bytes = base64ToBytes(publicKey);
44
+ assertKey(bytes);
45
+ const hex = Array.from(sha256(bytes).subarray(0, 10), (b) => b.toString(16).padStart(2, "0")).join("");
46
+ return hex.toUpperCase().match(/.{4}/g).join(" ");
47
+ }
48
+ /** Wrap an X25519 private key with a key derived from a password. */
49
+ export async function wrapPrivateKey(password, privateKey) {
50
+ assertKey(privateKey);
20
51
  const salt = generateSalt();
21
- const kek = await deriveKek(vaultPassword, salt);
22
- const pek = generateProjectKey();
23
- const { nonce, ciphertext } = aesGcmEncrypt(kek, pek);
24
- const wrapped = {
25
- version: CRYPTO_FORMAT_VERSION,
26
- salt: bytesToBase64(salt),
27
- wrappedKey: bytesToBase64(ciphertext),
28
- wrappedKeyNonce: bytesToBase64(nonce),
29
- kdf: KDF,
30
- kdfParams: { ...DEFAULT_KDF_PARAMS },
31
- };
32
- return { pek, wrapped };
52
+ const kek = await deriveKek(password, salt);
53
+ try {
54
+ const { nonce, ciphertext } = aesGcmEncrypt(kek, privateKey, AAD_USER_KEY);
55
+ return {
56
+ version: CRYPTO_FORMAT_VERSION,
57
+ kdf: KDF,
58
+ kdfParams: { ...DEFAULT_KDF_PARAMS },
59
+ salt: bytesToBase64(salt),
60
+ nonce: bytesToBase64(nonce),
61
+ ciphertext: bytesToBase64(ciphertext),
62
+ };
63
+ }
64
+ finally {
65
+ wipe(kek);
66
+ }
33
67
  }
34
- /**
35
- * Unwrap (decrypt) the project encryption key using the vault password.
36
- */
37
- export async function unwrapProjectKey(vaultPassword, wrapped) {
38
- if (wrapped.version !== CRYPTO_FORMAT_VERSION) {
39
- throw new Error(`Unsupported wrapped key version: ${wrapped.version}`);
68
+ /** Throws when the password is wrong or the blob was changed. */
69
+ export async function unwrapPrivateKey(password, wrapped) {
70
+ if (wrapped.version !== CRYPTO_FORMAT_VERSION || wrapped.kdf !== KDF) {
71
+ throw new Error("Unsupported wrapped key");
72
+ }
73
+ assertKdfParams(wrapped.kdfParams);
74
+ const kek = await deriveKek(password, base64ToBytes(wrapped.salt), wrapped.kdfParams);
75
+ try {
76
+ const key = aesGcmDecrypt(kek, base64ToBytes(wrapped.nonce), base64ToBytes(wrapped.ciphertext), AAD_USER_KEY);
77
+ assertKey(key);
78
+ return key;
79
+ }
80
+ finally {
81
+ wipe(kek);
40
82
  }
41
- const salt = base64ToBytes(wrapped.salt);
42
- const kek = await deriveKek(vaultPassword, salt, wrapped.kdfParams);
43
- const nonce = base64ToBytes(wrapped.wrappedKeyNonce);
44
- const ciphertext = base64ToBytes(wrapped.wrappedKey);
45
- return aesGcmDecrypt(kek, nonce, ciphertext);
46
83
  }
47
- /**
48
- * Change vault password: unwrap PEK with old password, rewrap with new.
49
- * Secret ciphertext does NOT need to be re-encrypted.
50
- */
51
- export async function rewrapProjectKey(oldPassword, newPassword, wrapped) {
52
- const pek = await unwrapProjectKey(oldPassword, wrapped);
53
- const salt = generateSalt();
54
- const kek = await deriveKek(newPassword, salt);
55
- const { nonce, ciphertext } = aesGcmEncrypt(kek, pek);
56
- return {
57
- version: CRYPTO_FORMAT_VERSION,
58
- salt: bytesToBase64(salt),
59
- wrappedKey: bytesToBase64(ciphertext),
60
- wrappedKeyNonce: bytesToBase64(nonce),
61
- kdf: KDF,
62
- kdfParams: { ...DEFAULT_KDF_PARAMS },
63
- };
84
+ /** New user keypair, wrapped with the Vault password. */
85
+ export async function createUserKeys(password) {
86
+ const { publicKey, privateKey } = generateKeypair();
87
+ const wrapped = await wrapPrivateKey(password, privateKey);
88
+ return { publicKey, privateKey, wrapped };
64
89
  }
65
- /**
66
- * Encrypt a secret value with the project encryption key.
67
- */
68
- export function encryptSecret(pek, plaintext) {
69
- const { nonce, ciphertext } = aesGcmEncrypt(pek, utf8Encode(plaintext));
90
+ /** Change the Vault password. Context keys and values stay the same. */
91
+ export async function rewrapPrivateKey(oldPassword, newPassword, wrapped) {
92
+ const privateKey = await unwrapPrivateKey(oldPassword, wrapped);
93
+ try {
94
+ return await wrapPrivateKey(newPassword, privateKey);
95
+ }
96
+ finally {
97
+ wipe(privateKey);
98
+ }
99
+ }
100
+ function sealAad(contextId, recipientPublicKey) {
101
+ return `getmyenv:v2:ctxkey:${contextId}:${recipientPublicKey}`;
102
+ }
103
+ function sealKek(shared, ephemeralPublicKey, recipientPublicKey) {
104
+ const salt = new Uint8Array(ephemeralPublicKey.length + recipientPublicKey.length);
105
+ salt.set(ephemeralPublicKey, 0);
106
+ salt.set(recipientPublicKey, ephemeralPublicKey.length);
107
+ return hkdf(sha256, shared, salt, utf8Encode(HKDF_INFO_SEAL), KEY_LENGTH);
108
+ }
109
+ /** Seal a context key to one recipient. Bound to the context id and recipient key. */
110
+ export function sealContextKey(contextKey, recipientPublicKey, contextId) {
111
+ assertKey(contextKey);
112
+ const recipient = base64ToBytes(recipientPublicKey);
113
+ const ephemeralPrivate = x25519.utils.randomSecretKey();
114
+ const ephemeralPublic = x25519.getPublicKey(ephemeralPrivate);
115
+ const shared = x25519.getSharedSecret(ephemeralPrivate, recipient);
116
+ const kek = sealKek(shared, ephemeralPublic, recipient);
117
+ try {
118
+ const { nonce, ciphertext } = aesGcmEncrypt(kek, contextKey, sealAad(contextId, recipientPublicKey));
119
+ return {
120
+ version: CRYPTO_FORMAT_VERSION,
121
+ algorithm: SEAL,
122
+ ephemeralPublicKey: bytesToBase64(ephemeralPublic),
123
+ nonce: bytesToBase64(nonce),
124
+ ciphertext: bytesToBase64(ciphertext),
125
+ };
126
+ }
127
+ finally {
128
+ wipe(ephemeralPrivate, shared, kek);
129
+ }
130
+ }
131
+ /** Open a sealed context key with the recipient's private key. */
132
+ export function openSealedKey(sealed, privateKey, contextId) {
133
+ if (sealed.version !== CRYPTO_FORMAT_VERSION || sealed.algorithm !== SEAL) {
134
+ throw new Error("Unsupported sealed key");
135
+ }
136
+ const recipientPublicKey = publicKeyFromPrivate(privateKey);
137
+ const recipient = base64ToBytes(recipientPublicKey);
138
+ const ephemeralPublic = base64ToBytes(sealed.ephemeralPublicKey);
139
+ const shared = x25519.getSharedSecret(privateKey, ephemeralPublic);
140
+ const kek = sealKek(shared, ephemeralPublic, recipient);
141
+ try {
142
+ const key = aesGcmDecrypt(kek, base64ToBytes(sealed.nonce), base64ToBytes(sealed.ciphertext), sealAad(contextId, recipientPublicKey));
143
+ assertKey(key);
144
+ return key;
145
+ }
146
+ finally {
147
+ wipe(shared, kek);
148
+ }
149
+ }
150
+ function secretAad(name) {
151
+ return `getmyenv:v2:secret:${name}`;
152
+ }
153
+ /** Encrypt a value with its context key. Bound to the variable name. */
154
+ export function encryptSecret(contextKey, name, plaintext) {
155
+ assertKey(contextKey);
156
+ const { nonce, ciphertext } = aesGcmEncrypt(contextKey, utf8Encode(plaintext), secretAad(name));
70
157
  return {
71
158
  version: CRYPTO_FORMAT_VERSION,
72
159
  algorithm: ALGORITHM,
@@ -74,37 +161,80 @@ export function encryptSecret(pek, plaintext) {
74
161
  ciphertext: bytesToBase64(ciphertext),
75
162
  };
76
163
  }
77
- /**
78
- * Decrypt a secret value with the project encryption key.
79
- */
80
- export function decryptSecret(pek, payload) {
81
- if (payload.version !== CRYPTO_FORMAT_VERSION) {
82
- throw new Error(`Unsupported secret payload version: ${payload.version}`);
164
+ /** Throws when the key is wrong, the name differs, or the payload was changed. */
165
+ export function decryptSecret(contextKey, name, payload) {
166
+ if (payload.version !== CRYPTO_FORMAT_VERSION || payload.algorithm !== ALGORITHM) {
167
+ throw new Error("Unsupported secret payload");
168
+ }
169
+ return utf8Decode(aesGcmDecrypt(contextKey, base64ToBytes(payload.nonce), base64ToBytes(payload.ciphertext), secretAad(name)));
170
+ }
171
+ function parseJsonObject(raw, what) {
172
+ let parsed;
173
+ try {
174
+ parsed = JSON.parse(raw);
83
175
  }
84
- if (payload.algorithm !== ALGORITHM) {
85
- throw new Error(`Unsupported algorithm: ${payload.algorithm}`);
176
+ catch {
177
+ throw new Error(`Invalid ${what}`);
86
178
  }
87
- const plaintext = aesGcmDecrypt(pek, base64ToBytes(payload.nonce), base64ToBytes(payload.ciphertext));
88
- return utf8Decode(plaintext);
179
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
180
+ throw new Error(`Invalid ${what}`);
181
+ }
182
+ return parsed;
183
+ }
184
+ function hasStrings(o, keys) {
185
+ return keys.every((k) => typeof o[k] === "string" && o[k].length > 0);
89
186
  }
90
187
  export function serializePayload(payload) {
91
188
  return JSON.stringify(payload);
92
189
  }
93
190
  export function parsePayload(raw) {
94
- const parsed = JSON.parse(raw);
95
- if (parsed.version !== CRYPTO_FORMAT_VERSION || !parsed.nonce || !parsed.ciphertext) {
191
+ const o = parseJsonObject(raw, "encrypted secret payload");
192
+ if (o.version !== CRYPTO_FORMAT_VERSION ||
193
+ o.algorithm !== ALGORITHM ||
194
+ !hasStrings(o, ["nonce", "ciphertext"])) {
96
195
  throw new Error("Invalid encrypted secret payload");
97
196
  }
98
- return parsed;
197
+ return o;
99
198
  }
100
199
  export function serializeWrappedKey(wrapped) {
101
200
  return JSON.stringify(wrapped);
102
201
  }
103
202
  export function parseWrappedKey(raw) {
104
- const parsed = JSON.parse(raw);
105
- if (parsed.version !== CRYPTO_FORMAT_VERSION || !parsed.wrappedKey || !parsed.salt) {
106
- throw new Error("Invalid wrapped project key");
203
+ const o = parseJsonObject(raw, "wrapped key");
204
+ if (o.version !== CRYPTO_FORMAT_VERSION ||
205
+ o.kdf !== KDF ||
206
+ !hasStrings(o, ["salt", "nonce", "ciphertext"]) ||
207
+ !o.kdfParams ||
208
+ typeof o.kdfParams !== "object") {
209
+ throw new Error("Invalid wrapped key");
107
210
  }
108
- return parsed;
211
+ assertKdfParams(o.kdfParams);
212
+ return o;
213
+ }
214
+ export function serializeSealedKey(sealed) {
215
+ return JSON.stringify(sealed);
216
+ }
217
+ export function parseSealedKey(raw) {
218
+ const o = parseJsonObject(raw, "sealed key");
219
+ if (o.version !== CRYPTO_FORMAT_VERSION ||
220
+ o.algorithm !== SEAL ||
221
+ !hasStrings(o, ["ephemeralPublicKey", "nonce", "ciphertext"])) {
222
+ throw new Error("Invalid sealed key");
223
+ }
224
+ return o;
225
+ }
226
+ /**
227
+ * Server tokens carry their own private key after the dot. Only the part
228
+ * before the dot is sent to the server.
229
+ */
230
+ export function joinServerToken(authPart, privateKey) {
231
+ return `${authPart}.${bytesToBase64Url(privateKey)}`;
232
+ }
233
+ export function splitServerToken(token) {
234
+ const dot = token.indexOf(".");
235
+ if (dot < 0)
236
+ return { authPart: token, privateKey: null };
237
+ const privateKey = base64UrlToBytes(token.slice(dot + 1));
238
+ assertKey(privateKey);
239
+ return { authPart: token.slice(0, dot), privateKey };
109
240
  }
110
- //# sourceMappingURL=envelope.js.map
@@ -9,4 +9,3 @@ export type MachineKeypair = {
9
9
  export declare function generateMachineIdentity(): MachineKeypair;
10
10
  export declare function signAccessRequest(privateKeyB64: string, message: string): string;
11
11
  export declare function verifyAccessRequest(publicKeyB64: string, message: string, signatureB64: string): boolean;
12
- //# sourceMappingURL=identity.d.ts.map
package/dist/identity.js CHANGED
@@ -21,4 +21,3 @@ export function verifyAccessRequest(publicKeyB64, message, signatureB64) {
21
21
  return false;
22
22
  }
23
23
  }
24
- //# sourceMappingURL=identity.js.map
package/dist/index.d.ts CHANGED
@@ -4,4 +4,3 @@ export * from "./kdf.js";
4
4
  export * from "./envelope.js";
5
5
  export * from "./backup.js";
6
6
  export * from "./identity.js";
7
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -4,4 +4,3 @@ export * from "./kdf.js";
4
4
  export * from "./envelope.js";
5
5
  export * from "./backup.js";
6
6
  export * from "./identity.js";
7
- //# sourceMappingURL=index.js.map
package/dist/kdf.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { type KdfParams } from "./types.js";
2
+ /** Throw when Argon2id parameters are outside KDF_BOUNDS. */
3
+ export declare function assertKdfParams(params: KdfParams): void;
2
4
  /**
3
- * Derive a Key Encryption Key (KEK) from a vault password using Argon2id.
5
+ * Derive a Key Encryption Key (KEK) from a Vault password using Argon2id.
4
6
  */
5
7
  export declare function deriveKek(password: string, salt: Uint8Array, params?: KdfParams): Promise<Uint8Array>;
6
8
  export declare function generateSalt(length?: number): Uint8Array;
7
- export declare function generateProjectKey(): Uint8Array;
8
- export declare function saltToBase64(salt: Uint8Array): string;
9
- //# sourceMappingURL=kdf.d.ts.map
9
+ /** A random 32-byte key for one context. */
10
+ export declare function generateContextKey(): Uint8Array;
package/dist/kdf.js CHANGED
@@ -1,10 +1,21 @@
1
1
  import { argon2id } from "hash-wasm";
2
- import { DEFAULT_KDF_PARAMS, } from "./types.js";
3
- import { bytesToBase64, getRandomBytes } from "./bytes.js";
2
+ import { DEFAULT_KDF_PARAMS, KDF_BOUNDS } from "./types.js";
3
+ import { getRandomBytes } from "./bytes.js";
4
+ /** Throw when Argon2id parameters are outside KDF_BOUNDS. */
5
+ export function assertKdfParams(params) {
6
+ const inRange = (v, r) => Number.isInteger(v) && v >= r.min && v <= r.max;
7
+ if (!inRange(params.memory, KDF_BOUNDS.memory) ||
8
+ !inRange(params.iterations, KDF_BOUNDS.iterations) ||
9
+ !inRange(params.parallelism, KDF_BOUNDS.parallelism) ||
10
+ params.hashLength !== KDF_BOUNDS.hashLength) {
11
+ throw new Error("Unsupported key derivation parameters");
12
+ }
13
+ }
4
14
  /**
5
- * Derive a Key Encryption Key (KEK) from a vault password using Argon2id.
15
+ * Derive a Key Encryption Key (KEK) from a Vault password using Argon2id.
6
16
  */
7
17
  export async function deriveKek(password, salt, params = DEFAULT_KDF_PARAMS) {
18
+ assertKdfParams(params);
8
19
  const hash = await argon2id({
9
20
  password,
10
21
  salt,
@@ -19,10 +30,7 @@ export async function deriveKek(password, salt, params = DEFAULT_KDF_PARAMS) {
19
30
  export function generateSalt(length = 16) {
20
31
  return getRandomBytes(length);
21
32
  }
22
- export function generateProjectKey() {
33
+ /** A random 32-byte key for one context. */
34
+ export function generateContextKey() {
23
35
  return getRandomBytes(32);
24
36
  }
25
- export function saltToBase64(salt) {
26
- return bytesToBase64(salt);
27
- }
28
- //# sourceMappingURL=kdf.js.map
package/dist/types.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- /** Versioned getmyenv crypto protocol - shared by browser and CLI. */
2
- export declare const CRYPTO_FORMAT_VERSION: 1;
1
+ /** Versioned getmyenv crypto protocol, shared by browser and CLI. */
2
+ export declare const CRYPTO_FORMAT_VERSION: 2;
3
3
  export declare const ALGORITHM: "AES-256-GCM";
4
4
  export declare const KDF: "argon2id";
5
+ export declare const SEAL: "X25519-HKDF-SHA256-AES-256-GCM";
5
6
  /** Argon2id parameters (balanced for browser + CLI). */
6
7
  export declare const DEFAULT_KDF_PARAMS: {
7
8
  readonly memory: number;
@@ -9,20 +10,47 @@ export declare const DEFAULT_KDF_PARAMS: {
9
10
  readonly parallelism: 1;
10
11
  readonly hashLength: 32;
11
12
  };
13
+ /** Accepted Argon2id bounds. Weaker or client-crashing parameters are refused. */
14
+ export declare const KDF_BOUNDS: {
15
+ readonly memory: {
16
+ readonly min: 19456;
17
+ readonly max: 1048576;
18
+ };
19
+ readonly iterations: {
20
+ readonly min: 2;
21
+ readonly max: 10;
22
+ };
23
+ readonly parallelism: {
24
+ readonly min: 1;
25
+ readonly max: 4;
26
+ };
27
+ readonly hashLength: 32;
28
+ };
12
29
  export type KdfParams = {
13
30
  memory: number;
14
31
  iterations: number;
15
32
  parallelism: number;
16
33
  hashLength: number;
17
34
  };
18
- /** Wrapped project encryption key (stored server-side / in backups). */
19
- export type WrappedProjectKey = {
35
+ /**
36
+ * A user's X25519 private key wrapped with a key derived from the Vault password.
37
+ * Stored on the server, useless without the password.
38
+ */
39
+ export type WrappedPrivateKey = {
20
40
  version: typeof CRYPTO_FORMAT_VERSION;
21
- salt: string;
22
- wrappedKey: string;
23
- wrappedKeyNonce: string;
24
41
  kdf: typeof KDF;
25
42
  kdfParams: KdfParams;
43
+ salt: string;
44
+ nonce: string;
45
+ ciphertext: string;
46
+ };
47
+ /** A context key sealed to one recipient's X25519 public key. */
48
+ export type SealedKey = {
49
+ version: typeof CRYPTO_FORMAT_VERSION;
50
+ algorithm: typeof SEAL;
51
+ ephemeralPublicKey: string;
52
+ nonce: string;
53
+ ciphertext: string;
26
54
  };
27
55
  /** Encrypted secret value payload. */
28
56
  export type EncryptedSecretPayload = {
@@ -31,11 +59,15 @@ export type EncryptedSecretPayload = {
31
59
  nonce: string;
32
60
  ciphertext: string;
33
61
  };
34
- export declare const BACKUP_FORMAT_VERSION: 2;
62
+ export declare const BACKUP_FORMAT_VERSION: 3;
35
63
  export type BackupContext = {
64
+ /** Context id when the backup was made. Part of the sealed key's binding. */
65
+ id: number;
36
66
  slug: string;
37
67
  name: string;
38
68
  protection: "open" | "locked";
69
+ /** Context key sealed to the backup's public key. Null when the context had no key yet. */
70
+ sealedKey: SealedKey | null;
39
71
  };
40
72
  export type BackupValue = {
41
73
  key: string;
@@ -44,13 +76,17 @@ export type BackupValue = {
44
76
  expiresAt: string | null;
45
77
  payload: EncryptedSecretPayload;
46
78
  };
47
- /** Portable encrypted backup envelope. */
79
+ /**
80
+ * Portable encrypted backup. Opens with the Vault password that was set when
81
+ * it was made: it carries the wrapped private key and the context keys sealed to it.
82
+ */
48
83
  export type EncryptedBackupEnvelope = {
49
84
  format: "getmyenv-backup";
50
85
  version: typeof BACKUP_FORMAT_VERSION;
51
86
  createdAt: string;
52
87
  projectName: string;
53
- wrappedProjectKey: WrappedProjectKey;
88
+ publicKey: string;
89
+ wrappedPrivateKey: WrappedPrivateKey;
54
90
  contexts: BackupContext[];
55
91
  /** Every variable name in the project, including ones with no values. */
56
92
  keys: string[];
@@ -58,4 +94,3 @@ export type EncryptedBackupEnvelope = {
58
94
  tags?: Record<string, string>;
59
95
  values: BackupValue[];
60
96
  };
61
- //# sourceMappingURL=types.d.ts.map
package/dist/types.js CHANGED
@@ -1,7 +1,8 @@
1
- /** Versioned getmyenv crypto protocol - shared by browser and CLI. */
2
- export const CRYPTO_FORMAT_VERSION = 1;
1
+ /** Versioned getmyenv crypto protocol, shared by browser and CLI. */
2
+ export const CRYPTO_FORMAT_VERSION = 2;
3
3
  export const ALGORITHM = "AES-256-GCM";
4
4
  export const KDF = "argon2id";
5
+ export const SEAL = "X25519-HKDF-SHA256-AES-256-GCM";
5
6
  /** Argon2id parameters (balanced for browser + CLI). */
6
7
  export const DEFAULT_KDF_PARAMS = {
7
8
  memory: 64 * 1024, // KiB
@@ -9,5 +10,11 @@ export const DEFAULT_KDF_PARAMS = {
9
10
  parallelism: 1,
10
11
  hashLength: 32,
11
12
  };
12
- export const BACKUP_FORMAT_VERSION = 2;
13
- //# sourceMappingURL=types.js.map
13
+ /** Accepted Argon2id bounds. Weaker or client-crashing parameters are refused. */
14
+ export const KDF_BOUNDS = {
15
+ memory: { min: 19_456, max: 1_048_576 },
16
+ iterations: { min: 2, max: 10 },
17
+ parallelism: { min: 1, max: 4 },
18
+ hashLength: 32,
19
+ };
20
+ export const BACKUP_FORMAT_VERSION = 3;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@getmyenv/crypto",
3
- "version": "0.2.0",
4
- "description": "Envelope encryption for getmyenv (Argon2id + AES-256-GCM)",
3
+ "version": "0.4.0",
4
+ "description": "Encryption for getmyenv: Argon2id-wrapped X25519 keys, sealed per-context keys, AES-256-GCM values",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -1 +0,0 @@
1
- {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,WAAW,EACX,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAoB,MAAM,eAAe,CAAC;AAE/E,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB,GAAG,uBAAuB,CAa1B;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,uBAAuB,GAAG,MAAM,CAEzE;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,CAShE;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,uBAAuB,GAChC,OAAO,CAAC;IACT,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,KAAK,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;KAC1B,CAAC,CAAC;CACJ,CAAC,CAYD;AAED,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"backup.js","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE/E,MAAM,UAAU,oBAAoB,CAAC,KAOpC;IACC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IACjE,OAAO;QACL,MAAM,EAAE,iBAAiB;QACzB,OAAO,EAAE,qBAAqB;QAC9B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAiC;IAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4C,CAAC;IAC1E,IAAI,MAAM,CAAC,MAAM,KAAK,iBAAiB,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,MAAM,CAAC,OAAO,KAAK,qBAAqB,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,+BAA+B,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,MAAiC,CAAC;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,aAAqB,EACrB,QAAiC;IAWjC,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,aAAa,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAC9E,OAAO;QACL,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAClC,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,KAAK,EAAE,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC;YACpC,SAAS,EAAE,CAAC,CAAC,SAAS;SACvB,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"bytes.d.ts","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CASvD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAUrD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAOzD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEnD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEpD;AAED,wBAAgB,WAAW,CAAC,GAAG,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,CAS9D"}
package/dist/bytes.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"bytes.js","sourceRoot":"","sources":["../src/bytes.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,OAAO,UAAU,CAAC,MAAM,EAAE,eAAe,KAAK,UAAU,EAAE,CAAC;QAC7D,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAG,KAAmB;IAChD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACtB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;IACxB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AA+BpB;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,CAAC,CAgB1D;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,UAAU,CAAC,CASrB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAa5B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,MAAM,GAChB,sBAAsB,CAQxB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,sBAAsB,GAC9B,MAAM,CAaR;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,CAExE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,sBAAsB,CAMhE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAEtE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAM9D"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,uBAAuB,IAAI,cAAc,CAOxD;AAED,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GACd,MAAM,CAIR;AAED,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAUT"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAWtF,MAAM,UAAU,uBAAuB;IACrC,MAAM,UAAU,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;IACnD,OAAO;QACL,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC;QACnC,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,aAAqB,EACrB,OAAe;IAEf,MAAM,UAAU,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;IAC1D,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,YAAoB,EACpB,OAAe,EACf,YAAoB;IAEpB,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,MAAM,CACnB,aAAa,CAAC,YAAY,CAAC,EAC3B,UAAU,CAAC,OAAO,CAAC,EACnB,aAAa,CAAC,YAAY,CAAC,CAC5B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC"}
package/dist/kdf.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"kdf.d.ts","sourceRoot":"","sources":["../src/kdf.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,YAAY,CAAC;AAGpB;;GAEG;AACH,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,SAA8B,GACrC,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED,wBAAgB,YAAY,CAAC,MAAM,SAAK,GAAG,UAAU,CAEpD;AAED,wBAAgB,kBAAkB,IAAI,UAAU,CAE/C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAErD"}
package/dist/kdf.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"kdf.js","sourceRoot":"","sources":["../src/kdf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EACL,kBAAkB,GAEnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE3D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,QAAgB,EAChB,IAAgB,EAChB,SAAoB,kBAAkB;IAEtC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC;QAC1B,QAAQ;QACR,IAAI;QACJ,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,UAAU,EAAE,MAAM,CAAC,MAAM;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,UAAU,EAAE,QAAQ;KACrB,CAAC,CAAC;IACH,OAAO,IAAI,YAAY,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAM,GAAG,EAAE;IACtC,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,cAAc,CAAC,EAAE,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAgB;IAC3C,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,eAAO,MAAM,qBAAqB,EAAG,CAAU,CAAC;AAChD,eAAO,MAAM,SAAS,EAAG,aAAsB,CAAC;AAChD,eAAO,MAAM,GAAG,EAAG,UAAmB,CAAC;AAEvC,wDAAwD;AACxD,eAAO,MAAM,kBAAkB;;;;;CAKrB,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,OAAO,qBAAqB,CAAC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,EAAE,OAAO,GAAG,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF,sCAAsC;AACtC,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,OAAO,qBAAqB,CAAC;IACtC,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAG,CAAU,CAAC;AAEhD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,sBAAsB,CAAC;CACjC,CAAC;AAEF,0CAA0C;AAC1C,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,OAAO,qBAAqB,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,yEAAyE;IACzE,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB,CAAC"}
package/dist/types.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAU,CAAC;AAChD,MAAM,CAAC,MAAM,SAAS,GAAG,aAAsB,CAAC;AAChD,MAAM,CAAC,MAAM,GAAG,GAAG,UAAmB,CAAC;AAEvC,wDAAwD;AACxD,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM;IACzB,UAAU,EAAE,CAAC;IACb,WAAW,EAAE,CAAC;IACd,UAAU,EAAE,EAAE;CACN,CAAC;AA2BX,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAU,CAAC"}