ehbp 0.0.6 → 0.1.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/LICENSE +22 -0
- package/README.md +158 -0
- package/dist/cjs/client.d.ts +13 -13
- package/dist/cjs/client.d.ts.map +1 -1
- package/dist/cjs/client.js +39 -50
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/derive.d.ts +63 -0
- package/dist/cjs/derive.d.ts.map +1 -0
- package/dist/cjs/derive.js +136 -0
- package/dist/cjs/derive.js.map +1 -0
- package/dist/cjs/identity.d.ts +37 -10
- package/dist/cjs/identity.d.ts.map +1 -1
- package/dist/cjs/identity.js +169 -150
- package/dist/cjs/identity.js.map +1 -1
- package/dist/cjs/index.d.ts +4 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +15 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/protocol.d.ts +1 -1
- package/dist/cjs/protocol.js +2 -2
- package/dist/cjs/protocol.js.map +1 -1
- package/dist/esm/client.d.ts +13 -13
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +39 -50
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/derive.d.ts +63 -0
- package/dist/esm/derive.d.ts.map +1 -0
- package/dist/esm/derive.js +127 -0
- package/dist/esm/derive.js.map +1 -0
- package/dist/esm/identity.d.ts +37 -10
- package/dist/esm/identity.d.ts.map +1 -1
- package/dist/esm/identity.js +169 -150
- package/dist/esm/identity.js.map +1 -1
- package/dist/esm/index.d.ts +4 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/protocol.d.ts +1 -1
- package/dist/esm/protocol.js +2 -2
- package/dist/esm/protocol.js.map +1 -1
- package/dist/esm/test/client.test.js +15 -16
- package/dist/esm/test/client.test.js.map +1 -1
- package/dist/esm/test/derive.test.d.ts +2 -0
- package/dist/esm/test/derive.test.d.ts.map +1 -0
- package/dist/esm/test/derive.test.js +164 -0
- package/dist/esm/test/derive.test.js.map +1 -0
- package/dist/esm/test/security.test.d.ts +10 -0
- package/dist/esm/test/security.test.d.ts.map +1 -0
- package/dist/esm/test/security.test.js +153 -0
- package/dist/esm/test/security.test.js.map +1 -0
- package/dist/esm/test/streaming.integration.d.ts +9 -0
- package/dist/esm/test/streaming.integration.d.ts.map +1 -0
- package/dist/esm/test/streaming.integration.js +190 -0
- package/dist/esm/test/streaming.integration.js.map +1 -0
- package/package.json +6 -7
- package/dist/esm/example.d.ts +0 -6
- package/dist/esm/example.d.ts.map +0 -1
- package/dist/esm/example.js +0 -115
- package/dist/esm/example.js.map +0 -1
- package/dist/esm/streaming-test.d.ts +0 -3
- package/dist/esm/streaming-test.d.ts.map +0 -1
- package/dist/esm/streaming-test.js +0 -102
- package/dist/esm/streaming-test.js.map +0 -1
package/dist/esm/identity.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import { CipherSuite,
|
|
1
|
+
import { CipherSuite, KEM_DHKEM_X25519_HKDF_SHA256, KDF_HKDF_SHA256, AEAD_AES_256_GCM, } from 'hpke';
|
|
2
2
|
import { PROTOCOL, HPKE_CONFIG } from './protocol.js';
|
|
3
|
+
import { deriveResponseKeys, decryptChunk, hexToBytes, bytesToHex, HPKE_REQUEST_INFO, EXPORT_LABEL, EXPORT_LENGTH, RESPONSE_NONCE_LENGTH, } from './derive.js';
|
|
4
|
+
/**
|
|
5
|
+
* Creates a new CipherSuite for X25519/HKDF-SHA256/AES-256-GCM
|
|
6
|
+
*/
|
|
7
|
+
function createSuite() {
|
|
8
|
+
return new CipherSuite(KEM_DHKEM_X25519_HKDF_SHA256, KDF_HKDF_SHA256, AEAD_AES_256_GCM);
|
|
9
|
+
}
|
|
3
10
|
/**
|
|
4
11
|
* Identity class for managing HPKE key pairs and encryption/decryption
|
|
5
12
|
*/
|
|
@@ -16,48 +23,34 @@ export class Identity {
|
|
|
16
23
|
* Generate a new identity with X25519 key pair
|
|
17
24
|
*/
|
|
18
25
|
static async generate() {
|
|
19
|
-
const suite =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
aead: new Aes256Gcm()
|
|
23
|
-
});
|
|
24
|
-
const { publicKey, privateKey } = await suite.kem.generateKeyPair();
|
|
25
|
-
// Make sure the public key is extractable for serialization
|
|
26
|
-
const extractablePublicKey = await crypto.subtle.importKey('raw', await crypto.subtle.exportKey('raw', publicKey), { name: 'X25519' }, true, // extractable
|
|
27
|
-
[]);
|
|
28
|
-
return new Identity(suite, extractablePublicKey, privateKey);
|
|
26
|
+
const suite = createSuite();
|
|
27
|
+
const { publicKey, privateKey } = await suite.GenerateKeyPair(true); // extractable
|
|
28
|
+
return new Identity(suite, publicKey, privateKey);
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* Create identity from JSON string
|
|
32
32
|
*/
|
|
33
33
|
static async fromJSON(json) {
|
|
34
34
|
const data = JSON.parse(json);
|
|
35
|
-
const suite =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
});
|
|
40
|
-
// Import public key
|
|
41
|
-
const publicKey = await crypto.subtle.importKey('raw', new Uint8Array(data.publicKey), { name: 'X25519' }, true, // extractable
|
|
42
|
-
[]);
|
|
43
|
-
// Deserialize private key using HPKE library
|
|
44
|
-
const privateKey = await suite.kem.deserializePrivateKey(new Uint8Array(data.privateKey).buffer);
|
|
35
|
+
const suite = createSuite();
|
|
36
|
+
// Deserialize keys using the suite
|
|
37
|
+
const publicKey = await suite.DeserializePublicKey(new Uint8Array(data.publicKey));
|
|
38
|
+
const privateKey = await suite.DeserializePrivateKey(new Uint8Array(data.privateKey), true);
|
|
45
39
|
return new Identity(suite, publicKey, privateKey);
|
|
46
40
|
}
|
|
47
41
|
/**
|
|
48
42
|
* Convert identity to JSON string
|
|
49
43
|
*/
|
|
50
44
|
async toJSON() {
|
|
51
|
-
const publicKeyBytes =
|
|
52
|
-
|
|
53
|
-
const privateKeyBytes = await this.suite.kem.serializePrivateKey(this.privateKey);
|
|
45
|
+
const publicKeyBytes = await this.suite.SerializePublicKey(this.publicKey);
|
|
46
|
+
const privateKeyBytes = await this.suite.SerializePrivateKey(this.privateKey);
|
|
54
47
|
return JSON.stringify({
|
|
55
48
|
publicKey: Array.from(publicKeyBytes),
|
|
56
|
-
privateKey: Array.from(
|
|
49
|
+
privateKey: Array.from(privateKeyBytes),
|
|
57
50
|
});
|
|
58
51
|
}
|
|
59
52
|
/**
|
|
60
|
-
* Get public key
|
|
53
|
+
* Get public key
|
|
61
54
|
*/
|
|
62
55
|
getPublicKey() {
|
|
63
56
|
return this.publicKey;
|
|
@@ -66,13 +59,11 @@ export class Identity {
|
|
|
66
59
|
* Get public key as hex string
|
|
67
60
|
*/
|
|
68
61
|
async getPublicKeyHex() {
|
|
69
|
-
const exported = await
|
|
70
|
-
return
|
|
71
|
-
.map(b => b.toString(16).padStart(2, '0'))
|
|
72
|
-
.join('');
|
|
62
|
+
const exported = await this.suite.SerializePublicKey(this.publicKey);
|
|
63
|
+
return bytesToHex(exported);
|
|
73
64
|
}
|
|
74
65
|
/**
|
|
75
|
-
* Get private key
|
|
66
|
+
* Get private key
|
|
76
67
|
*/
|
|
77
68
|
getPrivateKey() {
|
|
78
69
|
return this.privateKey;
|
|
@@ -86,7 +77,7 @@ export class Identity {
|
|
|
86
77
|
const kdfId = HPKE_CONFIG.KDF;
|
|
87
78
|
const aeadId = HPKE_CONFIG.AEAD;
|
|
88
79
|
// Export public key as raw bytes
|
|
89
|
-
const publicKeyBytes =
|
|
80
|
+
const publicKeyBytes = await this.suite.SerializePublicKey(this.publicKey);
|
|
90
81
|
// Key ID (1 byte) + KEM ID (2 bytes) + Public Key + Cipher Suites
|
|
91
82
|
const keyId = 0;
|
|
92
83
|
const publicKeySize = publicKeyBytes.length;
|
|
@@ -96,20 +87,20 @@ export class Identity {
|
|
|
96
87
|
// Key ID
|
|
97
88
|
buffer[offset++] = keyId;
|
|
98
89
|
// KEM ID
|
|
99
|
-
buffer[offset++] = (kemId >> 8) &
|
|
100
|
-
buffer[offset++] = kemId &
|
|
90
|
+
buffer[offset++] = (kemId >> 8) & 0xff;
|
|
91
|
+
buffer[offset++] = kemId & 0xff;
|
|
101
92
|
// Public Key
|
|
102
93
|
buffer.set(publicKeyBytes, offset);
|
|
103
94
|
offset += publicKeySize;
|
|
104
95
|
// Cipher Suites Length (2 bytes)
|
|
105
|
-
buffer[offset++] = (cipherSuitesSize >> 8) &
|
|
106
|
-
buffer[offset++] = cipherSuitesSize &
|
|
96
|
+
buffer[offset++] = (cipherSuitesSize >> 8) & 0xff;
|
|
97
|
+
buffer[offset++] = cipherSuitesSize & 0xff;
|
|
107
98
|
// KDF ID
|
|
108
|
-
buffer[offset++] = (kdfId >> 8) &
|
|
109
|
-
buffer[offset++] = kdfId &
|
|
99
|
+
buffer[offset++] = (kdfId >> 8) & 0xff;
|
|
100
|
+
buffer[offset++] = kdfId & 0xff;
|
|
110
101
|
// AEAD ID
|
|
111
|
-
buffer[offset++] = (aeadId >> 8) &
|
|
112
|
-
buffer[offset++] = aeadId &
|
|
102
|
+
buffer[offset++] = (aeadId >> 8) & 0xff;
|
|
103
|
+
buffer[offset++] = aeadId & 0xff;
|
|
113
104
|
return buffer;
|
|
114
105
|
}
|
|
115
106
|
/**
|
|
@@ -127,144 +118,172 @@ export class Identity {
|
|
|
127
118
|
offset += publicKeySize;
|
|
128
119
|
// Read Cipher Suites Length
|
|
129
120
|
const cipherSuitesLength = (data[offset++] << 8) | data[offset++];
|
|
130
|
-
//
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
121
|
+
// Parse all cipher suites (each suite is 4 bytes: 2 for KDF, 2 for AEAD)
|
|
122
|
+
const suites = [];
|
|
123
|
+
const cipherSuitesEnd = offset + cipherSuitesLength;
|
|
124
|
+
while (offset < cipherSuitesEnd) {
|
|
125
|
+
const kdfId = (data[offset++] << 8) | data[offset++];
|
|
126
|
+
const aeadId = (data[offset++] << 8) | data[offset++];
|
|
127
|
+
suites.push({ kdfId, aeadId });
|
|
128
|
+
}
|
|
129
|
+
if (suites.length === 0) {
|
|
130
|
+
throw new Error('No cipher suites found in config');
|
|
131
|
+
}
|
|
132
|
+
// Use the first cipher suite
|
|
133
|
+
const firstSuite = suites[0];
|
|
134
|
+
// Validate that we support this cipher suite
|
|
135
|
+
if (firstSuite.kdfId !== HPKE_CONFIG.KDF || firstSuite.aeadId !== HPKE_CONFIG.AEAD) {
|
|
136
|
+
throw new Error(`Unsupported cipher suite: KDF=0x${firstSuite.kdfId.toString(16)}, AEAD=0x${firstSuite.aeadId.toString(16)}`);
|
|
137
|
+
}
|
|
138
|
+
// Create cipher suite
|
|
139
|
+
const suite = createSuite();
|
|
140
|
+
// Import public key
|
|
141
|
+
const publicKey = await suite.DeserializePublicKey(publicKeyBytes);
|
|
142
142
|
// For server config, we only have the public key, no private key
|
|
143
143
|
// We'll create a dummy private key that won't be used
|
|
144
|
-
const dummyPrivateKey = await suite.
|
|
144
|
+
const dummyPrivateKey = await suite.DeserializePrivateKey(new Uint8Array(32), false);
|
|
145
145
|
return new Identity(suite, publicKey, dummyPrivateKey);
|
|
146
146
|
}
|
|
147
147
|
/**
|
|
148
|
-
* Encrypt request body and
|
|
148
|
+
* Encrypt request body and return context for response decryption.
|
|
149
|
+
*
|
|
150
|
+
* This method is called on the SERVER's identity (public key only).
|
|
151
|
+
* It:
|
|
152
|
+
* 1. Creates an HPKE sender context to this identity's public key
|
|
153
|
+
* 2. Encrypts the request body
|
|
154
|
+
* 3. Returns a RequestContext that must be used to decrypt the response
|
|
149
155
|
*/
|
|
150
|
-
async
|
|
156
|
+
async encryptRequestWithContext(request) {
|
|
151
157
|
const body = await request.arrayBuffer();
|
|
158
|
+
// Bodyless requests pass through unmodified - no HPKE context needed.
|
|
159
|
+
// See SPEC.md Section 5.1: "When the request has no payload body, an encrypted
|
|
160
|
+
// response is not possible (since there is no HPKE context to derive response
|
|
161
|
+
// keys from). Such requests pass through unmodified."
|
|
152
162
|
if (body.byteLength === 0) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
163
|
+
return {
|
|
164
|
+
request: new Request(request.url, {
|
|
165
|
+
method: request.method,
|
|
166
|
+
headers: request.headers,
|
|
167
|
+
body: null,
|
|
168
|
+
}),
|
|
169
|
+
context: null,
|
|
170
|
+
};
|
|
161
171
|
}
|
|
162
|
-
// Create sender for encryption
|
|
163
|
-
const
|
|
164
|
-
|
|
172
|
+
// Create sender context for encryption with info parameter for domain separation
|
|
173
|
+
const infoBytes = new TextEncoder().encode(HPKE_REQUEST_INFO);
|
|
174
|
+
const { encapsulatedSecret, ctx } = await this.suite.SetupSender(this.publicKey, {
|
|
175
|
+
info: infoBytes,
|
|
165
176
|
});
|
|
177
|
+
// Store context for response decryption
|
|
178
|
+
const context = {
|
|
179
|
+
senderContext: ctx,
|
|
180
|
+
requestEnc: encapsulatedSecret,
|
|
181
|
+
};
|
|
182
|
+
// Set headers - only encapsulated key for requests with body
|
|
183
|
+
const headers = new Headers(request.headers);
|
|
184
|
+
headers.set(PROTOCOL.ENCAPSULATED_KEY_HEADER, bytesToHex(context.requestEnc));
|
|
166
185
|
// Encrypt the body
|
|
167
|
-
const encrypted = await
|
|
168
|
-
// Get encapsulated key
|
|
169
|
-
const encapKey = sender.enc;
|
|
186
|
+
const encrypted = await ctx.Seal(new Uint8Array(body));
|
|
170
187
|
// Create chunked format: 4-byte length header + encrypted data
|
|
171
188
|
const chunkLength = new Uint8Array(4);
|
|
172
|
-
|
|
173
|
-
view.setUint32(0, encrypted.byteLength, false); // Big-endian
|
|
189
|
+
new DataView(chunkLength.buffer).setUint32(0, encrypted.byteLength, false);
|
|
174
190
|
const chunkedData = new Uint8Array(4 + encrypted.byteLength);
|
|
175
191
|
chunkedData.set(chunkLength, 0);
|
|
176
|
-
chunkedData.set(
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
body: chunkedData,
|
|
187
|
-
duplex: 'half'
|
|
188
|
-
});
|
|
192
|
+
chunkedData.set(encrypted, 4);
|
|
193
|
+
return {
|
|
194
|
+
request: new Request(request.url, {
|
|
195
|
+
method: request.method,
|
|
196
|
+
headers,
|
|
197
|
+
body: chunkedData,
|
|
198
|
+
duplex: 'half',
|
|
199
|
+
}),
|
|
200
|
+
context,
|
|
201
|
+
};
|
|
189
202
|
}
|
|
190
203
|
/**
|
|
191
|
-
* Decrypt response
|
|
204
|
+
* Decrypt response using keys derived from request context.
|
|
205
|
+
*
|
|
206
|
+
* This method:
|
|
207
|
+
* 1. Reads the response nonce from Ehbp-Response-Nonce header
|
|
208
|
+
* 2. Exports a secret from the HPKE sender context
|
|
209
|
+
* 3. Derives response keys using HKDF
|
|
210
|
+
* 4. Decrypts the response body
|
|
192
211
|
*/
|
|
193
|
-
async
|
|
212
|
+
async decryptResponseWithContext(response, context) {
|
|
194
213
|
if (!response.body) {
|
|
195
214
|
return response;
|
|
196
215
|
}
|
|
197
|
-
//
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
216
|
+
// Get response nonce from header
|
|
217
|
+
const responseNonceHex = response.headers.get(PROTOCOL.RESPONSE_NONCE_HEADER);
|
|
218
|
+
if (!responseNonceHex) {
|
|
219
|
+
throw new Error(`Missing ${PROTOCOL.RESPONSE_NONCE_HEADER} header`);
|
|
220
|
+
}
|
|
221
|
+
const responseNonce = hexToBytes(responseNonceHex);
|
|
222
|
+
if (responseNonce.length !== RESPONSE_NONCE_LENGTH) {
|
|
223
|
+
throw new Error(`Invalid response nonce length: expected ${RESPONSE_NONCE_LENGTH}, got ${responseNonce.length}`);
|
|
224
|
+
}
|
|
225
|
+
// Export secret from request context
|
|
226
|
+
const exportLabelBytes = new TextEncoder().encode(EXPORT_LABEL);
|
|
227
|
+
const exportedSecret = await context.senderContext.Export(exportLabelBytes, EXPORT_LENGTH);
|
|
228
|
+
// Derive response keys
|
|
229
|
+
const km = await deriveResponseKeys(exportedSecret, context.requestEnc, responseNonce);
|
|
230
|
+
// Create decrypting stream
|
|
231
|
+
const decryptedStream = this.createDecryptStream(response.body, km);
|
|
232
|
+
return new Response(decryptedStream, {
|
|
233
|
+
status: response.status,
|
|
234
|
+
statusText: response.statusText,
|
|
235
|
+
headers: response.headers,
|
|
201
236
|
});
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
buffer =
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
continue; // Empty chunk
|
|
229
|
-
}
|
|
230
|
-
// Check if we have the complete chunk
|
|
231
|
-
if (offset + chunkLength > buffer.length) {
|
|
232
|
-
// Not enough data yet, rewind offset and wait for more
|
|
233
|
-
offset -= 4;
|
|
234
|
-
break;
|
|
235
|
-
}
|
|
236
|
-
// Extract and decrypt the chunk
|
|
237
|
-
const encryptedChunk = buffer.slice(offset, offset + chunkLength);
|
|
238
|
-
offset += chunkLength;
|
|
239
|
-
try {
|
|
240
|
-
const decryptedChunk = await receiver.open(encryptedChunk.buffer);
|
|
241
|
-
controller.enqueue(new Uint8Array(decryptedChunk));
|
|
242
|
-
}
|
|
243
|
-
catch (error) {
|
|
244
|
-
controller.error(new Error(`Failed to decrypt chunk: ${error}`));
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Creates a ReadableStream that decrypts response chunks.
|
|
240
|
+
*/
|
|
241
|
+
createDecryptStream(body, km) {
|
|
242
|
+
let buffer = new Uint8Array(0);
|
|
243
|
+
let seq = 0;
|
|
244
|
+
const reader = body.getReader();
|
|
245
|
+
return new ReadableStream({
|
|
246
|
+
async pull(controller) {
|
|
247
|
+
while (true) {
|
|
248
|
+
// Try to read a complete chunk from buffer
|
|
249
|
+
if (buffer.length >= 4) {
|
|
250
|
+
const chunkLength = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
|
|
251
|
+
if (chunkLength === 0) {
|
|
252
|
+
// Skip empty chunk
|
|
253
|
+
buffer = buffer.slice(4);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (buffer.length >= 4 + chunkLength) {
|
|
257
|
+
const ciphertext = buffer.slice(4, 4 + chunkLength);
|
|
258
|
+
buffer = buffer.slice(4 + chunkLength);
|
|
259
|
+
try {
|
|
260
|
+
const plaintext = await decryptChunk(km, seq++, ciphertext);
|
|
261
|
+
controller.enqueue(plaintext);
|
|
262
|
+
return;
|
|
247
263
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
offset = 0;
|
|
264
|
+
catch (error) {
|
|
265
|
+
controller.error(new Error(`Decryption failed at chunk ${seq - 1}: ${error}`));
|
|
266
|
+
return;
|
|
252
267
|
}
|
|
253
268
|
}
|
|
254
|
-
controller.close();
|
|
255
269
|
}
|
|
256
|
-
|
|
257
|
-
|
|
270
|
+
// Need more data
|
|
271
|
+
const { done, value } = await reader.read();
|
|
272
|
+
if (done) {
|
|
273
|
+
controller.close();
|
|
274
|
+
return;
|
|
258
275
|
}
|
|
276
|
+
// Append to buffer
|
|
277
|
+
const newBuffer = new Uint8Array(buffer.length + value.length);
|
|
278
|
+
newBuffer.set(buffer);
|
|
279
|
+
newBuffer.set(value, buffer.length);
|
|
280
|
+
buffer = newBuffer;
|
|
259
281
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
status: response.status,
|
|
266
|
-
statusText: response.statusText,
|
|
267
|
-
headers: response.headers
|
|
282
|
+
},
|
|
283
|
+
cancel(reason) {
|
|
284
|
+
// Release the underlying reader when the stream is cancelled
|
|
285
|
+
return reader.cancel(reason);
|
|
286
|
+
},
|
|
268
287
|
});
|
|
269
288
|
}
|
|
270
289
|
}
|
package/dist/esm/identity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* bodies while preserving HTTP headers for routing.
|
|
7
7
|
*/
|
|
8
8
|
export { Identity } from './identity.js';
|
|
9
|
+
export type { RequestContext } from './identity.js';
|
|
9
10
|
export { Transport, createTransport } from './client.js';
|
|
10
11
|
export { PROTOCOL, HPKE_CONFIG } from './protocol.js';
|
|
11
|
-
export
|
|
12
|
+
export { deriveResponseKeys, computeNonce, encryptChunk, decryptChunk, hexToBytes, bytesToHex, HPKE_REQUEST_INFO, EXPORT_LABEL, EXPORT_LENGTH, RESPONSE_NONCE_LENGTH, AES256_KEY_LENGTH, AES_GCM_NONCE_LENGTH, } from './derive.js';
|
|
13
|
+
export type { ResponseKeyMaterial } from './derive.js';
|
|
14
|
+
export type { CipherSuite, SenderContext, RecipientContext, Key } from 'hpke';
|
|
12
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGtD,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -8,4 +8,6 @@
|
|
|
8
8
|
export { Identity } from './identity.js';
|
|
9
9
|
export { Transport, createTransport } from './client.js';
|
|
10
10
|
export { PROTOCOL, HPKE_CONFIG } from './protocol.js';
|
|
11
|
+
// Export key derivation utilities for advanced usage
|
|
12
|
+
export { deriveResponseKeys, computeNonce, encryptChunk, decryptChunk, hexToBytes, bytesToHex, HPKE_REQUEST_INFO, EXPORT_LABEL, EXPORT_LENGTH, RESPONSE_NONCE_LENGTH, AES256_KEY_LENGTH, AES_GCM_NONCE_LENGTH, } from './derive.js';
|
|
11
13
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEtD,qDAAqD;AACrD,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,aAAa,CAAC"}
|
package/dist/esm/protocol.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export declare const PROTOCOL: {
|
|
5
5
|
readonly ENCAPSULATED_KEY_HEADER: "Ehbp-Encapsulated-Key";
|
|
6
|
-
readonly
|
|
6
|
+
readonly RESPONSE_NONCE_HEADER: "Ehbp-Response-Nonce";
|
|
7
7
|
readonly KEYS_MEDIA_TYPE: "application/ohttp-keys";
|
|
8
8
|
readonly KEYS_PATH: "/.well-known/hpke-keys";
|
|
9
9
|
readonly FALLBACK_HEADER: "Ehbp-Fallback";
|
package/dist/esm/protocol.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const PROTOCOL = {
|
|
5
5
|
ENCAPSULATED_KEY_HEADER: 'Ehbp-Encapsulated-Key',
|
|
6
|
-
|
|
6
|
+
RESPONSE_NONCE_HEADER: 'Ehbp-Response-Nonce',
|
|
7
7
|
KEYS_MEDIA_TYPE: 'application/ohttp-keys',
|
|
8
8
|
KEYS_PATH: '/.well-known/hpke-keys',
|
|
9
|
-
FALLBACK_HEADER: 'Ehbp-Fallback'
|
|
9
|
+
FALLBACK_HEADER: 'Ehbp-Fallback',
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
12
|
* HPKE suite configuration matching the Go implementation
|
package/dist/esm/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,uBAAuB,EAAE,uBAAuB;IAChD,
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,uBAAuB,EAAE,uBAAuB;IAChD,qBAAqB,EAAE,qBAAqB;IAC5C,eAAe,EAAE,wBAAwB;IACzC,SAAS,EAAE,wBAAwB;IACnC,eAAe,EAAE,eAAe;CACxB,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,GAAG,EAAE,MAAM,EAAE,qBAAqB;IAClC,GAAG,EAAE,MAAM,EAAE,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC,cAAc;CACnB,CAAC"}
|
|
@@ -3,41 +3,41 @@ import assert from 'node:assert';
|
|
|
3
3
|
import { Identity, Transport, createTransport } from '../index.js';
|
|
4
4
|
import { PROTOCOL } from '../protocol.js';
|
|
5
5
|
describe('Transport', () => {
|
|
6
|
-
let clientIdentity;
|
|
7
6
|
let serverIdentity;
|
|
8
7
|
before(async () => {
|
|
9
|
-
clientIdentity = await Identity.generate();
|
|
10
8
|
serverIdentity = await Identity.generate();
|
|
11
9
|
});
|
|
12
10
|
it('should create transport with server public key', () => {
|
|
13
|
-
const transport = new Transport(
|
|
11
|
+
const transport = new Transport(serverIdentity, 'localhost:8080');
|
|
14
12
|
assert(transport instanceof Transport, 'Should create transport instance');
|
|
15
13
|
});
|
|
16
14
|
it('should encrypt and decrypt request', async () => {
|
|
17
|
-
const serverPublicKey = serverIdentity.getPublicKey();
|
|
18
15
|
const originalBody = new TextEncoder().encode('Hello, World!');
|
|
19
16
|
const request = new Request('http://localhost:8080/test', {
|
|
20
17
|
method: 'POST',
|
|
21
18
|
body: originalBody
|
|
22
19
|
});
|
|
23
|
-
const encryptedRequest = await
|
|
24
|
-
// Check that headers are set
|
|
25
|
-
assert(encryptedRequest.headers.get(PROTOCOL.CLIENT_PUBLIC_KEY_HEADER), 'Client public key header should be set');
|
|
20
|
+
const { request: encryptedRequest, context } = await serverIdentity.encryptRequestWithContext(request);
|
|
26
21
|
assert(encryptedRequest.headers.get(PROTOCOL.ENCAPSULATED_KEY_HEADER), 'Encapsulated key header should be set');
|
|
22
|
+
// Check that context was returned for response decryption
|
|
23
|
+
assert(context, 'Context should be returned');
|
|
24
|
+
assert(context.senderContext, 'Context should have sender context');
|
|
25
|
+
assert(context.requestEnc, 'Context should have request enc');
|
|
27
26
|
// Check that body is encrypted (different from original)
|
|
28
27
|
const encryptedBody = await encryptedRequest.arrayBuffer();
|
|
29
28
|
assert(encryptedBody.byteLength > 0, 'Encrypted body should not be empty');
|
|
30
29
|
assert(encryptedBody.byteLength !== originalBody.length, 'Encrypted body should have different length');
|
|
31
30
|
});
|
|
32
31
|
it('should handle request without body', async () => {
|
|
33
|
-
const serverPublicKey = serverIdentity.getPublicKey();
|
|
34
32
|
const request = new Request('http://localhost:8080/test', {
|
|
35
33
|
method: 'GET'
|
|
36
34
|
});
|
|
37
|
-
const
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
assert(
|
|
35
|
+
const { request: resultRequest, context } = await serverIdentity.encryptRequestWithContext(request);
|
|
36
|
+
// Bodyless requests pass through unmodified - no EHBP headers set
|
|
37
|
+
// See SPEC.md Section 5.1
|
|
38
|
+
assert.strictEqual(resultRequest.headers.get(PROTOCOL.ENCAPSULATED_KEY_HEADER), null, 'Encapsulated key header should NOT be set for bodyless requests');
|
|
39
|
+
// Context is null for bodyless requests (no HPKE context to derive response keys from)
|
|
40
|
+
assert.strictEqual(context, null, 'Context should be null for bodyless requests');
|
|
41
41
|
});
|
|
42
42
|
it('should connect to actual server and POST to /secure endpoint', async (t) => {
|
|
43
43
|
const serverURL = 'http://localhost:8080';
|
|
@@ -48,15 +48,14 @@ describe('Transport', () => {
|
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
catch
|
|
51
|
+
catch {
|
|
52
52
|
t.skip('Server not running at localhost:8080');
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
const transport = await createTransport(serverURL, clientIdentity);
|
|
55
|
+
const transport = await createTransport(serverURL);
|
|
57
56
|
const testName = 'Integration Test User';
|
|
58
57
|
const serverPubKeyHex = await transport.getServerPublicKeyHex();
|
|
59
|
-
assert.strictEqual(serverPubKeyHex.length, 64, 'Server public key should be 64 bytes');
|
|
58
|
+
assert.strictEqual(serverPubKeyHex.length, 64, 'Server public key should be 64 hex chars (32 bytes)');
|
|
60
59
|
// Make actual POST request to /secure endpoint
|
|
61
60
|
const response = await transport.post(`${serverURL}/secure`, testName, {
|
|
62
61
|
headers: { 'Content-Type': 'text/plain' }
|