@sebastienrousseau/crypto-sdk 0.0.8 → 0.0.24
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 +114 -58
- package/dist/errors.d.ts +8 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/index.d.ts +69 -241
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +102 -139
- package/dist/key-types.d.ts +203 -0
- package/dist/key-types.d.ts.map +1 -0
- package/dist/key-types.js +3 -0
- package/dist/negotiation.d.ts +3 -0
- package/dist/negotiation.d.ts.map +1 -0
- package/dist/negotiation.js +105 -0
- package/dist/request.d.ts +15 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +111 -0
- package/dist/types.d.ts +183 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/package.json +17 -13
package/dist/index.js
CHANGED
|
@@ -1,35 +1,50 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
17
|
+
exports.CryptoClient = exports.CryptoApiError = void 0;
|
|
18
|
+
const negotiation_1 = require("./negotiation");
|
|
19
|
+
const request_1 = require("./request");
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
__exportStar(require("./key-types"), exports);
|
|
22
|
+
var errors_1 = require("./errors");
|
|
23
|
+
Object.defineProperty(exports, "CryptoApiError", { enumerable: true, get: function () { return errors_1.CryptoApiError; } });
|
|
4
24
|
class CryptoClient {
|
|
5
25
|
baseUrl;
|
|
6
26
|
headers;
|
|
7
27
|
fetchFn;
|
|
28
|
+
timeout;
|
|
29
|
+
retry;
|
|
30
|
+
autoTraceparent = false;
|
|
8
31
|
constructor(options) {
|
|
9
32
|
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
10
33
|
this.fetchFn = options.fetch ?? globalThis.fetch;
|
|
11
|
-
this.headers =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const init =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
init.body = JSON.stringify(body);
|
|
26
|
-
}
|
|
27
|
-
const res = await this.fetchFn(`${this.baseUrl}${path}`, init);
|
|
28
|
-
const json = await res.json();
|
|
29
|
-
if (!res.ok) {
|
|
30
|
-
throw new CryptoApiError(res.status, json);
|
|
31
|
-
}
|
|
32
|
-
return json;
|
|
34
|
+
this.headers = (0, request_1.buildClientHeaders)(options);
|
|
35
|
+
this.timeout = options.timeout;
|
|
36
|
+
this.retry = (0, request_1.resolveRetryConfig)(options.retry);
|
|
37
|
+
this.autoTraceparent = options.traceparent === true;
|
|
38
|
+
}
|
|
39
|
+
async send(method, path, body) {
|
|
40
|
+
const headers = this.autoTraceparent
|
|
41
|
+
? { ...this.headers, traceparent: (0, request_1.generateSdkTraceparent)() }
|
|
42
|
+
: this.headers;
|
|
43
|
+
const init = (0, request_1.buildRequestInit)(method, headers, body, this.timeout);
|
|
44
|
+
return (0, request_1.executeRequest)(this.fetchFn, `${this.baseUrl}${path}`, init, this.retry);
|
|
45
|
+
}
|
|
46
|
+
request(method, path, body) {
|
|
47
|
+
return this.send(method, path, body);
|
|
33
48
|
}
|
|
34
49
|
async encrypt(params) {
|
|
35
50
|
return this.request("POST", "/v2/encrypt", params);
|
|
@@ -58,14 +73,26 @@ class CryptoClient {
|
|
|
58
73
|
async generateKeyPair(params) {
|
|
59
74
|
return this.request("POST", "/v2/keys/generate", params ?? { algorithm: "ed25519" });
|
|
60
75
|
}
|
|
76
|
+
async exportKey(params) {
|
|
77
|
+
return this.request("POST", "/v2/keys/export", params);
|
|
78
|
+
}
|
|
61
79
|
async sign(params) {
|
|
62
80
|
return this.request("POST", "/v2/sign", params);
|
|
63
81
|
}
|
|
64
82
|
async verify(params) {
|
|
65
83
|
return this.request("POST", "/v2/verify", params);
|
|
66
84
|
}
|
|
67
|
-
async
|
|
68
|
-
return this.request("POST", "/v2/pq/
|
|
85
|
+
async mlKemGenerateKeyPair(params = {}) {
|
|
86
|
+
return this.request("POST", "/v2/pq/keygen", params);
|
|
87
|
+
}
|
|
88
|
+
async mlKemEncapsulate(params) {
|
|
89
|
+
return this.request("POST", "/v2/pq/encapsulate", params);
|
|
90
|
+
}
|
|
91
|
+
async mlKemDecapsulate(params) {
|
|
92
|
+
return this.request("POST", "/v2/pq/decapsulate", params);
|
|
93
|
+
}
|
|
94
|
+
async pqGenerateKeyPair(params = {}) {
|
|
95
|
+
return this.request("POST", "/v2/pq/hybrid/keygen", params);
|
|
69
96
|
}
|
|
70
97
|
async pqEncapsulate(params) {
|
|
71
98
|
return this.request("POST", "/v2/pq/hybrid/encapsulate", params);
|
|
@@ -83,13 +110,13 @@ class CryptoClient {
|
|
|
83
110
|
return this.request("POST", "/v2/pq/dsa/keygen", params);
|
|
84
111
|
}
|
|
85
112
|
async pqHashSign(params) {
|
|
86
|
-
return this.request("POST", "/v2/pq/
|
|
113
|
+
return this.request("POST", "/v2/pq/slh-dsa/sign", params);
|
|
87
114
|
}
|
|
88
115
|
async pqHashVerify(params) {
|
|
89
|
-
return this.request("POST", "/v2/pq/
|
|
116
|
+
return this.request("POST", "/v2/pq/slh-dsa/verify", params);
|
|
90
117
|
}
|
|
91
118
|
async pqHashSignKeygen(params) {
|
|
92
|
-
return this.request("POST", "/v2/pq/
|
|
119
|
+
return this.request("POST", "/v2/pq/slh-dsa/keygen", params);
|
|
93
120
|
}
|
|
94
121
|
async secretboxSeal(params) {
|
|
95
122
|
return this.request("POST", "/v2/secretbox/seal", params);
|
|
@@ -103,124 +130,71 @@ class CryptoClient {
|
|
|
103
130
|
async sealedboxOpen(params) {
|
|
104
131
|
return this.request("POST", "/v2/sealedbox/open", params);
|
|
105
132
|
}
|
|
133
|
+
async sealedboxSealPq(params) {
|
|
134
|
+
return this.request("POST", "/v2/sealedbox/seal-pq", params);
|
|
135
|
+
}
|
|
136
|
+
async sealedboxOpenPq(params) {
|
|
137
|
+
return this.request("POST", "/v2/sealedbox/open-pq", params);
|
|
138
|
+
}
|
|
139
|
+
async streamPqEncrypt(params) {
|
|
140
|
+
return this.request("POST", "/v2/stream/pq-encrypt", params);
|
|
141
|
+
}
|
|
142
|
+
async streamPqDecrypt(params) {
|
|
143
|
+
return this.request("POST", "/v2/stream/pq-decrypt", params);
|
|
144
|
+
}
|
|
145
|
+
async streamMultiPqEncrypt(params) {
|
|
146
|
+
return this.request("POST", "/v2/stream/multi-pq-encrypt", params);
|
|
147
|
+
}
|
|
148
|
+
async streamMultiPqDecrypt(params) {
|
|
149
|
+
return this.request("POST", "/v2/stream/multi-pq-decrypt", params);
|
|
150
|
+
}
|
|
106
151
|
async passwordEncrypt(params) {
|
|
107
152
|
return this.request("POST", "/v2/password/encrypt", params);
|
|
108
153
|
}
|
|
109
154
|
async passwordDecrypt(params) {
|
|
110
155
|
return this.request("POST", "/v2/password/decrypt", params);
|
|
111
156
|
}
|
|
157
|
+
async hpkeGenerateKeyPair(params = {}) {
|
|
158
|
+
return this.request("POST", "/v2/hpke/keygen", params);
|
|
159
|
+
}
|
|
160
|
+
async hpkeSeal(params) {
|
|
161
|
+
return this.request("POST", "/v2/hpke/seal", params);
|
|
162
|
+
}
|
|
163
|
+
async hpkeOpen(params) {
|
|
164
|
+
return this.request("POST", "/v2/hpke/open", params);
|
|
165
|
+
}
|
|
112
166
|
async keyWrap(params) {
|
|
113
167
|
return this.request("POST", "/v2/keys/wrap", params);
|
|
114
168
|
}
|
|
115
169
|
async keyUnwrap(params) {
|
|
116
170
|
return this.request("POST", "/v2/keys/unwrap", params);
|
|
117
171
|
}
|
|
172
|
+
async kmsCreateKey(params = {}) {
|
|
173
|
+
return this.request("POST", "/v2/kms/create-key", params);
|
|
174
|
+
}
|
|
175
|
+
async kmsWrap(params) {
|
|
176
|
+
return this.request("POST", "/v2/kms/wrap", params);
|
|
177
|
+
}
|
|
178
|
+
async kmsUnwrap(params) {
|
|
179
|
+
return this.request("POST", "/v2/kms/unwrap", params);
|
|
180
|
+
}
|
|
181
|
+
async kmsGenerateDataKey(params) {
|
|
182
|
+
return this.request("POST", "/v2/kms/generate-data-key", params);
|
|
183
|
+
}
|
|
184
|
+
async kmsEncrypt(params) {
|
|
185
|
+
return this.request("POST", "/v2/kms/encrypt", params);
|
|
186
|
+
}
|
|
187
|
+
async kmsDecrypt(params) {
|
|
188
|
+
return this.request("POST", "/v2/kms/decrypt", params);
|
|
189
|
+
}
|
|
118
190
|
async getDoraCompliance() {
|
|
119
191
|
return this.request("GET", "/v2/compliance/dora");
|
|
120
192
|
}
|
|
121
193
|
async getCbom() {
|
|
122
|
-
return this.
|
|
194
|
+
return this.send("GET", "/v2/compliance/cbom");
|
|
123
195
|
}
|
|
124
196
|
negotiateAlgorithm(options = {}) {
|
|
125
|
-
|
|
126
|
-
const requireHybrid = options.requireHybrid ?? false;
|
|
127
|
-
const maxBytes = options.maxPayloadBytes ?? Infinity;
|
|
128
|
-
const clientAlgos = options.clientSupportedAlgorithms;
|
|
129
|
-
const catalog = [
|
|
130
|
-
{
|
|
131
|
-
name: "x448-mlkem1024",
|
|
132
|
-
category: "hybrid-kem",
|
|
133
|
-
level: 5,
|
|
134
|
-
isHybrid: true,
|
|
135
|
-
pk: 1624,
|
|
136
|
-
ct: 1624,
|
|
137
|
-
fips: "FIPS 203 + RFC 7748",
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
name: "ml-kem-1024",
|
|
141
|
-
category: "lattice-kem",
|
|
142
|
-
level: 5,
|
|
143
|
-
isHybrid: false,
|
|
144
|
-
pk: 1568,
|
|
145
|
-
ct: 1568,
|
|
146
|
-
fips: "FIPS 203",
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
name: "x25519-mlkem768",
|
|
150
|
-
category: "hybrid-kem",
|
|
151
|
-
level: 3,
|
|
152
|
-
isHybrid: true,
|
|
153
|
-
pk: 1216,
|
|
154
|
-
ct: 1120,
|
|
155
|
-
fips: "FIPS 203 + X25519 hybrid",
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
name: "ml-kem-768",
|
|
159
|
-
category: "lattice-kem",
|
|
160
|
-
level: 3,
|
|
161
|
-
isHybrid: false,
|
|
162
|
-
pk: 1184,
|
|
163
|
-
ct: 1088,
|
|
164
|
-
fips: "FIPS 203",
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
name: "x25519-mlkem512",
|
|
168
|
-
category: "hybrid-kem",
|
|
169
|
-
level: 1,
|
|
170
|
-
isHybrid: true,
|
|
171
|
-
pk: 832,
|
|
172
|
-
ct: 800,
|
|
173
|
-
fips: "FIPS 203 + X25519 hybrid",
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
name: "ml-kem-512",
|
|
177
|
-
category: "lattice-kem",
|
|
178
|
-
level: 1,
|
|
179
|
-
isHybrid: false,
|
|
180
|
-
pk: 800,
|
|
181
|
-
ct: 768,
|
|
182
|
-
fips: "FIPS 203",
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
name: "x25519",
|
|
186
|
-
category: "classical-ecdh",
|
|
187
|
-
level: 1,
|
|
188
|
-
isHybrid: false,
|
|
189
|
-
pk: 32,
|
|
190
|
-
ct: 32,
|
|
191
|
-
fips: "RFC 7748 (Legacy)",
|
|
192
|
-
},
|
|
193
|
-
];
|
|
194
|
-
const fallbackChain = catalog.map((c) => c.name);
|
|
195
|
-
const eligible = catalog.filter((candidate) => {
|
|
196
|
-
if (candidate.level < minCategory)
|
|
197
|
-
return false;
|
|
198
|
-
if (requireHybrid && !candidate.isHybrid)
|
|
199
|
-
return false;
|
|
200
|
-
if (clientAlgos && !clientAlgos.includes(candidate.name))
|
|
201
|
-
return false;
|
|
202
|
-
return true;
|
|
203
|
-
});
|
|
204
|
-
const selected = eligible.find((c) => c.ct <= maxBytes) ??
|
|
205
|
-
eligible[0] ??
|
|
206
|
-
catalog[catalog.length - 1];
|
|
207
|
-
const fitsWithinMtu = selected.ct <= maxBytes;
|
|
208
|
-
return {
|
|
209
|
-
selectedAlgorithm: selected.name,
|
|
210
|
-
cipherCategory: selected.category,
|
|
211
|
-
securityCategory: selected.level,
|
|
212
|
-
isHybrid: selected.isHybrid,
|
|
213
|
-
publicKeyBytes: selected.pk,
|
|
214
|
-
ciphertextBytes: selected.ct,
|
|
215
|
-
totalPayloadOverhead: selected.pk + selected.ct,
|
|
216
|
-
fitsWithinMtu,
|
|
217
|
-
fallbackChain,
|
|
218
|
-
compliancePosture: {
|
|
219
|
-
standard: "NIST Post-Quantum Cryptography Standardization",
|
|
220
|
-
doraArticle13Compliant: selected.level >= 3 || selected.isHybrid,
|
|
221
|
-
fipsStandard: selected.fips,
|
|
222
|
-
},
|
|
223
|
-
};
|
|
197
|
+
return (0, negotiation_1.negotiateAlgorithm)(options);
|
|
224
198
|
}
|
|
225
199
|
async algorithms() {
|
|
226
200
|
return this.request("GET", "/v2/algorithms");
|
|
@@ -231,15 +205,4 @@ class CryptoClient {
|
|
|
231
205
|
}
|
|
232
206
|
}
|
|
233
207
|
exports.CryptoClient = CryptoClient;
|
|
234
|
-
class CryptoApiError extends Error {
|
|
235
|
-
status;
|
|
236
|
-
body;
|
|
237
|
-
constructor(status, body) {
|
|
238
|
-
super(`API Error ${status}: ${body.error}`);
|
|
239
|
-
this.name = "CryptoApiError";
|
|
240
|
-
this.status = status;
|
|
241
|
-
this.body = body;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
exports.CryptoApiError = CryptoApiError;
|
|
245
208
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
export type KeyAlgorithm = "ed25519" | "x25519" | "ed448" | "x448" | "p256" | "p384" | "ml-kem-512" | "ml-kem-768" | "ml-kem-1024" | "ml-dsa-44" | "ml-dsa-65" | "ml-dsa-87";
|
|
2
|
+
export type MlKemLevel = 512 | 768 | 1024;
|
|
3
|
+
export type MlDsaLevel = 44 | 65 | 87;
|
|
4
|
+
export type SlhDsaVariant = "sha2-128f" | "sha2-128s" | "sha2-192f" | "sha2-192s" | "sha2-256f" | "sha2-256s" | "shake-128f" | "shake-128s" | "shake-192f" | "shake-192s" | "shake-256f" | "shake-256s";
|
|
5
|
+
export interface KeyIdParams {
|
|
6
|
+
keyId: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SignParams extends KeyIdParams {
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
export interface KeyMetadata {
|
|
12
|
+
kid?: string;
|
|
13
|
+
use?: "sig" | "enc";
|
|
14
|
+
exp?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ServerKey {
|
|
17
|
+
keyId: string;
|
|
18
|
+
algorithm: string;
|
|
19
|
+
}
|
|
20
|
+
export interface KeyGenerateResult extends ServerKey {
|
|
21
|
+
publicKey: string;
|
|
22
|
+
kid: string;
|
|
23
|
+
metadata: KeyMetadata;
|
|
24
|
+
}
|
|
25
|
+
export interface KeyExportResult extends ServerKey {
|
|
26
|
+
[part: string]: string;
|
|
27
|
+
}
|
|
28
|
+
export interface SignResult {
|
|
29
|
+
signature: string;
|
|
30
|
+
algorithm: string;
|
|
31
|
+
}
|
|
32
|
+
export interface VerifyResult {
|
|
33
|
+
valid: boolean;
|
|
34
|
+
algorithm: string;
|
|
35
|
+
}
|
|
36
|
+
export interface MlKemKeyPair extends ServerKey {
|
|
37
|
+
publicKey: string;
|
|
38
|
+
}
|
|
39
|
+
export interface MlKemKeygenParams {
|
|
40
|
+
level?: MlKemLevel;
|
|
41
|
+
}
|
|
42
|
+
export interface MlKemEncapsulateParams {
|
|
43
|
+
publicKey: string;
|
|
44
|
+
level?: MlKemLevel;
|
|
45
|
+
}
|
|
46
|
+
export interface MlKemDecapsulateParams extends KeyIdParams {
|
|
47
|
+
ciphertext: string;
|
|
48
|
+
level?: MlKemLevel;
|
|
49
|
+
}
|
|
50
|
+
export interface HybridEncapsulateParams {
|
|
51
|
+
x25519PublicKey: string;
|
|
52
|
+
mlKemPublicKey: string;
|
|
53
|
+
level?: MlKemLevel;
|
|
54
|
+
}
|
|
55
|
+
export interface HybridDecapsulateParams extends KeyIdParams {
|
|
56
|
+
x25519EphemeralPublic: string;
|
|
57
|
+
mlKemCiphertext: string;
|
|
58
|
+
level?: MlKemLevel;
|
|
59
|
+
}
|
|
60
|
+
export interface MlKemEncapsulateResult {
|
|
61
|
+
ciphertext: string;
|
|
62
|
+
sharedSecret: string;
|
|
63
|
+
algorithm: string;
|
|
64
|
+
}
|
|
65
|
+
export interface KemDecapsulateResult {
|
|
66
|
+
sharedSecret: string;
|
|
67
|
+
algorithm: string;
|
|
68
|
+
}
|
|
69
|
+
export interface HybridKeyPair extends ServerKey {
|
|
70
|
+
x25519PublicKey: string;
|
|
71
|
+
mlKemPublicKey: string;
|
|
72
|
+
}
|
|
73
|
+
export interface HybridEncapsulateResult {
|
|
74
|
+
x25519EphemeralPublic: string;
|
|
75
|
+
mlKemCiphertext: string;
|
|
76
|
+
sharedSecret: string;
|
|
77
|
+
algorithm: string;
|
|
78
|
+
}
|
|
79
|
+
export interface MlDsaKeyPair extends ServerKey {
|
|
80
|
+
publicKey: string;
|
|
81
|
+
}
|
|
82
|
+
export interface MlDsaSignResult {
|
|
83
|
+
signature: string;
|
|
84
|
+
algorithm: string;
|
|
85
|
+
}
|
|
86
|
+
export interface MlDsaVerifyResult {
|
|
87
|
+
valid: boolean;
|
|
88
|
+
algorithm: string;
|
|
89
|
+
}
|
|
90
|
+
export interface SlhDsaKeyPair extends ServerKey {
|
|
91
|
+
publicKey: string;
|
|
92
|
+
}
|
|
93
|
+
export interface SlhDsaSignResult {
|
|
94
|
+
signature: string;
|
|
95
|
+
algorithm: string;
|
|
96
|
+
}
|
|
97
|
+
export interface SlhDsaVerifyResult {
|
|
98
|
+
valid: boolean;
|
|
99
|
+
algorithm: string;
|
|
100
|
+
}
|
|
101
|
+
export interface SealedboxSealResult {
|
|
102
|
+
sealed: string;
|
|
103
|
+
algorithm: string;
|
|
104
|
+
}
|
|
105
|
+
export type HpkeKem = "x25519" | "p256" | "x25519-ml-kem-768";
|
|
106
|
+
export type HpkeAead = "chacha20-poly1305" | "aes-128-gcm";
|
|
107
|
+
export interface HpkeGenerateKeyPairParams {
|
|
108
|
+
kem?: HpkeKem;
|
|
109
|
+
}
|
|
110
|
+
export interface HpkeKeyPair extends ServerKey {
|
|
111
|
+
publicKey: string;
|
|
112
|
+
}
|
|
113
|
+
export interface HpkeSealParams {
|
|
114
|
+
recipientPublicKey: string;
|
|
115
|
+
plaintext: string;
|
|
116
|
+
kem?: HpkeKem;
|
|
117
|
+
aead?: HpkeAead;
|
|
118
|
+
info?: string;
|
|
119
|
+
aad?: string;
|
|
120
|
+
psk?: string;
|
|
121
|
+
pskId?: string;
|
|
122
|
+
}
|
|
123
|
+
export interface HpkeSealResult {
|
|
124
|
+
ciphertext: string;
|
|
125
|
+
encapsulatedKey: string;
|
|
126
|
+
}
|
|
127
|
+
export interface HpkeOpenParams {
|
|
128
|
+
keyId: string;
|
|
129
|
+
encapsulatedKey: string;
|
|
130
|
+
ciphertext: string;
|
|
131
|
+
aead?: HpkeAead;
|
|
132
|
+
info?: string;
|
|
133
|
+
aad?: string;
|
|
134
|
+
psk?: string;
|
|
135
|
+
pskId?: string;
|
|
136
|
+
}
|
|
137
|
+
export interface HpkeOpenResult {
|
|
138
|
+
plaintext: string;
|
|
139
|
+
hex: string;
|
|
140
|
+
}
|
|
141
|
+
export interface KmsCreateKeyParams {
|
|
142
|
+
provider?: string;
|
|
143
|
+
algorithm?: string;
|
|
144
|
+
usage?: "encrypt" | "sign" | "wrap";
|
|
145
|
+
metadata?: Record<string, string>;
|
|
146
|
+
}
|
|
147
|
+
export interface KmsWrapParams {
|
|
148
|
+
keyId: string;
|
|
149
|
+
unwrappedKey: string;
|
|
150
|
+
provider?: string;
|
|
151
|
+
context?: Record<string, string>;
|
|
152
|
+
}
|
|
153
|
+
export interface KmsWrapResult {
|
|
154
|
+
wrappedKey: string;
|
|
155
|
+
keyId: string;
|
|
156
|
+
provider: string;
|
|
157
|
+
}
|
|
158
|
+
export interface KmsUnwrapParams {
|
|
159
|
+
keyId: string;
|
|
160
|
+
wrappedKey: string;
|
|
161
|
+
provider?: string;
|
|
162
|
+
context?: Record<string, string>;
|
|
163
|
+
}
|
|
164
|
+
export interface KmsUnwrapResult {
|
|
165
|
+
unwrappedKey: string;
|
|
166
|
+
keyId: string;
|
|
167
|
+
provider: string;
|
|
168
|
+
}
|
|
169
|
+
export interface KmsGenerateDataKeyParams {
|
|
170
|
+
keyId: string;
|
|
171
|
+
provider?: string;
|
|
172
|
+
keySpec?: string;
|
|
173
|
+
}
|
|
174
|
+
export interface KmsGenerateDataKeyResult {
|
|
175
|
+
plaintext: string;
|
|
176
|
+
ciphertext: string;
|
|
177
|
+
keyId: string;
|
|
178
|
+
provider: string;
|
|
179
|
+
}
|
|
180
|
+
export interface KmsEncryptParams {
|
|
181
|
+
keyId: string;
|
|
182
|
+
plaintext: string;
|
|
183
|
+
provider?: string;
|
|
184
|
+
context?: Record<string, string>;
|
|
185
|
+
}
|
|
186
|
+
export interface KmsEncryptResult {
|
|
187
|
+
ciphertext: string;
|
|
188
|
+
keyId: string;
|
|
189
|
+
provider: string;
|
|
190
|
+
}
|
|
191
|
+
export interface KmsDecryptParams {
|
|
192
|
+
keyId: string;
|
|
193
|
+
ciphertext: string;
|
|
194
|
+
provider?: string;
|
|
195
|
+
context?: Record<string, string>;
|
|
196
|
+
}
|
|
197
|
+
export interface KmsDecryptResult {
|
|
198
|
+
plaintext: string;
|
|
199
|
+
hex: string;
|
|
200
|
+
keyId: string;
|
|
201
|
+
provider: string;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=key-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-types.d.ts","sourceRoot":"","sources":["../src/key-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"negotiation.d.ts","sourceRoot":"","sources":["../src/negotiation.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,2BAA2B,EAC3B,0BAA0B,EAC3B,MAAM,SAAS,CAAC;AAmFjB,wBAAgB,kBAAkB,CAChC,OAAO,GAAE,2BAAgC,GACxC,0BAA0B,CAwC5B"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.negotiateAlgorithm = negotiateAlgorithm;
|
|
4
|
+
const KEM_CATALOG = [
|
|
5
|
+
{
|
|
6
|
+
name: "x448-mlkem1024",
|
|
7
|
+
category: "hybrid-kem",
|
|
8
|
+
level: 5,
|
|
9
|
+
isHybrid: true,
|
|
10
|
+
pk: 1624,
|
|
11
|
+
ct: 1624,
|
|
12
|
+
fips: "FIPS 203 + RFC 7748",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: "ml-kem-1024",
|
|
16
|
+
category: "lattice-kem",
|
|
17
|
+
level: 5,
|
|
18
|
+
isHybrid: false,
|
|
19
|
+
pk: 1568,
|
|
20
|
+
ct: 1568,
|
|
21
|
+
fips: "FIPS 203",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "x25519-mlkem768",
|
|
25
|
+
category: "hybrid-kem",
|
|
26
|
+
level: 3,
|
|
27
|
+
isHybrid: true,
|
|
28
|
+
pk: 1216,
|
|
29
|
+
ct: 1120,
|
|
30
|
+
fips: "FIPS 203 + X25519 hybrid",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "ml-kem-768",
|
|
34
|
+
category: "lattice-kem",
|
|
35
|
+
level: 3,
|
|
36
|
+
isHybrid: false,
|
|
37
|
+
pk: 1184,
|
|
38
|
+
ct: 1088,
|
|
39
|
+
fips: "FIPS 203",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "x25519-mlkem512",
|
|
43
|
+
category: "hybrid-kem",
|
|
44
|
+
level: 1,
|
|
45
|
+
isHybrid: true,
|
|
46
|
+
pk: 832,
|
|
47
|
+
ct: 800,
|
|
48
|
+
fips: "FIPS 203 + X25519 hybrid",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "ml-kem-512",
|
|
52
|
+
category: "lattice-kem",
|
|
53
|
+
level: 1,
|
|
54
|
+
isHybrid: false,
|
|
55
|
+
pk: 800,
|
|
56
|
+
ct: 768,
|
|
57
|
+
fips: "FIPS 203",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "x25519",
|
|
61
|
+
category: "classical-ecdh",
|
|
62
|
+
level: 1,
|
|
63
|
+
isHybrid: false,
|
|
64
|
+
pk: 32,
|
|
65
|
+
ct: 32,
|
|
66
|
+
fips: "RFC 7748 (Legacy)",
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
function negotiateAlgorithm(options = {}) {
|
|
70
|
+
const minCategory = options.securityCategoryMin ?? 1;
|
|
71
|
+
const requireHybrid = options.requireHybrid ?? false;
|
|
72
|
+
const maxBytes = options.maxPayloadBytes ?? Infinity;
|
|
73
|
+
const clientAlgos = options.clientSupportedAlgorithms;
|
|
74
|
+
const fallbackChain = KEM_CATALOG.map((c) => c.name);
|
|
75
|
+
const eligible = KEM_CATALOG.filter((candidate) => {
|
|
76
|
+
if (candidate.level < minCategory)
|
|
77
|
+
return false;
|
|
78
|
+
if (requireHybrid && !candidate.isHybrid)
|
|
79
|
+
return false;
|
|
80
|
+
if (clientAlgos && !clientAlgos.includes(candidate.name))
|
|
81
|
+
return false;
|
|
82
|
+
return true;
|
|
83
|
+
});
|
|
84
|
+
const selected = eligible.find((c) => c.ct <= maxBytes) ??
|
|
85
|
+
eligible[0] ??
|
|
86
|
+
KEM_CATALOG[KEM_CATALOG.length - 1];
|
|
87
|
+
const fitsWithinMtu = selected.ct <= maxBytes;
|
|
88
|
+
return {
|
|
89
|
+
selectedAlgorithm: selected.name,
|
|
90
|
+
cipherCategory: selected.category,
|
|
91
|
+
securityCategory: selected.level,
|
|
92
|
+
isHybrid: selected.isHybrid,
|
|
93
|
+
publicKeyBytes: selected.pk,
|
|
94
|
+
ciphertextBytes: selected.ct,
|
|
95
|
+
totalPayloadOverhead: selected.pk + selected.ct,
|
|
96
|
+
fitsWithinMtu,
|
|
97
|
+
fallbackChain,
|
|
98
|
+
compliancePosture: {
|
|
99
|
+
standard: "NIST Post-Quantum Cryptography Standardization",
|
|
100
|
+
doraArticle13Compliant: selected.level >= 3 || selected.isHybrid,
|
|
101
|
+
fipsStandard: selected.fips,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=negotiation.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ClientOptions, RetryOptions } from "./types";
|
|
2
|
+
export interface RetryConfig {
|
|
3
|
+
maxRetries: number;
|
|
4
|
+
initialDelayMs: number;
|
|
5
|
+
maxDelayMs: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function resolveRetryConfig(retry?: RetryOptions): RetryConfig;
|
|
8
|
+
export declare function buildClientHeaders(options: ClientOptions): Record<string, string>;
|
|
9
|
+
export declare function isTransientStatus(status: number): boolean;
|
|
10
|
+
export declare function computeBackoffDelay(attempt: number, config: RetryConfig, retryAfterHeader?: string | null): number;
|
|
11
|
+
export declare function buildRequestInit(method: string, headers: Record<string, string>, body?: unknown, timeout?: number): RequestInit;
|
|
12
|
+
export declare function executeRequest<T>(fetchFn: typeof globalThis.fetch, url: string, init: RequestInit, retry: RetryConfig): Promise<T>;
|
|
13
|
+
export declare function generateSdkTraceparent(): string;
|
|
14
|
+
export declare function resolveTraceparentHeader(traceparent?: string | boolean): string | undefined;
|
|
15
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG3D,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAGD,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE,YAAY,GAAG,WAAW,CAMpE;AAGD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,aAAa,GACrB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAaxB;AAGD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEzD;AAGD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,WAAW,EACnB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,GAC/B,MAAM,CAWR;AAGD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,MAAM,GACf,WAAW,CAcb;AAGD,wBAAsB,cAAc,CAAC,CAAC,EACpC,OAAO,EAAE,OAAO,UAAU,CAAC,KAAK,EAChC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,CAAC,CAAC,CAkCZ;AAGD,wBAAgB,sBAAsB,IAAI,MAAM,CAoB/C;AAGD,wBAAgB,wBAAwB,CACtC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,GAC7B,MAAM,GAAG,SAAS,CAKpB"}
|