@agentdock/crypto 0.0.47 → 0.0.48

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 CHANGED
@@ -66,7 +66,7 @@ const result = await authChallenge(seed: Uint8Array);
66
66
  const valid = await verifyChallenge(challenge, signature, publicKey);
67
67
  ```
68
68
 
69
- **注意**:直接使用 seed 作为 Ed25519 种子,不做额外 deriveKey(与 Happy 对齐,见 L23)。
69
+ **注意**:直接使用 seed 作为 Ed25519 种子,不做额外 deriveKey
70
70
 
71
71
  ### NaCl Box (box.ts)
72
72
 
@@ -99,7 +99,7 @@ const plaintext = decryptSecretBox(bundle, secret);
99
99
  import { deriveSecretKeyTreeRoot, deriveSecretKeyTreeChild, deriveKey } from '@agentdock/crypto';
100
100
 
101
101
  // 从根密钥 + 标签派生子密钥
102
- const root = await deriveSecretKeyTreeRoot(masterSecret, 'Happy EnCoder');
102
+ const root = await deriveSecretKeyTreeRoot(masterSecret, 'my-app');
103
103
  const child = await deriveSecretKeyTreeChild(root, 'content');
104
104
 
105
105
  // 底层:HKDF-SHA512 派生
@@ -111,7 +111,7 @@ const key = await deriveKey(secret, label, segments);
111
111
  ```typescript
112
112
  import { deriveContentKeyPair } from '@agentdock/crypto';
113
113
 
114
- // 'Happy EnCoder' + ['content'] + SHA-512[0:32] → NaCl Box keypair
114
+ // domainSeparation + ['content'] + SHA-512[0:32] → NaCl Box keypair
115
115
  const { publicKey, secretKey } = await deriveContentKeyPair(secret);
