@ubay182/sveltekit-hpke-wrapper 1.0.2 โ 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +180 -154
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,12 +4,12 @@ HPKE (Hybrid Public Key Encryption) wrapper for SvelteKit applications with end-
|
|
|
4
4
|
|
|
5
5
|
## ๐ Features
|
|
6
6
|
|
|
7
|
-
- โ
**Complete HPKE Implementation**
|
|
8
|
-
- โ
**End-to-End Encryption**
|
|
9
|
-
- โ
**SvelteKit Integration**
|
|
10
|
-
- โ
**TypeScript Support**
|
|
11
|
-
- โ
**X25519 Key Exchange**
|
|
12
|
-
- โ
**AES-128-GCM & ChaCha20**
|
|
7
|
+
- โ
**Complete HPKE Implementation** โ RFC 9180 compliant
|
|
8
|
+
- โ
**End-to-End Encryption** โ Client โ Server encryption
|
|
9
|
+
- โ
**SvelteKit Integration** โ Ready-to-use API endpoint creators
|
|
10
|
+
- โ
**TypeScript Support** โ Full type definitions
|
|
11
|
+
- โ
**X25519 Key Exchange** โ Elliptic curve Diffie-Hellman
|
|
12
|
+
- โ
**AES-128-GCM & ChaCha20-Poly1305** โ Authenticated encryption
|
|
13
13
|
|
|
14
14
|
## ๐ฆ Installation
|
|
15
15
|
|
|
@@ -17,76 +17,128 @@ HPKE (Hybrid Public Key Encryption) wrapper for SvelteKit applications with end-
|
|
|
17
17
|
npm install @ubay182/sveltekit-hpke-wrapper
|
|
18
18
|
# or
|
|
19
19
|
pnpm add @ubay182/sveltekit-hpke-wrapper
|
|
20
|
-
# or
|
|
21
|
-
yarn add @ubay182/sveltekit-hpke-wrapper
|
|
22
20
|
```
|
|
23
21
|
|
|
24
22
|
## ๐ฏ Quick Start
|
|
25
23
|
|
|
26
|
-
### 1.
|
|
24
|
+
### 1. Client-Side (Svelte Component)
|
|
25
|
+
|
|
26
|
+
```svelte
|
|
27
|
+
<script lang="ts">
|
|
28
|
+
import {
|
|
29
|
+
generateKeyPair,
|
|
30
|
+
hpkeEncrypt,
|
|
31
|
+
hpkeDecrypt,
|
|
32
|
+
uint8ArrayToBase64,
|
|
33
|
+
base64ToUint8Array,
|
|
34
|
+
createHpkeSuite
|
|
35
|
+
} from '@ubay182/sveltekit-hpke-wrapper';
|
|
36
|
+
|
|
37
|
+
let serverPubKey = $state<any>(null);
|
|
38
|
+
let clientPrivKey = $state<any>(null);
|
|
39
|
+
let clientPubKeyB64 = $state('');
|
|
40
|
+
let decryptedText = $state('');
|
|
41
|
+
|
|
42
|
+
// Step 1: Fetch server public key
|
|
43
|
+
async function getServerKey() {
|
|
44
|
+
const res = await fetch('/api/hpke-keys');
|
|
45
|
+
const data = await res.json();
|
|
46
|
+
|
|
47
|
+
const keyBytes = base64ToUint8Array(data.publicKey);
|
|
48
|
+
const suite = createHpkeSuite();
|
|
49
|
+
serverPubKey = await suite.kem.importKey('raw', keyBytes.buffer as ArrayBuffer, true);
|
|
50
|
+
}
|
|
27
51
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
importKeyFromBase64
|
|
35
|
-
} from '@ubay182/sveltekit-hpke-wrapper';
|
|
52
|
+
// Step 2: Generate client key pair
|
|
53
|
+
async function generateClientKeys() {
|
|
54
|
+
const keys = await generateKeyPair();
|
|
55
|
+
clientPrivKey = keys.privateKey;
|
|
56
|
+
clientPubKeyB64 = uint8ArrayToBase64(keys.publicKeyRaw);
|
|
57
|
+
}
|
|
36
58
|
|
|
37
|
-
//
|
|
38
|
-
|
|
59
|
+
// Step 3: Encrypt & send
|
|
60
|
+
async function encryptAndSend(payload: any) {
|
|
61
|
+
const message = JSON.stringify(payload);
|
|
62
|
+
const result = await hpkeEncrypt(message, serverPubKey);
|
|
39
63
|
|
|
40
|
-
|
|
41
|
-
const
|
|
64
|
+
const ciphertext = uint8ArrayToBase64(new Uint8Array(result.ciphertext));
|
|
65
|
+
const enc = uint8ArrayToBase64(new Uint8Array(result.enc));
|
|
42
66
|
|
|
43
|
-
|
|
44
|
-
|
|
67
|
+
const res = await fetch('/api/hpke-proxy', {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: { 'Content-Type': 'application/json' },
|
|
70
|
+
body: JSON.stringify({ ciphertext, enc, clientPublicKey: clientPubKeyB64 })
|
|
71
|
+
});
|
|
45
72
|
|
|
46
|
-
|
|
47
|
-
|
|
73
|
+
const data = await res.json();
|
|
74
|
+
return data; // { ciphertext, enc }
|
|
75
|
+
}
|
|
48
76
|
|
|
49
|
-
// Decrypt
|
|
50
|
-
|
|
51
|
-
|
|
77
|
+
// Step 4: Decrypt server response
|
|
78
|
+
async function decryptResponse(encryptedData: { ciphertext: string; enc: string }) {
|
|
79
|
+
const ct = base64ToUint8Array(encryptedData.ciphertext);
|
|
80
|
+
const enc = base64ToUint8Array(encryptedData.enc);
|
|
52
81
|
|
|
53
|
-
|
|
82
|
+
decryptedText = await hpkeDecrypt(
|
|
83
|
+
ct.buffer as ArrayBuffer,
|
|
84
|
+
enc.buffer as ArrayBuffer,
|
|
85
|
+
clientPrivKey
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
</script>
|
|
89
|
+
```
|
|
54
90
|
|
|
55
|
-
|
|
56
|
-
// src/routes/api/hpke/+server.ts
|
|
57
|
-
import { createHpkeEndpoint } from '@ubay182/sveltekit-hpke-wrapper';
|
|
91
|
+
### 2. Server-Side (SvelteKit Routes)
|
|
58
92
|
|
|
59
|
-
|
|
60
|
-
onRequest: async (decryptedData, request) => {
|
|
61
|
-
// Process the decrypted request
|
|
62
|
-
const response = await fetch('https://api.example.com/data', {
|
|
63
|
-
method: 'POST',
|
|
64
|
-
headers: { 'Content-Type': 'application/json' },
|
|
65
|
-
body: JSON.stringify(decryptedData)
|
|
66
|
-
});
|
|
93
|
+
Create a shared HPKE server instance so all routes use the same key pair:
|
|
67
94
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
95
|
+
```typescript
|
|
96
|
+
// src/lib/hpke-server-instance.ts
|
|
97
|
+
import { createHpkeServer, type HpkeServerInstance } from '@ubay182/sveltekit-hpke-wrapper';
|
|
71
98
|
|
|
72
|
-
export {
|
|
99
|
+
export const hpkeServer: HpkeServerInstance = createHpkeServer({ autoGenerateKeys: false });
|
|
73
100
|
```
|
|
74
101
|
|
|
75
|
-
|
|
102
|
+
```typescript
|
|
103
|
+
// src/routes/api/hpke-keys/+server.ts
|
|
104
|
+
import { hpkeServer } from '$lib/hpke-server-instance';
|
|
105
|
+
|
|
106
|
+
export async function GET() {
|
|
107
|
+
const publicKey = await hpkeServer.init();
|
|
108
|
+
|
|
109
|
+
return new Response(
|
|
110
|
+
JSON.stringify({
|
|
111
|
+
publicKey,
|
|
112
|
+
algorithm: 'X25519-HKDF-SHA256',
|
|
113
|
+
aead: 'AES-128-GCM'
|
|
114
|
+
}),
|
|
115
|
+
{
|
|
116
|
+
headers: { 'Content-Type': 'application/json' }
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
76
121
|
|
|
77
122
|
```typescript
|
|
78
|
-
|
|
123
|
+
// src/routes/api/hpke-proxy/+server.ts
|
|
124
|
+
import { hpkeServer } from '$lib/hpke-server-instance';
|
|
125
|
+
|
|
126
|
+
export async function POST({ request }: { request: Request }) {
|
|
127
|
+
const body = await request.json();
|
|
128
|
+
const { ciphertext, enc, clientPublicKey } = body;
|
|
79
129
|
|
|
80
|
-
|
|
130
|
+
// Decrypt client message
|
|
131
|
+
const decrypted = await hpkeServer.decrypt(ciphertext, enc, clientPublicKey);
|
|
81
132
|
|
|
82
|
-
//
|
|
83
|
-
const publicKey = server.getPublicKeyBase64();
|
|
133
|
+
// ... process decrypted data, call external APIs, etc. ...
|
|
84
134
|
|
|
85
|
-
//
|
|
86
|
-
const
|
|
135
|
+
// Encrypt response
|
|
136
|
+
const encrypted = await hpkeServer.encrypt(responseData, clientPublicKey);
|
|
87
137
|
|
|
88
|
-
|
|
89
|
-
|
|
138
|
+
return new Response(JSON.stringify(encrypted), {
|
|
139
|
+
headers: { 'Content-Type': 'application/json' }
|
|
140
|
+
});
|
|
141
|
+
}
|
|
90
142
|
```
|
|
91
143
|
|
|
92
144
|
## ๐ API Reference
|
|
@@ -99,59 +151,76 @@ Generate a new HPKE key pair.
|
|
|
99
151
|
|
|
100
152
|
```typescript
|
|
101
153
|
async function generateKeyPair(): Promise<{
|
|
102
|
-
publicKey: any; // XCryptoKey
|
|
103
|
-
privateKey: any; // XCryptoKey
|
|
154
|
+
publicKey: any; // XCryptoKey
|
|
155
|
+
privateKey: any; // XCryptoKey
|
|
104
156
|
publicKeyRaw: Uint8Array; // Raw bytes for transmission
|
|
105
157
|
}>;
|
|
106
158
|
```
|
|
107
159
|
|
|
108
160
|
#### `hpkeEncrypt(message, recipientPublicKey)`
|
|
109
161
|
|
|
110
|
-
Encrypt a message.
|
|
162
|
+
Encrypt a message. Returns `{ ciphertext: ArrayBuffer, enc: ArrayBuffer }`.
|
|
111
163
|
|
|
112
164
|
```typescript
|
|
113
|
-
|
|
114
|
-
message: string,
|
|
115
|
-
recipientPublicKey: any
|
|
116
|
-
): Promise<{
|
|
117
|
-
ciphertext: ArrayBuffer;
|
|
118
|
-
enc: ArrayBuffer;
|
|
119
|
-
}>;
|
|
165
|
+
const { ciphertext, enc } = await hpkeEncrypt('Secret message', serverPublicKey);
|
|
120
166
|
```
|
|
121
167
|
|
|
122
168
|
#### `hpkeDecrypt(ciphertext, enc, recipientPrivateKey)`
|
|
123
169
|
|
|
124
|
-
Decrypt a message.
|
|
170
|
+
Decrypt a message. Returns plaintext string.
|
|
125
171
|
|
|
126
172
|
```typescript
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
173
|
+
const decrypted = await hpkeDecrypt(ciphertextBuffer, encBuffer, privateKey);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### `createHpkeSuite()`
|
|
177
|
+
|
|
178
|
+
Create an HPKE suite with AES-128-GCM.
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const suite = createHpkeSuite();
|
|
182
|
+
const keyPair = await suite.kem.generateKeyPair();
|
|
183
|
+
const importedKey = await suite.kem.importKey('raw', keyBytes.buffer, true);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### `createHpkeSuiteChaCha20()`
|
|
187
|
+
|
|
188
|
+
Create an HPKE suite with ChaCha20-Poly1305.
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
const suite = createHpkeSuiteChaCha20();
|
|
132
192
|
```
|
|
133
193
|
|
|
134
194
|
#### `exportKeyToBase64(publicKey)`
|
|
135
195
|
|
|
136
|
-
Export public key to base64.
|
|
196
|
+
Export public key to base64 string.
|
|
137
197
|
|
|
138
198
|
```typescript
|
|
139
|
-
|
|
199
|
+
const b64 = exportKeyToBase64(publicKey);
|
|
140
200
|
```
|
|
141
201
|
|
|
142
202
|
#### `importKeyFromBase64(base64)`
|
|
143
203
|
|
|
144
|
-
Import public key from base64.
|
|
204
|
+
Import public key from base64 string.
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
const publicKey = await importKeyFromBase64(b64String);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
#### `uint8ArrayToBase64(data)` / `base64ToUint8Array(base64)`
|
|
211
|
+
|
|
212
|
+
Utility functions for encoding/decoding.
|
|
145
213
|
|
|
146
214
|
```typescript
|
|
147
|
-
|
|
215
|
+
const b64 = uint8ArrayToBase64(bytes);
|
|
216
|
+
const bytes = base64ToUint8Array(b64);
|
|
148
217
|
```
|
|
149
218
|
|
|
150
219
|
### Server Functions
|
|
151
220
|
|
|
152
221
|
#### `createHpkeServer(config?)`
|
|
153
222
|
|
|
154
|
-
Create HPKE server instance.
|
|
223
|
+
Create an HPKE server instance with key management.
|
|
155
224
|
|
|
156
225
|
```typescript
|
|
157
226
|
interface HpkeServerConfig {
|
|
@@ -159,15 +228,10 @@ interface HpkeServerConfig {
|
|
|
159
228
|
}
|
|
160
229
|
|
|
161
230
|
interface HpkeServerInstance {
|
|
231
|
+
init(): Promise<string>; // Generate keys, return public key as base64
|
|
162
232
|
getPublicKeyBase64(): string;
|
|
163
233
|
decrypt(ciphertext: string, enc: string, clientPublicKey: string): Promise<string>;
|
|
164
|
-
encrypt(
|
|
165
|
-
message: string,
|
|
166
|
-
clientPublicKey: string
|
|
167
|
-
): Promise<{
|
|
168
|
-
ciphertext: string;
|
|
169
|
-
enc: string;
|
|
170
|
-
}>;
|
|
234
|
+
encrypt(message: string, clientPublicKey: string): Promise<{ ciphertext: string; enc: string }>;
|
|
171
235
|
}
|
|
172
236
|
```
|
|
173
237
|
|
|
@@ -175,93 +239,59 @@ interface HpkeServerInstance {
|
|
|
175
239
|
|
|
176
240
|
#### `createHpkeEndpoint(config?)`
|
|
177
241
|
|
|
178
|
-
Create complete
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
interface HpkeEndpointConfig {
|
|
182
|
-
autoGenerateKeys?: boolean;
|
|
183
|
-
onRequest?: (decrypted: any, request: Request) => Promise<any>;
|
|
184
|
-
onError?: (error: Error, request: Request) => Promise<Response>;
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
## ๐ง Advanced Usage
|
|
189
|
-
|
|
190
|
-
### Custom Algorithm (ChaCha20-Poly1305)
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
import { createHpkeSuiteChaCha20 } from '@ubay182/sveltekit-hpke-wrapper';
|
|
194
|
-
|
|
195
|
-
const suite = createHpkeSuiteChaCha20();
|
|
196
|
-
// Use suite for encryption/decryption
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Manual Key Management
|
|
200
|
-
|
|
201
|
-
```typescript
|
|
202
|
-
import { createHpkeServer } from '@ubay182/sveltekit-hpke-wrapper';
|
|
203
|
-
|
|
204
|
-
// Disable auto-generation
|
|
205
|
-
const server = createHpkeServer({ autoGenerateKeys: false });
|
|
206
|
-
|
|
207
|
-
// Set keys manually later
|
|
208
|
-
// (You'll need to extend the server instance with a setKeys method)
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### Error Handling
|
|
242
|
+
Create complete GET/POST handlers for a SvelteKit route.
|
|
212
243
|
|
|
213
244
|
```typescript
|
|
214
245
|
const { GET, POST } = createHpkeEndpoint({
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
JSON.stringify(
|
|
220
|
-
|
|
221
|
-
code: 'HPKE_ERROR'
|
|
222
|
-
}),
|
|
223
|
-
{ status: 500 }
|
|
224
|
-
);
|
|
246
|
+
onRequest: async (decryptedData, request) => {
|
|
247
|
+
// Process decrypted request
|
|
248
|
+
return await fetch('https://api.example.com/data', {
|
|
249
|
+
method: 'POST',
|
|
250
|
+
body: JSON.stringify(decryptedData)
|
|
251
|
+
}).then((r) => r.json());
|
|
225
252
|
}
|
|
226
253
|
});
|
|
227
254
|
```
|
|
228
255
|
|
|
229
|
-
## ๐
|
|
230
|
-
|
|
231
|
-
โ ๏ธ **Important**: This is a wrapper library for convenience. For production:
|
|
232
|
-
|
|
233
|
-
1. **Key Storage**: Use HSM, AWS KMS, or Azure Key Vault
|
|
234
|
-
2. **HTTPS**: Always use HTTPS in production
|
|
235
|
-
3. **Authentication**: Implement proper auth mechanisms
|
|
236
|
-
4. **Rate Limiting**: Add rate limiting to prevent abuse
|
|
237
|
-
5. **Key Rotation**: Implement regular key rotation
|
|
238
|
-
6. **Audit**: Have security audits performed
|
|
239
|
-
|
|
240
|
-
## ๐ How It Works
|
|
256
|
+
## ๐ How It Works
|
|
241
257
|
|
|
242
258
|
```
|
|
243
259
|
Client Server
|
|
244
260
|
โ โ
|
|
245
|
-
โโโโ GET /api/hpke
|
|
261
|
+
โโโโ GET /api/hpke-keys โโโโโโ>โ
|
|
246
262
|
โ โ
|
|
247
263
|
โ<โโโโ Public Key (base64) โโโโโ
|
|
248
264
|
โ โ
|
|
249
|
-
โโโโ
|
|
265
|
+
โโโโ generateKeyPair() โโโโโโโโโ (client generates its own keys)
|
|
266
|
+
โ โ
|
|
267
|
+
โโโโ hpkeEncrypt(payload) โโโโโ
|
|
250
268
|
โ โ
|
|
251
|
-
โโโโ POST
|
|
269
|
+
โโโโ POST { ciphertext, enc, โ>โ
|
|
270
|
+
โ clientPublicKey } โ
|
|
252
271
|
โ โ
|
|
253
|
-
โ โโโโ
|
|
254
|
-
โ โ
|
|
255
|
-
โ โ<โโ Process
|
|
272
|
+
โ โโโโ decrypt() โโโ
|
|
273
|
+
โ โ โ
|
|
274
|
+
โ โ<โโ Process โโโโโโ
|
|
275
|
+
โ โ โ
|
|
276
|
+
โ โ<โโ encrypt() โโโโ
|
|
256
277
|
โ โ
|
|
257
|
-
|
|
258
|
-
โ โ โ
|
|
259
|
-
โ<โโโโ Encrypted Response โโโโโโ<โโโโโโโโโโโโโโโ
|
|
278
|
+
โ<โโโโ { ciphertext, enc } โโโโโ
|
|
260
279
|
โ โ
|
|
261
|
-
โโโโ
|
|
280
|
+
โโโโ hpkeDecrypt(response) โโโโโ
|
|
262
281
|
```
|
|
263
282
|
|
|
264
|
-
##
|
|
283
|
+
## ๐ Security Notes
|
|
284
|
+
|
|
285
|
+
โ ๏ธ **Important**: This is a convenience wrapper library. For production:
|
|
286
|
+
|
|
287
|
+
1. **Key Storage** โ Use HSM, AWS KMS, or Azure Key Vault
|
|
288
|
+
2. **HTTPS** โ Always use HTTPS in production
|
|
289
|
+
3. **Authentication** โ Implement proper auth mechanisms
|
|
290
|
+
4. **Rate Limiting** โ Add rate limiting to prevent abuse
|
|
291
|
+
5. **Key Rotation** โ Implement regular key rotation
|
|
292
|
+
6. **Audit** โ Have security audits performed
|
|
293
|
+
|
|
294
|
+
## ๐งช Development
|
|
265
295
|
|
|
266
296
|
```bash
|
|
267
297
|
# Build the package
|
|
@@ -270,7 +300,7 @@ npm run build
|
|
|
270
300
|
# Type check
|
|
271
301
|
npm run lint
|
|
272
302
|
|
|
273
|
-
# Watch mode
|
|
303
|
+
# Watch mode
|
|
274
304
|
npm run dev
|
|
275
305
|
```
|
|
276
306
|
|
|
@@ -278,12 +308,8 @@ npm run dev
|
|
|
278
308
|
|
|
279
309
|
MIT
|
|
280
310
|
|
|
281
|
-
## ๐ค Contributing
|
|
282
|
-
|
|
283
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
284
|
-
|
|
285
311
|
## ๐ Resources
|
|
286
312
|
|
|
287
|
-
- [RFC 9180
|
|
313
|
+
- [RFC 9180 โ HPKE Specification](https://www.rfc-editor.org/rfc/rfc9180.html)
|
|
288
314
|
- [hpke-js Library](https://github.com/dajiaji/hpke-js)
|
|
289
315
|
- [SvelteKit Documentation](https://kit.svelte.dev/docs)
|
package/package.json
CHANGED