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/cjs/protocol.js
CHANGED
|
@@ -6,10 +6,10 @@ exports.HPKE_CONFIG = exports.PROTOCOL = void 0;
|
|
|
6
6
|
*/
|
|
7
7
|
exports.PROTOCOL = {
|
|
8
8
|
ENCAPSULATED_KEY_HEADER: 'Ehbp-Encapsulated-Key',
|
|
9
|
-
|
|
9
|
+
RESPONSE_NONCE_HEADER: 'Ehbp-Response-Nonce',
|
|
10
10
|
KEYS_MEDIA_TYPE: 'application/ohttp-keys',
|
|
11
11
|
KEYS_PATH: '/.well-known/hpke-keys',
|
|
12
|
-
FALLBACK_HEADER: 'Ehbp-Fallback'
|
|
12
|
+
FALLBACK_HEADER: 'Ehbp-Fallback',
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
15
|
* HPKE suite configuration matching the Go implementation
|
package/dist/cjs/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,QAAQ,GAAG;IACtB,uBAAuB,EAAE,uBAAuB;IAChD,
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/protocol.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,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;AACU,QAAA,WAAW,GAAG;IACzB,GAAG,EAAE,MAAM,EAAE,qBAAqB;IAClC,GAAG,EAAE,MAAM,EAAE,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC,cAAc;CACnB,CAAC"}
|
package/dist/esm/client.d.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import { Identity } from './identity.js';
|
|
2
|
+
import type { Key } from 'hpke';
|
|
2
3
|
/**
|
|
3
4
|
* HTTP transport for EHBP
|
|
4
5
|
*/
|
|
5
6
|
export declare class Transport {
|
|
6
|
-
private
|
|
7
|
+
private serverIdentity;
|
|
7
8
|
private serverHost;
|
|
8
|
-
|
|
9
|
-
constructor(clientIdentity: Identity, serverHost: string, serverPublicKey: CryptoKey);
|
|
9
|
+
constructor(serverIdentity: Identity, serverHost: string);
|
|
10
10
|
/**
|
|
11
|
-
* Create a new transport by fetching server public key
|
|
11
|
+
* Create a new transport by fetching server public key.
|
|
12
12
|
*/
|
|
13
|
-
static create(serverURL: string
|
|
13
|
+
static create(serverURL: string): Promise<Transport>;
|
|
14
|
+
/**
|
|
15
|
+
* Get the server identity
|
|
16
|
+
*/
|
|
17
|
+
getServerIdentity(): Identity;
|
|
14
18
|
/**
|
|
15
19
|
* Get the server public key
|
|
16
20
|
*/
|
|
17
|
-
getServerPublicKey():
|
|
21
|
+
getServerPublicKey(): Key;
|
|
18
22
|
/**
|
|
19
23
|
* Get the server public key as hex string
|
|
20
24
|
*/
|
|
21
25
|
getServerPublicKeyHex(): Promise<string>;
|
|
22
26
|
/**
|
|
23
|
-
*
|
|
24
|
-
*/
|
|
25
|
-
getClientPublicKey(): CryptoKey;
|
|
26
|
-
/**
|
|
27
|
-
* Make an encrypted HTTP request
|
|
27
|
+
* Make an encrypted HTTP request.
|
|
28
28
|
*/
|
|
29
29
|
request(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
30
30
|
/**
|
|
@@ -45,7 +45,7 @@ export declare class Transport {
|
|
|
45
45
|
delete(url: string | URL, init?: RequestInit): Promise<Response>;
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
48
|
-
* Create a new transport instance
|
|
48
|
+
* Create a new transport instance.
|
|
49
49
|
*/
|
|
50
|
-
export declare function createTransport(serverURL: string
|
|
50
|
+
export declare function createTransport(serverURL: string): Promise<Transport>;
|
|
51
51
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/esm/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAEhC;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,UAAU,CAAS;gBAEf,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM;IAKxD;;OAEG;WACU,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAuB1D;;OAEG;IACH,iBAAiB,IAAI,QAAQ;IAI7B;;OAEG;IACH,kBAAkB,IAAI,GAAG;IAIzB;;OAEG;IACG,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC;IAI9C;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IA6E9E;;OAEG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IAInE;;OAEG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IAIrF;;OAEG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IAIpF;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;CAGvE;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAE3E"}
|
package/dist/esm/client.js
CHANGED
|
@@ -4,18 +4,16 @@ import { PROTOCOL } from './protocol.js';
|
|
|
4
4
|
* HTTP transport for EHBP
|
|
5
5
|
*/
|
|
6
6
|
export class Transport {
|
|
7
|
-
|
|
7
|
+
serverIdentity;
|
|
8
8
|
serverHost;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
this.clientIdentity = clientIdentity;
|
|
9
|
+
constructor(serverIdentity, serverHost) {
|
|
10
|
+
this.serverIdentity = serverIdentity;
|
|
12
11
|
this.serverHost = serverHost;
|
|
13
|
-
this.serverPublicKey = serverPublicKey;
|
|
14
12
|
}
|
|
15
13
|
/**
|
|
16
|
-
* Create a new transport by fetching server public key
|
|
14
|
+
* Create a new transport by fetching server public key.
|
|
17
15
|
*/
|
|
18
|
-
static async create(serverURL
|
|
16
|
+
static async create(serverURL) {
|
|
19
17
|
const url = new URL(serverURL);
|
|
20
18
|
const serverHost = url.host;
|
|
21
19
|
// Fetch server public key
|
|
@@ -30,38 +28,33 @@ export class Transport {
|
|
|
30
28
|
}
|
|
31
29
|
const keysData = new Uint8Array(await response.arrayBuffer());
|
|
32
30
|
const serverIdentity = await Identity.unmarshalPublicConfig(keysData);
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
return new Transport(serverIdentity, serverHost);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get the server identity
|
|
35
|
+
*/
|
|
36
|
+
getServerIdentity() {
|
|
37
|
+
return this.serverIdentity;
|
|
35
38
|
}
|
|
36
39
|
/**
|
|
37
40
|
* Get the server public key
|
|
38
41
|
*/
|
|
39
42
|
getServerPublicKey() {
|
|
40
|
-
return this.
|
|
43
|
+
return this.serverIdentity.getPublicKey();
|
|
41
44
|
}
|
|
42
45
|
/**
|
|
43
46
|
* Get the server public key as hex string
|
|
44
47
|
*/
|
|
45
48
|
async getServerPublicKeyHex() {
|
|
46
|
-
|
|
47
|
-
const keyBytes = new Uint8Array(exported);
|
|
48
|
-
return Array.from(keyBytes)
|
|
49
|
-
.map(b => b.toString(16).padStart(2, '0'))
|
|
50
|
-
.join('');
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Get the client public key
|
|
54
|
-
*/
|
|
55
|
-
getClientPublicKey() {
|
|
56
|
-
return this.clientIdentity.getPublicKey();
|
|
49
|
+
return this.serverIdentity.getPublicKeyHex();
|
|
57
50
|
}
|
|
58
51
|
/**
|
|
59
|
-
* Make an encrypted HTTP request
|
|
52
|
+
* Make an encrypted HTTP request.
|
|
60
53
|
*/
|
|
61
54
|
async request(input, init) {
|
|
62
|
-
// Skip EHBP for
|
|
55
|
+
// Skip EHBP for non-network URLs (data:, blob:)
|
|
63
56
|
const inputUrl = input instanceof Request ? input.url : String(input);
|
|
64
|
-
if (inputUrl.startsWith('data:')) {
|
|
57
|
+
if (inputUrl.startsWith('data:') || inputUrl.startsWith('blob:')) {
|
|
65
58
|
return fetch(input, init);
|
|
66
59
|
}
|
|
67
60
|
// Extract body from init or original request before creating Request object
|
|
@@ -95,36 +88,32 @@ export class Transport {
|
|
|
95
88
|
method,
|
|
96
89
|
headers,
|
|
97
90
|
body: requestBody,
|
|
98
|
-
duplex: 'half'
|
|
91
|
+
duplex: 'half',
|
|
99
92
|
});
|
|
100
|
-
// Encrypt request
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
// No body, just set client public key header
|
|
106
|
-
const headers = new Headers(request.headers);
|
|
107
|
-
headers.set(PROTOCOL.CLIENT_PUBLIC_KEY_HEADER, await this.clientIdentity.getPublicKeyHex());
|
|
108
|
-
request = new Request(request.url, {
|
|
109
|
-
method: request.method,
|
|
110
|
-
headers,
|
|
111
|
-
body: null
|
|
112
|
-
});
|
|
113
|
-
}
|
|
93
|
+
// Encrypt request (returns context for response decryption)
|
|
94
|
+
// For bodyless requests, context will be null and request passes through unmodified
|
|
95
|
+
const { request: encryptedRequest, context } = await this.serverIdentity.encryptRequestWithContext(request);
|
|
114
96
|
// Make the request
|
|
115
|
-
const response = await fetch(
|
|
97
|
+
const response = await fetch(encryptedRequest);
|
|
116
98
|
if (!response.ok) {
|
|
117
99
|
console.warn(`Server returned non-OK status: ${response.status}`);
|
|
118
100
|
}
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
101
|
+
// Bodyless requests: context is null, response is plaintext
|
|
102
|
+
if (context === null) {
|
|
103
|
+
return response;
|
|
104
|
+
}
|
|
105
|
+
// Check for fallback header - if set, server returned unencrypted response
|
|
106
|
+
const fallbackHeader = response.headers.get(PROTOCOL.FALLBACK_HEADER);
|
|
107
|
+
if (fallbackHeader === '1') {
|
|
108
|
+
return response;
|
|
109
|
+
}
|
|
110
|
+
// Check for response nonce header (required for response decryption)
|
|
111
|
+
const responseNonceHeader = response.headers.get(PROTOCOL.RESPONSE_NONCE_HEADER);
|
|
112
|
+
if (!responseNonceHeader) {
|
|
113
|
+
throw new Error(`Missing ${PROTOCOL.RESPONSE_NONCE_HEADER} header`);
|
|
123
114
|
}
|
|
124
|
-
// Decode encapsulated key
|
|
125
|
-
const serverEncapKey = new Uint8Array(encapKeyHeader.match(/.{2}/g).map(byte => parseInt(byte, 16)));
|
|
126
115
|
// Decrypt response
|
|
127
|
-
return await this.
|
|
116
|
+
return await this.serverIdentity.decryptResponseWithContext(response, context);
|
|
128
117
|
}
|
|
129
118
|
/**
|
|
130
119
|
* Convenience method for GET requests
|
|
@@ -152,9 +141,9 @@ export class Transport {
|
|
|
152
141
|
}
|
|
153
142
|
}
|
|
154
143
|
/**
|
|
155
|
-
* Create a new transport instance
|
|
144
|
+
* Create a new transport instance.
|
|
156
145
|
*/
|
|
157
|
-
export async function createTransport(serverURL
|
|
158
|
-
return Transport.create(serverURL
|
|
146
|
+
export async function createTransport(serverURL) {
|
|
147
|
+
return Transport.create(serverURL);
|
|
159
148
|
}
|
|
160
149
|
//# sourceMappingURL=client.js.map
|
package/dist/esm/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response key derivation for EHBP
|
|
3
|
+
*
|
|
4
|
+
* This module implements the key derivation matching the Go implementation.
|
|
5
|
+
*
|
|
6
|
+
* The derivation follows OHTTP (RFC 9458):
|
|
7
|
+
* salt = concat(enc, response_nonce)
|
|
8
|
+
* prk = Extract(salt, secret)
|
|
9
|
+
* aead_key = Expand(prk, "key", Nk)
|
|
10
|
+
* aead_nonce = Expand(prk, "nonce", Nn)
|
|
11
|
+
*/
|
|
12
|
+
export declare const HPKE_REQUEST_INFO = "ehbp request";
|
|
13
|
+
export declare const EXPORT_LABEL = "ehbp response";
|
|
14
|
+
export declare const EXPORT_LENGTH = 32;
|
|
15
|
+
export declare const RESPONSE_NONCE_LENGTH = 32;
|
|
16
|
+
export declare const AES256_KEY_LENGTH = 32;
|
|
17
|
+
export declare const AES_GCM_NONCE_LENGTH = 12;
|
|
18
|
+
export declare const REQUEST_ENC_LENGTH = 32;
|
|
19
|
+
/**
|
|
20
|
+
* Response key material for encryption/decryption
|
|
21
|
+
*/
|
|
22
|
+
export interface ResponseKeyMaterial {
|
|
23
|
+
/** Raw key bytes for AEAD operations */
|
|
24
|
+
keyBytes: Uint8Array;
|
|
25
|
+
/** 12 bytes, XORed with sequence number for each chunk */
|
|
26
|
+
nonceBase: Uint8Array;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Derives response encryption keys from the HPKE exported secret.
|
|
30
|
+
*
|
|
31
|
+
* salt = concat(enc, response_nonce)
|
|
32
|
+
* prk = Extract(salt, secret)
|
|
33
|
+
* key = Expand(prk, "key", 32)
|
|
34
|
+
* nonceBase = Expand(prk, "nonce", 12)
|
|
35
|
+
*
|
|
36
|
+
* @param exportedSecret - 32 bytes exported from HPKE context
|
|
37
|
+
* @param requestEnc - 32 bytes encapsulated key from request
|
|
38
|
+
* @param responseNonce - 32 bytes random nonce from response
|
|
39
|
+
* @returns Key material for response encryption/decryption
|
|
40
|
+
*/
|
|
41
|
+
export declare function deriveResponseKeys(exportedSecret: Uint8Array, requestEnc: Uint8Array, responseNonce: Uint8Array): Promise<ResponseKeyMaterial>;
|
|
42
|
+
/**
|
|
43
|
+
* Computes the nonce for a specific sequence number.
|
|
44
|
+
* nonce = nonceBase XOR sequence_number (big-endian in last 8 bytes)
|
|
45
|
+
*/
|
|
46
|
+
export declare function computeNonce(nonceBase: Uint8Array, seq: number): Uint8Array;
|
|
47
|
+
/**
|
|
48
|
+
* Encrypts a chunk using the response key material
|
|
49
|
+
*/
|
|
50
|
+
export declare function encryptChunk(km: ResponseKeyMaterial, seq: number, plaintext: Uint8Array): Promise<Uint8Array>;
|
|
51
|
+
/**
|
|
52
|
+
* Decrypts a chunk using the response key material
|
|
53
|
+
*/
|
|
54
|
+
export declare function decryptChunk(km: ResponseKeyMaterial, seq: number, ciphertext: Uint8Array): Promise<Uint8Array>;
|
|
55
|
+
/**
|
|
56
|
+
* Utility: Convert hex string to Uint8Array
|
|
57
|
+
*/
|
|
58
|
+
export declare function hexToBytes(hex: string): Uint8Array;
|
|
59
|
+
/**
|
|
60
|
+
* Utility: Convert Uint8Array to hex string
|
|
61
|
+
*/
|
|
62
|
+
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
63
|
+
//# sourceMappingURL=derive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../../src/derive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAChD,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAC5C,eAAO,MAAM,aAAa,KAAK,CAAC;AAChC,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAMrC;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,QAAQ,EAAE,UAAU,CAAC;IACrB,0DAA0D;IAC1D,SAAS,EAAE,UAAU,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,UAAU,EAC1B,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,UAAU,GACxB,OAAO,CAAC,mBAAmB,CAAC,CA2B9B;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAyB3E;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,mBAAmB,EACvB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC,UAAU,CAAC,CAMrB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,mBAAmB,EACvB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,UAAU,CAAC,CAMrB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAYlD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIpD"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response key derivation for EHBP
|
|
3
|
+
*
|
|
4
|
+
* This module implements the key derivation matching the Go implementation.
|
|
5
|
+
*
|
|
6
|
+
* The derivation follows OHTTP (RFC 9458):
|
|
7
|
+
* salt = concat(enc, response_nonce)
|
|
8
|
+
* prk = Extract(salt, secret)
|
|
9
|
+
* aead_key = Expand(prk, "key", Nk)
|
|
10
|
+
* aead_nonce = Expand(prk, "nonce", Nn)
|
|
11
|
+
*/
|
|
12
|
+
import { KDF_HKDF_SHA256, AEAD_AES_256_GCM } from 'hpke';
|
|
13
|
+
const kdf = KDF_HKDF_SHA256();
|
|
14
|
+
const aead = AEAD_AES_256_GCM();
|
|
15
|
+
export const HPKE_REQUEST_INFO = 'ehbp request';
|
|
16
|
+
export const EXPORT_LABEL = 'ehbp response';
|
|
17
|
+
export const EXPORT_LENGTH = 32;
|
|
18
|
+
export const RESPONSE_NONCE_LENGTH = 32; // max(Nn, Nk) = max(12, 32) = 32
|
|
19
|
+
export const AES256_KEY_LENGTH = 32;
|
|
20
|
+
export const AES_GCM_NONCE_LENGTH = 12;
|
|
21
|
+
export const REQUEST_ENC_LENGTH = 32; // X25519 enc size
|
|
22
|
+
// Labels for HKDF-Expand
|
|
23
|
+
const RESPONSE_KEY_LABEL = new TextEncoder().encode('key');
|
|
24
|
+
const RESPONSE_NONCE_LABEL = new TextEncoder().encode('nonce');
|
|
25
|
+
/**
|
|
26
|
+
* Derives response encryption keys from the HPKE exported secret.
|
|
27
|
+
*
|
|
28
|
+
* salt = concat(enc, response_nonce)
|
|
29
|
+
* prk = Extract(salt, secret)
|
|
30
|
+
* key = Expand(prk, "key", 32)
|
|
31
|
+
* nonceBase = Expand(prk, "nonce", 12)
|
|
32
|
+
*
|
|
33
|
+
* @param exportedSecret - 32 bytes exported from HPKE context
|
|
34
|
+
* @param requestEnc - 32 bytes encapsulated key from request
|
|
35
|
+
* @param responseNonce - 32 bytes random nonce from response
|
|
36
|
+
* @returns Key material for response encryption/decryption
|
|
37
|
+
*/
|
|
38
|
+
export async function deriveResponseKeys(exportedSecret, requestEnc, responseNonce) {
|
|
39
|
+
// Validate inputs
|
|
40
|
+
if (exportedSecret.length !== EXPORT_LENGTH) {
|
|
41
|
+
throw new Error(`exported secret must be ${EXPORT_LENGTH} bytes, got ${exportedSecret.length}`);
|
|
42
|
+
}
|
|
43
|
+
if (requestEnc.length !== REQUEST_ENC_LENGTH) {
|
|
44
|
+
throw new Error(`request enc must be ${REQUEST_ENC_LENGTH} bytes, got ${requestEnc.length}`);
|
|
45
|
+
}
|
|
46
|
+
if (responseNonce.length !== RESPONSE_NONCE_LENGTH) {
|
|
47
|
+
throw new Error(`response nonce must be ${RESPONSE_NONCE_LENGTH} bytes, got ${responseNonce.length}`);
|
|
48
|
+
}
|
|
49
|
+
// salt = concat(enc, response_nonce)
|
|
50
|
+
const salt = new Uint8Array(requestEnc.length + responseNonce.length);
|
|
51
|
+
salt.set(requestEnc, 0);
|
|
52
|
+
salt.set(responseNonce, requestEnc.length);
|
|
53
|
+
// prk = Extract(salt, secret)
|
|
54
|
+
const prk = await kdf.Extract(salt, exportedSecret);
|
|
55
|
+
// key = Expand(prk, "key", 32)
|
|
56
|
+
const keyBytes = await kdf.Expand(prk, RESPONSE_KEY_LABEL, AES256_KEY_LENGTH);
|
|
57
|
+
// nonceBase = Expand(prk, "nonce", 12)
|
|
58
|
+
const nonceBase = await kdf.Expand(prk, RESPONSE_NONCE_LABEL, AES_GCM_NONCE_LENGTH);
|
|
59
|
+
return { keyBytes, nonceBase };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Computes the nonce for a specific sequence number.
|
|
63
|
+
* nonce = nonceBase XOR sequence_number (big-endian in last 8 bytes)
|
|
64
|
+
*/
|
|
65
|
+
export function computeNonce(nonceBase, seq) {
|
|
66
|
+
if (nonceBase.length !== AES_GCM_NONCE_LENGTH) {
|
|
67
|
+
throw new Error(`nonce base must be ${AES_GCM_NONCE_LENGTH} bytes`);
|
|
68
|
+
}
|
|
69
|
+
// Validate seq to prevent nonce reuse from integer overflow.
|
|
70
|
+
// JavaScript's >>> operator only works correctly for 32-bit unsigned integers.
|
|
71
|
+
// Values >= 2^32 wrap around (e.g., 2^32 >>> 0 === 0), causing nonce reuse.
|
|
72
|
+
// In practice, 2^32 chunks per response is impossible (~4PB minimum), but we validate defensively.
|
|
73
|
+
if (!Number.isInteger(seq) || seq < 0 || seq >= 0x100000000) {
|
|
74
|
+
throw new Error(`sequence number must be an integer in range [0, 2^32): got ${seq}`);
|
|
75
|
+
}
|
|
76
|
+
const nonce = new Uint8Array(AES_GCM_NONCE_LENGTH);
|
|
77
|
+
nonce.set(nonceBase);
|
|
78
|
+
// XOR with sequence number in the last 8 bytes (big-endian)
|
|
79
|
+
for (let i = 0; i < 8; i++) {
|
|
80
|
+
const shift = i * 8;
|
|
81
|
+
if (shift < 32) {
|
|
82
|
+
nonce[AES_GCM_NONCE_LENGTH - 1 - i] ^= (seq >>> shift) & 0xff;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return nonce;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Encrypts a chunk using the response key material
|
|
89
|
+
*/
|
|
90
|
+
export async function encryptChunk(km, seq, plaintext) {
|
|
91
|
+
const nonce = computeNonce(km.nonceBase, seq);
|
|
92
|
+
const ciphertext = await aead.Seal(km.keyBytes, nonce, new Uint8Array(0), plaintext);
|
|
93
|
+
return ciphertext;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Decrypts a chunk using the response key material
|
|
97
|
+
*/
|
|
98
|
+
export async function decryptChunk(km, seq, ciphertext) {
|
|
99
|
+
const nonce = computeNonce(km.nonceBase, seq);
|
|
100
|
+
const plaintext = await aead.Open(km.keyBytes, nonce, new Uint8Array(0), ciphertext);
|
|
101
|
+
return plaintext;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Utility: Convert hex string to Uint8Array
|
|
105
|
+
*/
|
|
106
|
+
export function hexToBytes(hex) {
|
|
107
|
+
if (hex.length % 2 !== 0) {
|
|
108
|
+
throw new Error('Hex string must have even length');
|
|
109
|
+
}
|
|
110
|
+
if (!/^[0-9a-fA-F]*$/.test(hex)) {
|
|
111
|
+
throw new Error('Invalid hex character');
|
|
112
|
+
}
|
|
113
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
114
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
115
|
+
bytes[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);
|
|
116
|
+
}
|
|
117
|
+
return bytes;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Utility: Convert Uint8Array to hex string
|
|
121
|
+
*/
|
|
122
|
+
export function bytesToHex(bytes) {
|
|
123
|
+
return Array.from(bytes)
|
|
124
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
125
|
+
.join('');
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=derive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../../src/derive.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/identity.d.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import { CipherSuite } from '
|
|
1
|
+
import { CipherSuite, type SenderContext, type Key } from 'hpke';
|
|
2
|
+
/**
|
|
3
|
+
* Request context for response decryption.
|
|
4
|
+
* Holds the HPKE sender context needed to derive response keys.
|
|
5
|
+
*/
|
|
6
|
+
export interface RequestContext {
|
|
7
|
+
senderContext: SenderContext;
|
|
8
|
+
requestEnc: Uint8Array;
|
|
9
|
+
}
|
|
2
10
|
/**
|
|
3
11
|
* Identity class for managing HPKE key pairs and encryption/decryption
|
|
4
12
|
*/
|
|
@@ -6,7 +14,7 @@ export declare class Identity {
|
|
|
6
14
|
private suite;
|
|
7
15
|
private publicKey;
|
|
8
16
|
private privateKey;
|
|
9
|
-
constructor(suite: CipherSuite, publicKey:
|
|
17
|
+
constructor(suite: CipherSuite, publicKey: Key, privateKey: Key);
|
|
10
18
|
/**
|
|
11
19
|
* Generate a new identity with X25519 key pair
|
|
12
20
|
*/
|
|
@@ -20,17 +28,17 @@ export declare class Identity {
|
|
|
20
28
|
*/
|
|
21
29
|
toJSON(): Promise<string>;
|
|
22
30
|
/**
|
|
23
|
-
* Get public key
|
|
31
|
+
* Get public key
|
|
24
32
|
*/
|
|
25
|
-
getPublicKey():
|
|
33
|
+
getPublicKey(): Key;
|
|
26
34
|
/**
|
|
27
35
|
* Get public key as hex string
|
|
28
36
|
*/
|
|
29
37
|
getPublicKeyHex(): Promise<string>;
|
|
30
38
|
/**
|
|
31
|
-
* Get private key
|
|
39
|
+
* Get private key
|
|
32
40
|
*/
|
|
33
|
-
getPrivateKey():
|
|
41
|
+
getPrivateKey(): Key;
|
|
34
42
|
/**
|
|
35
43
|
* Marshal public key configuration for server key distribution
|
|
36
44
|
* Implements RFC 9458 format
|
|
@@ -41,12 +49,31 @@ export declare class Identity {
|
|
|
41
49
|
*/
|
|
42
50
|
static unmarshalPublicConfig(data: Uint8Array): Promise<Identity>;
|
|
43
51
|
/**
|
|
44
|
-
* Encrypt request body and
|
|
52
|
+
* Encrypt request body and return context for response decryption.
|
|
53
|
+
*
|
|
54
|
+
* This method is called on the SERVER's identity (public key only).
|
|
55
|
+
* It:
|
|
56
|
+
* 1. Creates an HPKE sender context to this identity's public key
|
|
57
|
+
* 2. Encrypts the request body
|
|
58
|
+
* 3. Returns a RequestContext that must be used to decrypt the response
|
|
59
|
+
*/
|
|
60
|
+
encryptRequestWithContext(request: Request): Promise<{
|
|
61
|
+
request: Request;
|
|
62
|
+
context: RequestContext | null;
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* Decrypt response using keys derived from request context.
|
|
66
|
+
*
|
|
67
|
+
* This method:
|
|
68
|
+
* 1. Reads the response nonce from Ehbp-Response-Nonce header
|
|
69
|
+
* 2. Exports a secret from the HPKE sender context
|
|
70
|
+
* 3. Derives response keys using HKDF
|
|
71
|
+
* 4. Decrypts the response body
|
|
45
72
|
*/
|
|
46
|
-
|
|
73
|
+
decryptResponseWithContext(response: Response, context: RequestContext): Promise<Response>;
|
|
47
74
|
/**
|
|
48
|
-
*
|
|
75
|
+
* Creates a ReadableStream that decrypts response chunks.
|
|
49
76
|
*/
|
|
50
|
-
|
|
77
|
+
private createDecryptStream;
|
|
51
78
|
}
|
|
52
79
|
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAIX,KAAK,aAAa,EAClB,KAAK,GAAG,EACT,MAAM,MAAM,CAAC;AAcd;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,aAAa,CAAC;IAC7B,UAAU,EAAE,UAAU,CAAC;CACxB;AAaD;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,UAAU,CAAM;gBAEZ,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG;IAM/D;;OAEG;WACU,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IAO1C;;OAEG;WACU,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAWtD;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAU/B;;OAEG;IACH,YAAY,IAAI,GAAG;IAInB;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IAKxC;;OAEG;IACH,aAAa,IAAI,GAAG;IAIpB;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IA0C1C;;OAEG;WACU,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;IAqDvE;;;;;;;;OAQG;IACG,yBAAyB,CAC7B,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;KAAE,CAAC;IAwDhE;;;;;;;;OAQG;IACG,0BAA0B,CAC9B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,QAAQ,CAAC;IAmCpB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAyD5B"}
|