116
116
  ```
117
117
 
@@ -142,5 +142,5 @@ pnpm --filter @agentdock/crypto test:coverage
142
142
 
143
143
  - **Web Crypto API 优先**:AES-GCM、HKDF、HMAC 全走 `crypto.subtle`,不引入额外依赖
144
144
  - **tweetnacl 用于 NaCl**:Box/SecretBox 使用 tweetnacl,因为 Web Crypto 不支持 X25519 Box
145
- - **密钥派生路径与 Happy 完全一致**:确保两端互操作(L23 教训)
145
+ - **密钥派生路径确定性**:确保两端互操作
146
146
  - **TypeScript `as BufferSource` 断言**:TS 5.7 的 Uint8Array 类型不兼容 Web Crypto(L7 教训)
package/dist/aes.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AES-256-GCM encryption and decryption using the Web Crypto API.
3
3
  *
4
- * Bundle format (compatible with Happy protocol):
4
+ * Bundle format:
5
5
  * version (1 byte) | nonce (12 bytes) | ciphertext + authTag
6
6
  *
7
7
  * - version: always 0 for this implementation
package/dist/auth.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Ed25519 authentication challenge — aligned with Happy.
2
+ * Ed25519 authentication challenge.
3
3
  *
4
4
  * Uses tweetnacl for Ed25519 signing/verification, which works in
5
5
  * ALL contexts (including non-secure HTTP). The raw 32-byte seed is
6
6
  * used directly as the Ed25519 private key seed, WITHOUT any extra
7
- * key derivation step, matching Happy's tweetnacl.sign.keyPair.fromSeed().
7
+ * key derivation step.
8
8
  *
9
9
  * Previous implementation used Web Crypto API (crypto.subtle) which
10
10
  * requires a secure context (HTTPS or localhost). This broke mobile
@@ -24,7 +24,7 @@ export type AuthChallengeResult = {
24
24
  * derived from the given seed.
25
25
  *
26
26
  * The seed is used directly as the Ed25519 private key seed (no extra
27
- * key derivation), matching Happy's tweetnacl.sign.keyPair.fromSeed().
27
+ * key derivation).
28
28
  *
29
29
  * @param seed - 32-byte seed for deterministic Ed25519 key pair
30
30
  * @returns Challenge result with random nonce, public key, and signature
package/dist/box.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * NaCl Box encryption — aligned with Happy.
2
+ * NaCl Box encryption.
3
3
  *
4
4
  * Ephemeral X25519 Diffie-Hellman key agreement + authenticated encryption.
5
5
  * Used for encrypting data for a specific recipient (key delivery).
package/dist/content.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  /**
2
- * Content keypair derivation — aligned with Happy.
2
+ * Content keypair derivation.
3
3
  *
4
4
  * Derives an X25519 NaCl Box keypair from a secret using the key tree.
5
- * Usage string: 'Happy EnCoder', path: ['content'].
6
5
  *
7
6
  * The derived seed is SHA-512 hashed and the first 32 bytes become the
8
7
  * Box secret key, matching libsodium's crypto_box_seed_keypair behavior.
@@ -10,8 +9,7 @@
10
9
  /**
11
10
  * Derive a NaCl Box keypair for content encryption.
12
11
  *
13
- * Follows Happy's deriveContentKeyPair():
14
- * 1. deriveKey(secret, 'Happy EnCoder', ['content']) → 32-byte seed
12
+ * 1. deriveKey(secret, usage, path) → 32-byte seed
15
13
  * 2. SHA-512(seed)[0:32] → box secret key (matching libsodium)
16
14
  * 3. tweetnacl.box.keyPair.fromSecretKey(boxSecretKey) → keypair
17
15
  *
@@ -23,7 +21,7 @@
23
21
  * @param secret - Master secret for key derivation
24
22
  * @returns NaCl Box keypair { publicKey, secretKey }
25
23
  */
26
- export declare function deriveContentKeyPair(secret: Uint8Array): Promise<{
24
+ export declare function deriveContentKeyPair(secret: Uint8Array, derivationVersion?: number): Promise<{
27
25
  readonly publicKey: Uint8Array;
28
26
  readonly secretKey: Uint8Array;
29
27
  }>;
package/dist/content.js CHANGED
@@ -1 +1 @@
1
- "use strict";import o from"tweetnacl";import{deriveKey as c}from"./keys.js";export async function deriveContentKeyPair(r){const t=await c(r,"Happy EnCoder",["content"]),n=await crypto.subtle.digest("SHA-512",t),i=new Uint8Array(n).slice(0,32),e=o.box.keyPair.fromSecretKey(i);return{publicKey:new Uint8Array(e.publicKey),secretKey:new Uint8Array(e.secretKey)}}
1
+ "use strict";import c from"tweetnacl";import{deriveKey as i}from"./keys.js";export async function deriveContentKeyPair(r,t){const n=await i(r,t===1?"CCPark EnCoder":"Happy EnCoder",["content"]),o=await crypto.subtle.digest("SHA-512",n),a=new Uint8Array(o).slice(0,32),e=c.box.keyPair.fromSecretKey(a);return{publicKey:new Uint8Array(e.publicKey),secretKey:new Uint8Array(e.secretKey)}}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * NaCl SecretBox encryption — aligned with Happy.
2
+ * NaCl SecretBox encryption.
3
3
  *
4
4
  * Symmetric authenticated encryption (XSalsa20-Poly1305).
5
5
  * Used for legacy encryption mode.
package/dist/session.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Session encryption — high-level API composing AES-GCM + NaCl Box.
3
3
  *
4
4
  * Provides per-session data encryption key (DEK) generation, wrapping,
5
- * unwrapping, and envelope encrypt/decrypt. Compatible with Happy protocol.
5
+ * unwrapping, and envelope encrypt/decrypt.
6
6
  *
7
7
  * Key flow:
8
8
  * masterSecret → deriveContentKeyPair → contentPublicKey
@@ -20,7 +20,7 @@
20
20
  * @param masterSecret - 32-byte master secret shared between daemon and web
21
21
  * @returns DEK (for local use) and wrappedDekBase64 (for server storage)
22
22
  */
23
- export declare function generateSessionKeys(masterSecret: Uint8Array): Promise<{
23
+ export declare function generateSessionKeys(masterSecret: Uint8Array, derivationVersion?: number): Promise<{
24
24
  readonly dek: Uint8Array;
25
25
  readonly wrappedDekBase64: string;
26
26
  }>;
@@ -36,7 +36,7 @@ export declare function generateSessionKeys(masterSecret: Uint8Array): Promise<{
36
36
  * @param masterSecret - Same master secret used during generation
37
37
  * @returns 32-byte DEK, or null if unwrapping fails
38
38
  */
39
- export declare function unwrapSessionKey(wrappedDekBase64: string, masterSecret: Uint8Array): Promise<Uint8Array | null>;
39
+ export declare function unwrapSessionKey(wrappedDekBase64: string, masterSecret: Uint8Array, derivationVersion?: number): Promise<Uint8Array | null>;
40
40
  /**
41
41
  * Encrypt a SessionEnvelope (or any JSON-serializable value) for transmission.
42
42
  *
package/dist/session.js CHANGED
@@ -1 +1 @@
1
- "use strict";import{encryptAesGcm as i,decryptAesGcm as y}from"./aes.js";import{encryptBox as d,decryptBox as f}from"./box.js";import{deriveContentKeyPair as l}from"./content.js";import{getRandomBytes as m}from"./random.js";import{encodeBase64 as u,decodeBase64 as p}from"./encoding.js";const a=0,s=32,E=57+s;export async function generateSessionKeys(n){const{publicKey:t}=await l(n),e=m(s),o=d(e,t),r=new Uint8Array(1+o.length);return r[0]=a,r.set(o,1),{dek:e,wrappedDekBase64:u(r)}}export async function unwrapSessionKey(n,t){let e;try{e=p(n)}catch{return null}if(e.length<E||e[0]!==a)return null;const o=e.slice(1),{secretKey:r}=await l(t),c=f(o,r);return!c||c.length!==s?null:c}export async function encryptEnvelope(n,t){const e=await i(n,t);return u(e)}export async function decryptEnvelope(n,t){let e;try{e=p(n)}catch{return null}return e.length===0?null:y(e,t)}
1
+ "use strict";import{encryptAesGcm as y,decryptAesGcm as d}from"./aes.js";import{encryptBox as f,decryptBox as m}from"./box.js";import{deriveContentKeyPair as u}from"./content.js";import{getRandomBytes as E}from"./random.js";import{encodeBase64 as p,decodeBase64 as a}from"./encoding.js";const i=0,l=32,w=57+l;export async function generateSessionKeys(n,t){const{publicKey:e}=await u(n,t),r=E(l),c=f(r,e),o=new Uint8Array(1+c.length);return o[0]=i,o.set(c,1),{dek:r,wrappedDekBase64:p(o)}}export async function unwrapSessionKey(n,t,e){let r;try{r=a(n)}catch{return null}if(r.length<w||r[0]!==i)return null;const c=r.slice(1),{secretKey:o}=await u(t,e),s=m(c,o);return!s||s.length!==l?null:s}export async function encryptEnvelope(n,t){const e=await y(n,t);return p(e)}export async function decryptEnvelope(n,t){let e;try{e=a(n)}catch{return null}return e.length===0?null:d(e,t)}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@agentdock/crypto",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "description": "E2E encryption for AgentDock — AES-256-GCM, key derivation, Web Crypto API",
5
5
  "license": "UNLICENSED",
6
- "author": "kevin8536945",
6
+ "author": "CCPark",
7
7
  "type": "module",
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "tweetnacl": "^1.0.3",
26
- "@agentdock/wire": "0.0.47"
26
+ "@agentdock/wire": "0.0.48"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@vitest/coverage-v8": "^3.0.0",