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/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tinfoil, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# EHBP JavaScript Client
|
|
2
|
+
|
|
3
|
+
JavaScript/TypeScript client for [Encrypted HTTP Body Protocol (EHBP)](https://github.com/tinfoilsh/encrypted-http-body-protocol).
|
|
4
|
+
|
|
5
|
+
EHBP encrypts HTTP request and response bodies end-to-end using HPKE ([RFC 9180](https://datatracker.ietf.org/doc/rfc9180/)) while leaving headers in cleartext for routing.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install ehbp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Node.js 20+
|
|
16
|
+
- Works in both Node.js and modern browsers
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
import { createTransport } from 'ehbp';
|
|
23
|
+
|
|
24
|
+
// Create transport (fetches server public key automatically)
|
|
25
|
+
const transport = await createTransport('https://example.com');
|
|
26
|
+
|
|
27
|
+
// Make encrypted requests - works like fetch()
|
|
28
|
+
const response = await transport.post('/api/data', JSON.stringify({ message: 'hello' }), {
|
|
29
|
+
headers: { 'Content-Type': 'application/json' }
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const data = await response.json();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## API
|
|
36
|
+
|
|
37
|
+
### `createTransport(serverURL: string): Promise<Transport>`
|
|
38
|
+
|
|
39
|
+
Creates a transport that automatically encrypts requests and decrypts responses.
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
const transport = await createTransport('https://example.com');
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `transport.request(input, init?): Promise<Response>`
|
|
46
|
+
|
|
47
|
+
General-purpose method supporting all fetch options.
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
const response = await transport.request('/api/data', {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers: { 'Content-Type': 'application/json' },
|
|
53
|
+
body: JSON.stringify({ key: 'value' })
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Convenience Methods
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
await transport.get('/users');
|
|
61
|
+
await transport.post('/users', body, options);
|
|
62
|
+
await transport.put('/users/123', body, options);
|
|
63
|
+
await transport.delete('/users/123');
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Browser Usage
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<script type="module">
|
|
70
|
+
import { createTransport } from './dist/browser.js';
|
|
71
|
+
|
|
72
|
+
const transport = await createTransport('https://example.com');
|
|
73
|
+
const response = await transport.post('/api', 'Hello!');
|
|
74
|
+
console.log(await response.text());
|
|
75
|
+
</script>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Requirements
|
|
79
|
+
|
|
80
|
+
- Node.js 20+ or modern browsers with Web Crypto API
|
|
81
|
+
|
|
82
|
+
## Development
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
npm install
|
|
86
|
+
npm run build
|
|
87
|
+
npm test
|
|
88
|
+
npm run build:browser # Browser bundle
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Running Examples (Node.js)
|
|
92
|
+
|
|
93
|
+
The Node.js example requires a build and an EHBP server running at `http://localhost:8080`:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
# Build first
|
|
97
|
+
npm run build
|
|
98
|
+
|
|
99
|
+
# Start the Go server (from parent directory)
|
|
100
|
+
go run pkg/server/main.go
|
|
101
|
+
|
|
102
|
+
# Run the example (in another terminal)
|
|
103
|
+
npm run example
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Running Examples (Browser)
|
|
107
|
+
|
|
108
|
+
Browser examples are located in `examples/` and require the browser bundle:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
# Build the browser bundle
|
|
112
|
+
npm run build:browser
|
|
113
|
+
|
|
114
|
+
# Start the local dev server
|
|
115
|
+
npm run serve
|
|
116
|
+
|
|
117
|
+
# Start the Go EHBP server (from parent directory, in another terminal)
|
|
118
|
+
go run pkg/server/main.go
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Then open in your browser:
|
|
122
|
+
|
|
123
|
+
| Example | URL | Description |
|
|
124
|
+
|---------|-----|-------------|
|
|
125
|
+
| `test.html` | http://localhost:3000/examples/test.html | POST and streaming tests (server: `localhost:8080`) |
|
|
126
|
+
| `chat.html` | http://localhost:3000/examples/chat.html | Chat interface demo (server: `localhost:8443`) |
|
|
127
|
+
|
|
128
|
+
**Note:** `chat.html` connects to port 8443 and expects an OpenAI-compatible chat completions API.
|
|
129
|
+
|
|
130
|
+
### Running Integration Tests
|
|
131
|
+
|
|
132
|
+
Integration tests verify streaming functionality against a live server:
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
# Start the Go server (from parent directory)
|
|
136
|
+
go run pkg/server/main.go
|
|
137
|
+
|
|
138
|
+
# Run integration tests (in another terminal)
|
|
139
|
+
npm run build
|
|
140
|
+
npm run test:integration
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Commands
|
|
144
|
+
|
|
145
|
+
| Command | Description |
|
|
146
|
+
|---------|-------------|
|
|
147
|
+
| `npm test` | Run unit tests (no server required) |
|
|
148
|
+
| `npm run test:integration` | Run streaming integration tests (requires server) |
|
|
149
|
+
| `npm run example` | Run Node.js API demo (requires server) |
|
|
150
|
+
| `npm run serve` | Start local server for browser examples |
|
|
151
|
+
|
|
152
|
+
## Protocol
|
|
153
|
+
|
|
154
|
+
See [SPEC.md](../SPEC.md) for the complete protocol specification.
|
|
155
|
+
|
|
156
|
+
## Security
|
|
157
|
+
|
|
158
|
+
Report vulnerabilities to [security@tinfoil.sh](mailto:security@tinfoil.sh) or open a GitHub issue.
|
package/dist/cjs/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/cjs/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/cjs/client.js
CHANGED
|
@@ -8,18 +8,16 @@ const protocol_js_1 = require("./protocol.js");
|
|
|
8
8
|
* HTTP transport for EHBP
|
|
9
9
|
*/
|
|
10
10
|
class Transport {
|
|
11
|
-
|
|
11
|
+
serverIdentity;
|
|
12
12
|
serverHost;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
this.clientIdentity = clientIdentity;
|
|
13
|
+
constructor(serverIdentity, serverHost) {
|
|
14
|
+
this.serverIdentity = serverIdentity;
|
|
16
15
|
this.serverHost = serverHost;
|
|
17
|
-
this.serverPublicKey = serverPublicKey;
|
|
18
16
|
}
|
|
19
17
|
/**
|
|
20
|
-
* Create a new transport by fetching server public key
|
|
18
|
+
* Create a new transport by fetching server public key.
|
|
21
19
|
*/
|
|
22
|
-
static async create(serverURL
|
|
20
|
+
static async create(serverURL) {
|
|
23
21
|
const url = new URL(serverURL);
|
|
24
22
|
const serverHost = url.host;
|
|
25
23
|
// Fetch server public key
|
|
@@ -34,38 +32,33 @@ class Transport {
|
|
|
34
32
|
}
|
|
35
33
|
const keysData = new Uint8Array(await response.arrayBuffer());
|
|
36
34
|
const serverIdentity = await identity_js_1.Identity.unmarshalPublicConfig(keysData);
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
return new Transport(serverIdentity, serverHost);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get the server identity
|
|
39
|
+
*/
|
|
40
|
+
getServerIdentity() {
|
|
41
|
+
return this.serverIdentity;
|
|
39
42
|
}
|
|
40
43
|
/**
|
|
41
44
|
* Get the server public key
|
|
42
45
|
*/
|
|
43
46
|
getServerPublicKey() {
|
|
44
|
-
return this.
|
|
47
|
+
return this.serverIdentity.getPublicKey();
|
|
45
48
|
}
|
|
46
49
|
/**
|
|
47
50
|
* Get the server public key as hex string
|
|
48
51
|
*/
|
|
49
52
|
async getServerPublicKeyHex() {
|
|
50
|
-
|
|
51
|
-
const keyBytes = new Uint8Array(exported);
|
|
52
|
-
return Array.from(keyBytes)
|
|
53
|
-
.map(b => b.toString(16).padStart(2, '0'))
|
|
54
|
-
.join('');
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Get the client public key
|
|
58
|
-
*/
|
|
59
|
-
getClientPublicKey() {
|
|
60
|
-
return this.clientIdentity.getPublicKey();
|
|
53
|
+
return this.serverIdentity.getPublicKeyHex();
|
|
61
54
|
}
|
|
62
55
|
/**
|
|
63
|
-
* Make an encrypted HTTP request
|
|
56
|
+
* Make an encrypted HTTP request.
|
|
64
57
|
*/
|
|
65
58
|
async request(input, init) {
|
|
66
|
-
// Skip EHBP for
|
|
59
|
+
// Skip EHBP for non-network URLs (data:, blob:)
|
|
67
60
|
const inputUrl = input instanceof Request ? input.url : String(input);
|
|
68
|
-
if (inputUrl.startsWith('data:')) {
|
|
61
|
+
if (inputUrl.startsWith('data:') || inputUrl.startsWith('blob:')) {
|
|
69
62
|
return fetch(input, init);
|
|
70
63
|
}
|
|
71
64
|
// Extract body from init or original request before creating Request object
|
|
@@ -99,36 +92,32 @@ class Transport {
|
|
|
99
92
|
method,
|
|
100
93
|
headers,
|
|
101
94
|
body: requestBody,
|
|
102
|
-
duplex: 'half'
|
|
95
|
+
duplex: 'half',
|
|
103
96
|
});
|
|
104
|
-
// Encrypt request
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
// No body, just set client public key header
|
|
110
|
-
const headers = new Headers(request.headers);
|
|
111
|
-
headers.set(protocol_js_1.PROTOCOL.CLIENT_PUBLIC_KEY_HEADER, await this.clientIdentity.getPublicKeyHex());
|
|
112
|
-
request = new Request(request.url, {
|
|
113
|
-
method: request.method,
|
|
114
|
-
headers,
|
|
115
|
-
body: null
|
|
116
|
-
});
|
|
117
|
-
}
|
|
97
|
+
// Encrypt request (returns context for response decryption)
|
|
98
|
+
// For bodyless requests, context will be null and request passes through unmodified
|
|
99
|
+
const { request: encryptedRequest, context } = await this.serverIdentity.encryptRequestWithContext(request);
|
|
118
100
|
// Make the request
|
|
119
|
-
const response = await fetch(
|
|
101
|
+
const response = await fetch(encryptedRequest);
|
|
120
102
|
if (!response.ok) {
|
|
121
103
|
console.warn(`Server returned non-OK status: ${response.status}`);
|
|
122
104
|
}
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
105
|
+
// Bodyless requests: context is null, response is plaintext
|
|
106
|
+
if (context === null) {
|
|
107
|
+
return response;
|
|
108
|
+
}
|
|
109
|
+
// Check for fallback header - if set, server returned unencrypted response
|
|
110
|
+
const fallbackHeader = response.headers.get(protocol_js_1.PROTOCOL.FALLBACK_HEADER);
|
|
111
|
+
if (fallbackHeader === '1') {
|
|
112
|
+
return response;
|
|
113
|
+
}
|
|
114
|
+
// Check for response nonce header (required for response decryption)
|
|
115
|
+
const responseNonceHeader = response.headers.get(protocol_js_1.PROTOCOL.RESPONSE_NONCE_HEADER);
|
|
116
|
+
if (!responseNonceHeader) {
|
|
117
|
+
throw new Error(`Missing ${protocol_js_1.PROTOCOL.RESPONSE_NONCE_HEADER} header`);
|
|
127
118
|
}
|
|
128
|
-
// Decode encapsulated key
|
|
129
|
-
const serverEncapKey = new Uint8Array(encapKeyHeader.match(/.{2}/g).map(byte => parseInt(byte, 16)));
|
|
130
119
|
// Decrypt response
|
|
131
|
-
return await this.
|
|
120
|
+
return await this.serverIdentity.decryptResponseWithContext(response, context);
|
|
132
121
|
}
|
|
133
122
|
/**
|
|
134
123
|
* Convenience method for GET requests
|
|
@@ -157,9 +146,9 @@ class Transport {
|
|
|
157
146
|
}
|
|
158
147
|
exports.Transport = Transport;
|
|
159
148
|
/**
|
|
160
|
-
* Create a new transport instance
|
|
149
|
+
* Create a new transport instance.
|
|
161
150
|
*/
|
|
162
|
-
async function createTransport(serverURL
|
|
163
|
-
return Transport.create(serverURL
|
|
151
|
+
async function createTransport(serverURL) {
|
|
152
|
+
return Transport.create(serverURL);
|
|
164
153
|
}
|
|
165
154
|
//# sourceMappingURL=client.js.map
|
package/dist/cjs/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":";;;AA+KA,0CAEC;AAjLD,+CAAyC;AACzC,+CAAyC;AAGzC;;GAEG;AACH,MAAa,SAAS;IACZ,cAAc,CAAW;IACzB,UAAU,CAAS;IAE3B,YAAY,cAAwB,EAAE,UAAkB;QACtD,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAiB;QACnC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/B,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,CAAC;QAE5B,0BAA0B;QAC1B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,sBAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACvD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEjD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACzD,IAAI,WAAW,KAAK,sBAAQ,CAAC,eAAe,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,yBAAyB,WAAW,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9D,MAAM,cAAc,GAAG,MAAM,sBAAQ,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAEtE,OAAO,IAAI,SAAS,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,iBAAiB;QACf,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,OAAO,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,qBAAqB;QACzB,OAAO,IAAI,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,KAAwB,EAAE,IAAkB;QACxD,gDAAgD;QAChD,MAAM,QAAQ,GAAG,KAAK,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACjE,OAAO,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC5B,CAAC;QAED,4EAA4E;QAC5E,IAAI,WAAW,GAAoB,IAAI,CAAC;QAExC,IAAI,KAAK,YAAY,OAAO,EAAE,CAAC;YAC7B,0CAA0C;YAC1C,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBACf,WAAW,GAAG,MAAM,KAAK,CAAC,WAAW,EAAE,CAAC;YAC1C,CAAC;QACH,CAAC;aAAM,CAAC;YACN,6CAA6C;YAC7C,WAAW,GAAG,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC;QACnC,CAAC;QAED,mCAAmC;QACnC,IAAI,GAAQ,CAAC;QACb,IAAI,MAAc,CAAC;QACnB,IAAI,OAAoB,CAAC;QAEzB,IAAI,KAAK,YAAY,OAAO,EAAE,CAAC;YAC7B,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACzB,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YACtB,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;YACrB,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC;YAC/B,OAAO,GAAG,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC;QAChC,CAAC;QAED,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;QAE3B,IAAI,OAAO,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YACxC,MAAM;YACN,OAAO;YACP,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,MAAM;SACA,CAAC,CAAC;QAElB,4DAA4D;QAC5D,oFAAoF;QACpF,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAC1C,MAAM,IAAI,CAAC,cAAc,CAAC,yBAAyB,CAAC,OAAO,CAAC,CAAC;QAE/D,mBAAmB;QACnB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAE/C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,kCAAkC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACpE,CAAC;QAED,4DAA4D;QAC5D,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,2EAA2E;QAC3E,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAQ,CAAC,eAAe,CAAC,CAAC;QACtE,IAAI,cAAc,KAAK,GAAG,EAAE,CAAC;YAC3B,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,qEAAqE;QACrE,MAAM,mBAAmB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAQ,CAAC,qBAAqB,CAAC,CAAC;QACjF,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,WAAW,sBAAQ,CAAC,qBAAqB,SAAS,CAAC,CAAC;QACtE,CAAC;QAED,mBAAmB;QACnB,OAAO,MAAM,IAAI,CAAC,cAAc,CAAC,0BAA0B,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,GAAiB,EAAE,IAAkB;QAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACvD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,GAAiB,EAAE,IAAe,EAAE,IAAkB;QAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,GAAiB,EAAE,IAAe,EAAE,IAAkB;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,GAAiB,EAAE,IAAkB;QAChD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1D,CAAC;CACF;AAnKD,8BAmKC;AAED;;GAEG;AACI,KAAK,UAAU,eAAe,CAAC,SAAiB;IACrD,OAAO,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -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,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Response key derivation for EHBP
|
|
4
|
+
*
|
|
5
|
+
* This module implements the key derivation matching the Go implementation.
|
|
6
|
+
*
|
|
7
|
+
* The derivation follows OHTTP (RFC 9458):
|
|
8
|
+
* salt = concat(enc, response_nonce)
|
|
9
|
+
* prk = Extract(salt, secret)
|
|
10
|
+
* aead_key = Expand(prk, "key", Nk)
|
|
11
|
+
* aead_nonce = Expand(prk, "nonce", Nn)
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.REQUEST_ENC_LENGTH = exports.AES_GCM_NONCE_LENGTH = exports.AES256_KEY_LENGTH = exports.RESPONSE_NONCE_LENGTH = exports.EXPORT_LENGTH = exports.EXPORT_LABEL = exports.HPKE_REQUEST_INFO = void 0;
|
|
15
|
+
exports.deriveResponseKeys = deriveResponseKeys;
|
|
16
|
+
exports.computeNonce = computeNonce;
|
|
17
|
+
exports.encryptChunk = encryptChunk;
|
|
18
|
+
exports.decryptChunk = decryptChunk;
|
|
19
|
+
exports.hexToBytes = hexToBytes;
|
|
20
|
+
exports.bytesToHex = bytesToHex;
|
|
21
|
+
const hpke_1 = require("hpke");
|
|
22
|
+
const kdf = (0, hpke_1.KDF_HKDF_SHA256)();
|
|
23
|
+
const aead = (0, hpke_1.AEAD_AES_256_GCM)();
|
|
24
|
+
exports.HPKE_REQUEST_INFO = 'ehbp request';
|
|
25
|
+
exports.EXPORT_LABEL = 'ehbp response';
|
|
26
|
+
exports.EXPORT_LENGTH = 32;
|
|
27
|
+
exports.RESPONSE_NONCE_LENGTH = 32; // max(Nn, Nk) = max(12, 32) = 32
|
|
28
|
+
exports.AES256_KEY_LENGTH = 32;
|
|
29
|
+
exports.AES_GCM_NONCE_LENGTH = 12;
|
|
30
|
+
exports.REQUEST_ENC_LENGTH = 32; // X25519 enc size
|
|
31
|
+
// Labels for HKDF-Expand
|
|
32
|
+
const RESPONSE_KEY_LABEL = new TextEncoder().encode('key');
|
|
33
|
+
const RESPONSE_NONCE_LABEL = new TextEncoder().encode('nonce');
|
|
34
|
+
/**
|
|
35
|
+
* Derives response encryption keys from the HPKE exported secret.
|
|
36
|
+
*
|
|
37
|
+
* salt = concat(enc, response_nonce)
|
|
38
|
+
* prk = Extract(salt, secret)
|
|
39
|
+
* key = Expand(prk, "key", 32)
|
|
40
|
+
* nonceBase = Expand(prk, "nonce", 12)
|
|
41
|
+
*
|
|
42
|
+
* @param exportedSecret - 32 bytes exported from HPKE context
|
|
43
|
+
* @param requestEnc - 32 bytes encapsulated key from request
|
|
44
|
+
* @param responseNonce - 32 bytes random nonce from response
|
|
45
|
+
* @returns Key material for response encryption/decryption
|
|
46
|
+
*/
|
|
47
|
+
async function deriveResponseKeys(exportedSecret, requestEnc, responseNonce) {
|
|
48
|
+
// Validate inputs
|
|
49
|
+
if (exportedSecret.length !== exports.EXPORT_LENGTH) {
|
|
50
|
+
throw new Error(`exported secret must be ${exports.EXPORT_LENGTH} bytes, got ${exportedSecret.length}`);
|
|
51
|
+
}
|
|
52
|
+
if (requestEnc.length !== exports.REQUEST_ENC_LENGTH) {
|
|
53
|
+
throw new Error(`request enc must be ${exports.REQUEST_ENC_LENGTH} bytes, got ${requestEnc.length}`);
|
|
54
|
+
}
|
|
55
|
+
if (responseNonce.length !== exports.RESPONSE_NONCE_LENGTH) {
|
|
56
|
+
throw new Error(`response nonce must be ${exports.RESPONSE_NONCE_LENGTH} bytes, got ${responseNonce.length}`);
|
|
57
|
+
}
|
|
58
|
+
// salt = concat(enc, response_nonce)
|
|
59
|
+
const salt = new Uint8Array(requestEnc.length + responseNonce.length);
|
|
60
|
+
salt.set(requestEnc, 0);
|
|
61
|
+
salt.set(responseNonce, requestEnc.length);
|
|
62
|
+
// prk = Extract(salt, secret)
|
|
63
|
+
const prk = await kdf.Extract(salt, exportedSecret);
|
|
64
|
+
// key = Expand(prk, "key", 32)
|
|
65
|
+
const keyBytes = await kdf.Expand(prk, RESPONSE_KEY_LABEL, exports.AES256_KEY_LENGTH);
|
|
66
|
+
// nonceBase = Expand(prk, "nonce", 12)
|
|
67
|
+
const nonceBase = await kdf.Expand(prk, RESPONSE_NONCE_LABEL, exports.AES_GCM_NONCE_LENGTH);
|
|
68
|
+
return { keyBytes, nonceBase };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Computes the nonce for a specific sequence number.
|
|
72
|
+
* nonce = nonceBase XOR sequence_number (big-endian in last 8 bytes)
|
|
73
|
+
*/
|
|
74
|
+
function computeNonce(nonceBase, seq) {
|
|
75
|
+
if (nonceBase.length !== exports.AES_GCM_NONCE_LENGTH) {
|
|
76
|
+
throw new Error(`nonce base must be ${exports.AES_GCM_NONCE_LENGTH} bytes`);
|
|
77
|
+
}
|
|
78
|
+
// Validate seq to prevent nonce reuse from integer overflow.
|
|
79
|
+
// JavaScript's >>> operator only works correctly for 32-bit unsigned integers.
|
|
80
|
+
// Values >= 2^32 wrap around (e.g., 2^32 >>> 0 === 0), causing nonce reuse.
|
|
81
|
+
// In practice, 2^32 chunks per response is impossible (~4PB minimum), but we validate defensively.
|
|
82
|
+
if (!Number.isInteger(seq) || seq < 0 || seq >= 0x100000000) {
|
|
83
|
+
throw new Error(`sequence number must be an integer in range [0, 2^32): got ${seq}`);
|
|
84
|
+
}
|
|
85
|
+
const nonce = new Uint8Array(exports.AES_GCM_NONCE_LENGTH);
|
|
86
|
+
nonce.set(nonceBase);
|
|
87
|
+
// XOR with sequence number in the last 8 bytes (big-endian)
|
|
88
|
+
for (let i = 0; i < 8; i++) {
|
|
89
|
+
const shift = i * 8;
|
|
90
|
+
if (shift < 32) {
|
|
91
|
+
nonce[exports.AES_GCM_NONCE_LENGTH - 1 - i] ^= (seq >>> shift) & 0xff;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return nonce;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Encrypts a chunk using the response key material
|
|
98
|
+
*/
|
|
99
|
+
async function encryptChunk(km, seq, plaintext) {
|
|
100
|
+
const nonce = computeNonce(km.nonceBase, seq);
|
|
101
|
+
const ciphertext = await aead.Seal(km.keyBytes, nonce, new Uint8Array(0), plaintext);
|
|
102
|
+
return ciphertext;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Decrypts a chunk using the response key material
|
|
106
|
+
*/
|
|
107
|
+
async function decryptChunk(km, seq, ciphertext) {
|
|
108
|
+
const nonce = computeNonce(km.nonceBase, seq);
|
|
109
|
+
const plaintext = await aead.Open(km.keyBytes, nonce, new Uint8Array(0), ciphertext);
|
|
110
|
+
return plaintext;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Utility: Convert hex string to Uint8Array
|
|
114
|
+
*/
|
|
115
|
+
function hexToBytes(hex) {
|
|
116
|
+
if (hex.length % 2 !== 0) {
|
|
117
|
+
throw new Error('Hex string must have even length');
|
|
118
|
+
}
|
|
119
|
+
if (!/^[0-9a-fA-F]*$/.test(hex)) {
|
|
120
|
+
throw new Error('Invalid hex character');
|
|
121
|
+
}
|
|
122
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
123
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
124
|
+
bytes[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);
|
|
125
|
+
}
|
|
126
|
+
return bytes;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Utility: Convert Uint8Array to hex string
|
|
130
|
+
*/
|
|
131
|
+
function bytesToHex(bytes) {
|
|
132
|
+
return Array.from(bytes)
|
|
133
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
134
|
+
.join('');
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=derive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../../src/derive.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AA0CH,gDA+BC;AAMD,oCAyBC;AAKD,oCAUC;AAKD,oCAUC;AAKD,gCAYC;AAKD,gCAIC;AA9JD,+BAA8E;AAE9E,MAAM,GAAG,GAAQ,IAAA,sBAAe,GAAE,CAAC;AACnC,MAAM,IAAI,GAAS,IAAA,uBAAgB,GAAE,CAAC;AAEzB,QAAA,iBAAiB,GAAG,cAAc,CAAC;AACnC,QAAA,YAAY,GAAG,eAAe,CAAC;AAC/B,QAAA,aAAa,GAAG,EAAE,CAAC;AACnB,QAAA,qBAAqB,GAAG,EAAE,CAAC,CAAC,iCAAiC;AAC7D,QAAA,iBAAiB,GAAG,EAAE,CAAC;AACvB,QAAA,oBAAoB,GAAG,EAAE,CAAC;AAC1B,QAAA,kBAAkB,GAAG,EAAE,CAAC,CAAC,kBAAkB;AAExD,yBAAyB;AACzB,MAAM,kBAAkB,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC3D,MAAM,oBAAoB,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAY/D;;;;;;;;;;;;GAYG;AACI,KAAK,UAAU,kBAAkB,CACtC,cAA0B,EAC1B,UAAsB,EACtB,aAAyB;IAEzB,kBAAkB;IAClB,IAAI,cAAc,CAAC,MAAM,KAAK,qBAAa,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,2BAA2B,qBAAa,eAAe,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC;IAClG,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,KAAK,0BAAkB,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,uBAAuB,0BAAkB,eAAe,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/F,CAAC;IACD,IAAI,aAAa,CAAC,MAAM,KAAK,6BAAqB,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,0BAA0B,6BAAqB,eAAe,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;IACxG,CAAC;IAED,qCAAqC;IACrC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACtE,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IACxB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAE3C,8BAA8B;IAC9B,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAEpD,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,kBAAkB,EAAE,yBAAiB,CAAC,CAAC;IAE9E,uCAAuC;IACvC,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,oBAAoB,EAAE,4BAAoB,CAAC,CAAC;IAEpF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,SAAqB,EAAE,GAAW;IAC7D,IAAI,SAAS,CAAC,MAAM,KAAK,4BAAoB,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,sBAAsB,4BAAoB,QAAQ,CAAC,CAAC;IACtE,CAAC;IAED,6DAA6D;IAC7D,+EAA+E;IAC/E,4EAA4E;IAC5E,mGAAmG;IACnG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,8DAA8D,GAAG,EAAE,CAAC,CAAC;IACvF,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,4BAAoB,CAAC,CAAC;IACnD,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAErB,4DAA4D;IAC5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;QACpB,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;YACf,KAAK,CAAC,4BAAoB,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG,IAAI,CAAC;QAChE,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,YAAY,CAChC,EAAuB,EACvB,GAAW,EACX,SAAqB;IAErB,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAE9C,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAErF,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,YAAY,CAChC,EAAuB,EACvB,GAAW,EACX,UAAsB;IAEtB,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAE9C,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAErF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAgB,UAAU,CAAC,GAAW;IACpC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,SAAgB,UAAU,CAAC,KAAiB;IAC1C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;SACrB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SACzC,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
|