@sebastienrousseau/crypto-mcp 0.0.9 → 0.0.25

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.
@@ -1 +1 @@
1
- {"version":3,"file":"annotations.d.ts","sourceRoot":"","sources":["../../src/tools/annotations.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AA8CnD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,kBAAkB,CAAA;CAAE,GAAG,SAAS,CAKhE"}
1
+ {"version":3,"file":"annotations.d.ts","sourceRoot":"","sources":["../../src/tools/annotations.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAkEnD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,kBAAkB,CAAA;CAAE,GAAG,SAAS,CAKhE"}
@@ -31,6 +31,26 @@ const TOOL_BEHAVIOUR = {
31
31
  crypto_decrypt: ["Decrypt data", "read"],
32
32
  crypto_kem_encapsulate: ["Encapsulate a shared secret", "add"],
33
33
  crypto_kem_decapsulate: ["Decapsulate a shared secret", "add"],
34
+ crypto_hybrid_kem_encapsulate: ["Hybrid post-quantum KEM encapsulate", "add"],
35
+ crypto_hybrid_kem_decapsulate: ["Hybrid post-quantum KEM decapsulate", "add"],
36
+ crypto_hybrid_kem_multi_encapsulate: [
37
+ "Multi-recipient hybrid KEM encapsulate",
38
+ "add",
39
+ ],
40
+ crypto_hybrid_kem_multi_decapsulate: [
41
+ "Multi-recipient hybrid KEM decapsulate",
42
+ "add",
43
+ ],
44
+ crypto_stream_encrypt: ["Stream encrypt data (post-quantum)", "read"],
45
+ crypto_stream_decrypt: ["Stream decrypt data (post-quantum)", "read"],
46
+ crypto_stream_multi_encrypt: [
47
+ "Multi-recipient stream encrypt data (post-quantum)",
48
+ "read",
49
+ ],
50
+ crypto_stream_multi_decrypt: [
51
+ "Multi-recipient stream decrypt data (post-quantum)",
52
+ "read",
53
+ ],
34
54
  crypto_sign: ["Sign data", "read"],
35
55
  crypto_verify: ["Verify a signature", "read"],
36
56
  crypto_hash: ["Hash data", "read"],
@@ -1,11 +1,10 @@
1
1
  import { MCPTool } from "../types";
2
2
  export declare const KEY_TYPES: string[];
3
+ export declare const ML_KEM_LEVELS: number[];
3
4
  export declare const RSA_MODULUS_LENGTHS: number[];
4
5
  export declare const EC_CURVES: string[];
5
6
  export declare const KEY_DIR_ENV = "CRYPTO_MCP_KEY_DIR";
6
7
  export declare const MAX_KEY_FILE_BYTES = 65536;
7
8
  export declare const HASH_ALGORITHMS: string[];
8
- export declare const MAX_TEXT_LENGTH = 1048576;
9
- export declare const MAX_KEY_LENGTH = 16384;
10
9
  export declare const TOOLS: MCPTool[];
11
10
  //# sourceMappingURL=definitions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAA4B,MAAM,UAAU,CAAC;AAK7D,eAAO,MAAM,SAAS,UAOrB,CAAC;AAGF,eAAO,MAAM,mBAAmB,UAAqB,CAAC;AAGtD,eAAO,MAAM,SAAS,UAA2C,CAAC;AAGlE,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAGhD,eAAO,MAAM,kBAAkB,QAAS,CAAC;AASzC,eAAO,MAAM,eAAe,UAM3B,CAAC;AASF,eAAO,MAAM,eAAe,UAAY,CAAC;AAGzC,eAAO,MAAM,cAAc,QAAS,CAAC;AAgVrC,eAAO,MAAM,KAAK,EAAE,OAAO,EAKiC,CAAC"}
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAA4B,MAAM,UAAU,CAAC;AAgB7D,eAAO,MAAM,SAAS,UAarB,CAAC;AAGF,eAAO,MAAM,aAAa,UAAmB,CAAC;AAG9C,eAAO,MAAM,mBAAmB,UAAqB,CAAC;AAGtD,eAAO,MAAM,SAAS,UAA2C,CAAC;AAGlE,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAGhD,eAAO,MAAM,kBAAkB,QAAS,CAAC;AASzC,eAAO,MAAM,eAAe,UAM3B,CAAC;AA4WF,eAAO,MAAM,KAAK,EAAE,OAAO,EAMiC,CAAC"}
@@ -1,16 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TOOLS = exports.MAX_KEY_LENGTH = exports.MAX_TEXT_LENGTH = exports.HASH_ALGORITHMS = exports.MAX_KEY_FILE_BYTES = exports.KEY_DIR_ENV = exports.EC_CURVES = exports.RSA_MODULUS_LENGTHS = exports.KEY_TYPES = void 0;
3
+ exports.TOOLS = exports.HASH_ALGORITHMS = exports.MAX_KEY_FILE_BYTES = exports.KEY_DIR_ENV = exports.EC_CURVES = exports.RSA_MODULUS_LENGTHS = exports.ML_KEM_LEVELS = exports.KEY_TYPES = void 0;
4
4
  const keystore_1 = require("./keystore");
5
5
  const annotations_1 = require("./annotations");
6
+ const stream_definitions_1 = require("./stream-definitions");
7
+ const schema_helpers_1 = require("./schema-helpers");
6
8
  exports.KEY_TYPES = [
7
9
  "rsa",
8
10
  "ecc",
9
11
  "ed25519",
12
+ "x25519",
13
+ "ml-kem-512",
10
14
  "ml-kem-768",
15
+ "ml-kem-1024",
16
+ "ml-dsa-44",
17
+ "ml-dsa-65",
18
+ "ml-dsa-87",
11
19
  "symmetric-256",
12
20
  "hmac-sha256",
13
21
  ];
22
+ exports.ML_KEM_LEVELS = [512, 768, 1024];
14
23
  exports.RSA_MODULUS_LENGTHS = [2048, 3072, 4096];
15
24
  exports.EC_CURVES = ["prime256v1", "secp384r1", "secp256k1"];
16
25
  exports.KEY_DIR_ENV = "CRYPTO_MCP_KEY_DIR";
@@ -26,36 +35,7 @@ exports.HASH_ALGORITHMS = [
26
35
  ];
27
36
  const AEAD_ALGORITHMS = ["aes-256-gcm", "chacha20-poly1305"];
28
37
  const KMS_PROVIDERS = ["aws", "gcp", "azure", "vault", "local"];
29
- exports.MAX_TEXT_LENGTH = 1_048_576;
30
- exports.MAX_KEY_LENGTH = 16_384;
31
- const HEX_BYTES = "^(?:[0-9a-fA-F]{2})*$";
32
- const ML_KEM_768_PUBLIC_KEY_HEX = 2368;
33
- const ML_KEM_768_CIPHERTEXT_HEX = 2176;
34
- const HANDLE_NOTE = "Secret key material stays inside the server; only an opaque keyHandle is returned.";
35
- function keyHandle(description) {
36
- return {
37
- type: "string",
38
- description: `${description} Key handles look like 'kh_' followed by 32 hex characters.`,
39
- maxLength: 35,
40
- pattern: keystore_1.KEY_HANDLE_PATTERN,
41
- };
42
- }
43
- function text(description) {
44
- return { type: "string", description, maxLength: exports.MAX_TEXT_LENGTH };
45
- }
46
- function hex(description, length, upTo = false) {
47
- return {
48
- type: "string",
49
- description,
50
- minLength: upTo ? 2 : length,
51
- maxLength: length,
52
- pattern: HEX_BYTES,
53
- };
54
- }
55
- function oneOf(description, values) {
56
- return { type: "string", description, enum: values };
57
- }
58
- const KMS_PROVIDER = oneOf("KMS provider ('aws', 'gcp', 'azure', 'vault', or 'local'). Only 'local' (random, in-process key material that does not survive a restart) is configured; the others return an error.", KMS_PROVIDERS);
38
+ const KMS_PROVIDER = (0, schema_helpers_1.oneOf)("KMS provider ('aws', 'gcp', 'azure', 'vault', or 'local'). Only 'local' (random, in-process key material that does not survive a restart) is configured; the others return an error.", KMS_PROVIDERS);
59
39
  const KEK_LABEL = {
60
40
  type: "string",
61
41
  description: "Label of the Key Encryption Key (KEK). It names the key; it is never used to derive it.",
@@ -65,18 +45,18 @@ const KEK_LABEL = {
65
45
  const KEY_TOOLS = [
66
46
  {
67
47
  name: "crypto_generate_key",
68
- description: `Generate a key inside the server: a classical (RSA, ECC, Ed25519) or post-quantum (ML-KEM-768, FIPS 203) keypair, a 256-bit symmetric key, or an HMAC-SHA256 key. Returns a keyHandle and, for keypairs, the public key. ${HANDLE_NOTE}`,
48
+ description: `Generate a key inside the server: a classical (RSA, ECC, Ed25519) or post-quantum (ML-KEM 512/768/1024 FIPS 203, ML-DSA 44/65/87 FIPS 204) keypair, a 256-bit symmetric key, or an HMAC-SHA256 key. Returns a keyHandle and, for keypairs, the public key. ${schema_helpers_1.HANDLE_NOTE}`,
69
49
  inputSchema: {
70
50
  type: "object",
71
51
  additionalProperties: false,
72
52
  properties: {
73
- type: oneOf("Key type: 'rsa', 'ecc', 'ed25519', 'ml-kem-768', 'symmetric-256' (for crypto_encrypt, crypto_decrypt and crypto_kms_wrap), or 'hmac-sha256'.", exports.KEY_TYPES),
53
+ type: (0, schema_helpers_1.oneOf)("Key type: 'rsa', 'ecc', 'ed25519', 'x25519', 'ml-kem-512', 'ml-kem-768', 'ml-kem-1024', 'ml-dsa-44', 'ml-dsa-65', 'ml-dsa-87', 'symmetric-256', or 'hmac-sha256'.", exports.KEY_TYPES),
74
54
  modulusLength: {
75
55
  type: "integer",
76
56
  description: "Modulus length for RSA (2048, 3072, 4096). Default is 2048.",
77
57
  enum: exports.RSA_MODULUS_LENGTHS,
78
58
  },
79
- curve: oneOf("Elliptic curve for 'ecc': 'prime256v1' (P-256), 'secp384r1' (P-384), or 'secp256k1'. Default is 'prime256v1'.", exports.EC_CURVES),
59
+ curve: (0, schema_helpers_1.oneOf)("Elliptic curve for 'ecc': 'prime256v1' (P-256), 'secp384r1' (P-384), or 'secp256k1'. Default is 'prime256v1'.", exports.EC_CURVES),
80
60
  },
81
61
  required: ["type"],
82
62
  },
@@ -96,13 +76,13 @@ const KEY_TOOLS = [
96
76
  inputSchema: {
97
77
  type: "object",
98
78
  additionalProperties: false,
99
- properties: { keyHandle: keyHandle("Handle of the key to destroy.") },
79
+ properties: { keyHandle: (0, schema_helpers_1.keyHandle)("Handle of the key to destroy.") },
100
80
  required: ["keyHandle"],
101
81
  },
102
82
  },
103
83
  {
104
84
  name: "crypto_key_import",
105
- description: `Import an existing key from a file in the directory the server operator set in ${exports.KEY_DIR_ENV} (disabled when it is unset). Reads an unencrypted PKCS#8 PEM private key (Ed25519, RSA 2048/3072/4096, ECDSA P-256/P-384/secp256k1; the type comes from the key) or a raw 32-byte key, as 32 binary bytes or 64 hex digits, imported as 'symmetric-256' (default) or 'hmac-sha256'. Files over ${exports.MAX_KEY_FILE_BYTES} bytes are refused. The key bytes never pass through the conversation. ${HANDLE_NOTE}`,
85
+ description: `Import an existing key from a file in the directory the server operator set in ${exports.KEY_DIR_ENV} (disabled when it is unset). Reads an unencrypted PKCS#8 PEM private key (Ed25519, RSA 2048/3072/4096, ECDSA P-256/P-384/secp256k1; the type comes from the key) or a raw 32-byte key, as 32 binary bytes or 64 hex digits, imported as 'symmetric-256' (default) or 'hmac-sha256'. Files over ${exports.MAX_KEY_FILE_BYTES} bytes are refused. The key bytes never pass through the conversation. ${schema_helpers_1.HANDLE_NOTE}`,
106
86
  inputSchema: {
107
87
  type: "object",
108
88
  additionalProperties: false,
@@ -113,7 +93,7 @@ const KEY_TOOLS = [
113
93
  minLength: 1,
114
94
  maxLength: MAX_KEY_PATH_LENGTH,
115
95
  },
116
- kind: oneOf("For a raw 32-byte key only: 'symmetric-256' (crypto_encrypt, crypto_decrypt, crypto_kms_wrap; default) or 'hmac-sha256' (crypto_sign, crypto_verify).", RAW_KEY_KINDS),
96
+ kind: (0, schema_helpers_1.oneOf)("For a raw 32-byte key only: 'symmetric-256' (crypto_encrypt, crypto_decrypt, crypto_kms_wrap; default) or 'hmac-sha256' (crypto_sign, crypto_verify).", RAW_KEY_KINDS),
117
97
  },
118
98
  required: ["path"],
119
99
  },
@@ -128,7 +108,7 @@ const KEY_TOOLS = [
128
108
  keyData: {
129
109
  type: "string",
130
110
  description: "PEM or armored key string.",
131
- maxLength: exports.MAX_KEY_LENGTH,
111
+ maxLength: schema_helpers_1.MAX_KEY_LENGTH,
132
112
  },
133
113
  },
134
114
  required: ["keyData"],
@@ -138,14 +118,14 @@ const KEY_TOOLS = [
138
118
  const CIPHER_TOOLS = [
139
119
  {
140
120
  name: "crypto_encrypt",
141
- description: `Encrypt plaintext with authenticated encryption (AES-256-GCM or ChaCha20-Poly1305) under a symmetric-256 key handle. Without keyHandle, a new key is generated and its handle returned. ${HANDLE_NOTE}`,
121
+ description: `Encrypt plaintext with authenticated encryption (AES-256-GCM or ChaCha20-Poly1305) under a symmetric-256 key handle. Without keyHandle, a new key is generated and its handle returned. ${schema_helpers_1.HANDLE_NOTE}`,
142
122
  inputSchema: {
143
123
  type: "object",
144
124
  additionalProperties: false,
145
125
  properties: {
146
- plaintext: text("Plaintext string to encrypt."),
147
- algorithm: oneOf("Encryption algorithm ('aes-256-gcm' or 'chacha20-poly1305'). Default is 'aes-256-gcm'.", AEAD_ALGORITHMS),
148
- keyHandle: keyHandle("Handle of a symmetric-256 key. If omitted, a new key is generated."),
126
+ plaintext: (0, schema_helpers_1.text)("Plaintext string to encrypt."),
127
+ algorithm: (0, schema_helpers_1.oneOf)("Encryption algorithm ('aes-256-gcm' or 'chacha20-poly1305'). Default is 'aes-256-gcm'.", AEAD_ALGORITHMS),
128
+ keyHandle: (0, schema_helpers_1.keyHandle)("Handle of a symmetric-256 key. If omitted, a new key is generated."),
149
129
  },
150
130
  required: ["plaintext"],
151
131
  },
@@ -157,71 +137,124 @@ const CIPHER_TOOLS = [
157
137
  type: "object",
158
138
  additionalProperties: false,
159
139
  properties: {
160
- ciphertext: hex("Hex-encoded ciphertext.", 2 * exports.MAX_TEXT_LENGTH, true),
161
- algorithm: oneOf("Algorithm used for encryption ('aes-256-gcm' or 'chacha20-poly1305'). Default is 'aes-256-gcm'.", AEAD_ALGORITHMS),
162
- keyHandle: keyHandle("Handle of the symmetric-256 key."),
163
- iv: hex("Hex-encoded 96-bit nonce (24 hex characters).", 24),
164
- authTag: hex("Hex-encoded 128-bit authentication tag.", 32),
140
+ ciphertext: (0, schema_helpers_1.hex)("Hex-encoded ciphertext.", 2 * schema_helpers_1.MAX_TEXT_LENGTH, true),
141
+ algorithm: (0, schema_helpers_1.oneOf)("Algorithm used for encryption ('aes-256-gcm' or 'chacha20-poly1305'). Default is 'aes-256-gcm'.", AEAD_ALGORITHMS),
142
+ keyHandle: (0, schema_helpers_1.keyHandle)("Handle of the symmetric-256 key."),
143
+ iv: (0, schema_helpers_1.hex)("Hex-encoded 96-bit nonce (24 hex characters).", 24),
144
+ authTag: (0, schema_helpers_1.hex)("Hex-encoded 128-bit authentication tag.", 32),
165
145
  },
166
146
  required: ["ciphertext", "keyHandle", "iv", "authTag"],
167
147
  },
168
148
  },
169
149
  {
170
150
  name: "crypto_kem_encapsulate",
171
- description: `Encapsulate a shared secret to an ML-KEM-768 (FIPS 203) public key. Returns the KEM ciphertext for the recipient and a symmetric-256 keyHandle for the shared secret, usable with crypto_encrypt. ${HANDLE_NOTE}`,
151
+ description: `Encapsulate a shared secret to an ML-KEM (FIPS 203) public key (512, 768, 1024). Returns the KEM ciphertext for the recipient and a symmetric-256 keyHandle for the shared secret, usable with crypto_encrypt. ${schema_helpers_1.HANDLE_NOTE}`,
172
152
  inputSchema: {
173
153
  type: "object",
174
154
  additionalProperties: false,
175
155
  properties: {
176
- publicKey: hex("Hex-encoded ML-KEM-768 public key (2368 hex characters).", ML_KEM_768_PUBLIC_KEY_HEX),
156
+ publicKey: (0, schema_helpers_1.hex)("Hex-encoded ML-KEM public key (1600, 2368, or 3136 hex characters).", 3136, true),
157
+ level: {
158
+ type: "integer",
159
+ description: "ML-KEM security level (512, 768, or 1024). Default is 768.",
160
+ enum: exports.ML_KEM_LEVELS,
161
+ },
177
162
  },
178
163
  required: ["publicKey"],
179
164
  },
180
165
  },
181
166
  {
182
167
  name: "crypto_kem_decapsulate",
183
- description: `Recover an ML-KEM-768 shared secret with an ml-kem-768 key handle. Returns a symmetric-256 keyHandle for the shared secret. ${HANDLE_NOTE}`,
168
+ description: `Recover an ML-KEM shared secret with an ml-kem key handle (512, 768, 1024). Returns a symmetric-256 keyHandle for the shared secret. ${schema_helpers_1.HANDLE_NOTE}`,
184
169
  inputSchema: {
185
170
  type: "object",
186
171
  additionalProperties: false,
187
172
  properties: {
188
- keyHandle: keyHandle("Handle of the ml-kem-768 key."),
189
- ciphertext: hex("Hex-encoded ML-KEM-768 ciphertext (2176 hex characters).", ML_KEM_768_CIPHERTEXT_HEX),
173
+ keyHandle: (0, schema_helpers_1.keyHandle)("Handle of the ml-kem key."),
174
+ ciphertext: (0, schema_helpers_1.hex)("Hex-encoded ML-KEM ciphertext (1536, 2176, or 3136 hex characters).", 3136, true),
175
+ level: {
176
+ type: "integer",
177
+ description: "ML-KEM security level (512, 768, or 1024). Default is inferred from key or 768.",
178
+ enum: exports.ML_KEM_LEVELS,
179
+ },
190
180
  },
191
181
  required: ["keyHandle", "ciphertext"],
192
182
  },
193
183
  },
184
+ {
185
+ name: "crypto_hybrid_kem_encapsulate",
186
+ description: `Encapsulate a shared secret using Post-Quantum Hybrid KEM (X25519 + ML-KEM, RFC 9180/10024). Returns the classical ephemeral public key, ML-KEM ciphertext, and a symmetric-256 keyHandle for the combined shared secret. ${schema_helpers_1.HANDLE_NOTE}`,
187
+ inputSchema: {
188
+ type: "object",
189
+ additionalProperties: false,
190
+ properties: {
191
+ x25519PublicKey: (0, schema_helpers_1.hex)("Hex-encoded recipient X25519 public key (64 hex characters).", schema_helpers_1.X25519_PUBLIC_KEY_HEX),
192
+ mlKemPublicKey: (0, schema_helpers_1.hex)("Hex-encoded recipient ML-KEM public key (1600, 2368, or 3136 hex characters).", 3136, true),
193
+ level: {
194
+ type: "integer",
195
+ description: "ML-KEM security level (512, 768, or 1024). Default is 768.",
196
+ enum: exports.ML_KEM_LEVELS,
197
+ },
198
+ },
199
+ required: ["x25519PublicKey", "mlKemPublicKey"],
200
+ },
201
+ },
202
+ {
203
+ name: "crypto_hybrid_kem_decapsulate",
204
+ description: `Recover a Post-Quantum Hybrid KEM shared secret (X25519 + ML-KEM) using server-held x25519 and ml-kem key handles. Returns a symmetric-256 keyHandle for the combined shared secret. ${schema_helpers_1.HANDLE_NOTE}`,
205
+ inputSchema: {
206
+ type: "object",
207
+ additionalProperties: false,
208
+ properties: {
209
+ x25519KeyHandle: (0, schema_helpers_1.keyHandle)("Handle of the recipient X25519 key."),
210
+ mlKemKeyHandle: (0, schema_helpers_1.keyHandle)("Handle of the recipient ML-KEM key."),
211
+ x25519EphemeralPublic: (0, schema_helpers_1.hex)("Hex-encoded sender ephemeral X25519 public key (64 hex characters).", schema_helpers_1.X25519_PUBLIC_KEY_HEX),
212
+ mlKemCiphertext: (0, schema_helpers_1.hex)("Hex-encoded ML-KEM ciphertext (1536, 2176, or 3136 hex characters).", 3136, true),
213
+ level: {
214
+ type: "integer",
215
+ description: "ML-KEM security level (512, 768, or 1024). Default is inferred from key or 768.",
216
+ enum: exports.ML_KEM_LEVELS,
217
+ },
218
+ },
219
+ required: [
220
+ "x25519KeyHandle",
221
+ "mlKemKeyHandle",
222
+ "x25519EphemeralPublic",
223
+ "mlKemCiphertext",
224
+ ],
225
+ },
226
+ },
194
227
  ];
195
228
  const SIGNATURE_TOOLS = [
196
229
  {
197
230
  name: "crypto_sign",
198
- description: "Sign data with a key handle. The algorithm follows the key: Ed25519, RSASSA-PSS (SHA-256), ECDSA (SHA-256; SHA-384 on P-384), or HMAC-SHA256.",
231
+ description: "Sign data with a key handle. The algorithm follows the key: Ed25519, RSASSA-PSS (SHA-256), ECDSA (SHA-256; SHA-384 on P-384), ML-DSA (44, 65, 87, FIPS 204), or HMAC-SHA256.",
199
232
  inputSchema: {
200
233
  type: "object",
201
234
  additionalProperties: false,
202
235
  properties: {
203
- data: text("Data string to sign."),
204
- keyHandle: keyHandle("Handle of an ed25519, rsa, ecc, or hmac-sha256 key."),
236
+ data: (0, schema_helpers_1.text)("Data string to sign."),
237
+ keyHandle: (0, schema_helpers_1.keyHandle)("Handle of an ed25519, rsa, ecc, ml-dsa, or hmac-sha256 key."),
205
238
  },
206
239
  required: ["data", "keyHandle"],
207
240
  },
208
241
  },
209
242
  {
210
243
  name: "crypto_verify",
211
- description: "Verify a signature against a public key PEM (Ed25519, RSA-PSS, ECDSA) or a key handle (also HMAC-SHA256). Pass exactly one of publicKey or keyHandle.",
244
+ description: "Verify a signature against a public key (SPKI PEM or ML-DSA hex) or a key handle (also HMAC-SHA256). Pass exactly one of publicKey or keyHandle.",
212
245
  inputSchema: {
213
246
  type: "object",
214
247
  additionalProperties: false,
215
248
  properties: {
216
- data: text("Original data string."),
217
- signature: hex("Hex-encoded signature.", 1024, true),
249
+ data: (0, schema_helpers_1.text)("Original data string."),
250
+ signature: (0, schema_helpers_1.hex)("Hex-encoded signature.", schema_helpers_1.MAX_KEY_LENGTH, true),
218
251
  publicKey: {
219
252
  type: "string",
220
- description: "Public key in SPKI PEM format. Private keys are refused.",
253
+ description: "Public key in SPKI PEM format or ML-DSA hex format. Private keys are refused.",
221
254
  minLength: 1,
222
- maxLength: exports.MAX_KEY_LENGTH,
255
+ maxLength: schema_helpers_1.MAX_KEY_LENGTH,
223
256
  },
224
- keyHandle: keyHandle("Handle of an ed25519, rsa, ecc, or hmac-sha256 key."),
257
+ keyHandle: (0, schema_helpers_1.keyHandle)("Handle of an ed25519, rsa, ecc, ml-dsa, or hmac-sha256 key."),
225
258
  },
226
259
  required: ["data", "signature"],
227
260
  },
@@ -233,8 +266,8 @@ const SIGNATURE_TOOLS = [
233
266
  type: "object",
234
267
  additionalProperties: false,
235
268
  properties: {
236
- data: text("Data string to hash."),
237
- algorithm: oneOf("Hash algorithm.", exports.HASH_ALGORITHMS),
269
+ data: (0, schema_helpers_1.text)("Data string to hash."),
270
+ algorithm: (0, schema_helpers_1.oneOf)("Hash algorithm.", exports.HASH_ALGORITHMS),
238
271
  },
239
272
  required: ["data"],
240
273
  },
@@ -250,21 +283,21 @@ const KMS_AND_AUDIT_TOOLS = [
250
283
  properties: {
251
284
  provider: KMS_PROVIDER,
252
285
  keyId: KEK_LABEL,
253
- keyHandle: keyHandle("Handle of the symmetric-256 DEK to wrap."),
286
+ keyHandle: (0, schema_helpers_1.keyHandle)("Handle of the symmetric-256 DEK to wrap."),
254
287
  },
255
288
  required: ["provider", "keyId", "keyHandle"],
256
289
  },
257
290
  },
258
291
  {
259
292
  name: "crypto_kms_unwrap",
260
- description: `Unwrap a DEK previously wrapped by crypto_kms_wrap in this server process into a symmetric-256 key handle. Only the 'local' provider is configured. ${HANDLE_NOTE}`,
293
+ description: `Unwrap a DEK previously wrapped by crypto_kms_wrap in this server process into a symmetric-256 key handle. Only the 'local' provider is configured. ${schema_helpers_1.HANDLE_NOTE}`,
261
294
  inputSchema: {
262
295
  type: "object",
263
296
  additionalProperties: false,
264
297
  properties: {
265
298
  provider: KMS_PROVIDER,
266
299
  keyId: KEK_LABEL,
267
- wrappedKey: hex("Hex-encoded wrapped key payload.", 1024, true),
300
+ wrappedKey: (0, schema_helpers_1.hex)("Hex-encoded wrapped key payload.", 1024, true),
268
301
  },
269
302
  required: ["provider", "keyId", "wrappedKey"],
270
303
  },
@@ -289,6 +322,7 @@ const KMS_AND_AUDIT_TOOLS = [
289
322
  exports.TOOLS = [
290
323
  ...KEY_TOOLS,
291
324
  ...CIPHER_TOOLS,
325
+ ...stream_definitions_1.STREAM_TOOLS,
292
326
  ...SIGNATURE_TOOLS,
293
327
  ...KMS_AND_AUDIT_TOOLS,
294
328
  ].map((tool) => ({ ...tool, ...(0, annotations_1.annotationsFor)(tool.name) }));
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAsB,MAAM,UAAU,CAAC;AAYjE,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAwC/C,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACjC,OAAO,CAAC,iBAAiB,CAAC,CAU5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAsB,MAAM,UAAU,CAAC;AAyBjE,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAgD/C,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACjC,OAAO,CAAC,iBAAiB,CAAC,CAU5B"}
@@ -10,6 +10,7 @@ const keys_1 = require("./keys");
10
10
  const kms_1 = require("./kms");
11
11
  const result_1 = require("./result");
12
12
  const signing_1 = require("./signing");
13
+ const stream_1 = require("./stream");
13
14
  const symmetric_1 = require("./symmetric");
14
15
  const validate_1 = require("./validate");
15
16
  var definitions_2 = require("./definitions");
@@ -23,8 +24,16 @@ const HANDLERS = {
23
24
  crypto_key_import: keyimport_1.importKey,
24
25
  crypto_kem_encapsulate: kem_1.kemEncapsulate,
25
26
  crypto_kem_decapsulate: kem_1.kemDecapsulate,
27
+ crypto_hybrid_kem_encapsulate: kem_1.hybridKemEncapsulateHandler,
28
+ crypto_hybrid_kem_decapsulate: kem_1.hybridKemDecapsulateHandler,
29
+ crypto_hybrid_kem_multi_encapsulate: kem_1.hybridKemMultiEncapsulateHandler,
30
+ crypto_hybrid_kem_multi_decapsulate: kem_1.hybridKemMultiDecapsulateHandler,
26
31
  crypto_encrypt: symmetric_1.encrypt,
27
32
  crypto_decrypt: symmetric_1.decrypt,
33
+ crypto_stream_encrypt: stream_1.streamEncrypt,
34
+ crypto_stream_decrypt: stream_1.streamDecrypt,
35
+ crypto_stream_multi_encrypt: stream_1.streamMultiEncrypt,
36
+ crypto_stream_multi_decrypt: stream_1.streamMultiDecrypt,
28
37
  crypto_sign: signing_1.sign,
29
38
  crypto_verify: signing_1.verify,
30
39
  crypto_hash: signing_1.hash,
@@ -1,4 +1,8 @@
1
1
  import { ToolHandler } from "./result";
2
2
  export declare const kemEncapsulate: ToolHandler;
3
3
  export declare const kemDecapsulate: ToolHandler;
4
+ export declare const hybridKemEncapsulateHandler: ToolHandler;
5
+ export declare const hybridKemDecapsulateHandler: ToolHandler;
6
+ export declare const hybridKemMultiEncapsulateHandler: ToolHandler;
7
+ export declare const hybridKemMultiDecapsulateHandler: ToolHandler;
4
8
  //# sourceMappingURL=kem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"kem.d.ts","sourceRoot":"","sources":["../../src/tools/kem.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAc,MAAM,UAAU,CAAC;AASnD,eAAO,MAAM,cAAc,EAAE,WAS5B,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,WAW5B,CAAC"}
1
+ {"version":3,"file":"kem.d.ts","sourceRoot":"","sources":["../../src/tools/kem.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,WAAW,EAAc,MAAM,UAAU,CAAC;AA2BnD,eAAO,MAAM,cAAc,EAAE,WAa5B,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,WAoB5B,CAAC;AAGF,eAAO,MAAM,2BAA2B,EAAE,WAoBzC,CAAC;AAGF,eAAO,MAAM,2BAA2B,EAAE,WAuBzC,CAAC;AAmBF,eAAO,MAAM,gCAAgC,EAAE,WAoC9C,CAAC;AAgEF,eAAO,MAAM,gCAAgC,EAAE,WAqB9C,CAAC"}
package/dist/tools/kem.js CHANGED
@@ -1,20 +1,156 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.kemDecapsulate = exports.kemEncapsulate = void 0;
6
+ exports.hybridKemMultiDecapsulateHandler = exports.hybridKemMultiEncapsulateHandler = exports.hybridKemDecapsulateHandler = exports.hybridKemEncapsulateHandler = exports.kemDecapsulate = exports.kemEncapsulate = void 0;
7
+ const node_crypto_1 = __importDefault(require("node:crypto"));
4
8
  const crypto_lib_1 = require("@sebastienrousseau/crypto-lib");
5
9
  const keystore_1 = require("./keystore");
6
10
  const result_1 = require("./result");
11
+ function resolveKemLevel(levelArg, defaultLevel = 768) {
12
+ const num = Number(levelArg);
13
+ if (num === 512 || num === 768 || num === 1024) {
14
+ return num;
15
+ }
16
+ return defaultLevel;
17
+ }
18
+ function inferLevelFromKey(keyKind) {
19
+ if (keyKind === "ml-kem-512")
20
+ return 512;
21
+ if (keyKind === "ml-kem-1024")
22
+ return 1024;
23
+ return 768;
24
+ }
7
25
  const kemEncapsulate = async (args) => {
8
- const { ciphertext, sharedSecret, algorithm } = (0, crypto_lib_1.mlKemEncap)(768, String(args.publicKey));
9
- const keyHandle = keystore_1.keyStore.add((0, keystore_1.symmetricKey)(Buffer.from(sharedSecret, "hex"), "ml-kem-768 encapsulation"));
26
+ const level = resolveKemLevel(args.level, 768);
27
+ const { ciphertext, sharedSecret, algorithm } = (0, crypto_lib_1.mlKemEncap)(level, String(args.publicKey));
28
+ const keyHandle = keystore_1.keyStore.add((0, keystore_1.symmetricKey)(Buffer.from(sharedSecret, "hex"), `${algorithm} encapsulation`));
10
29
  return (0, result_1.jsonResult)({ algorithm, ciphertext, keyHandle });
11
30
  };
12
31
  exports.kemEncapsulate = kemEncapsulate;
13
32
  const kemDecapsulate = async (args) => {
14
- const key = keystore_1.keyStore.use(String(args.keyHandle), ["ml-kem-768"]);
15
- const { sharedSecret, algorithm } = (0, crypto_lib_1.mlKemDecap)(768, key.secret.toString("hex"), String(args.ciphertext));
16
- const keyHandle = keystore_1.keyStore.add((0, keystore_1.symmetricKey)(Buffer.from(sharedSecret, "hex"), "ml-kem-768 decapsulation"));
33
+ const key = keystore_1.keyStore.use(String(args.keyHandle), [
34
+ "ml-kem-512",
35
+ "ml-kem-768",
36
+ "ml-kem-1024",
37
+ ]);
38
+ const defaultLevel = inferLevelFromKey(key.kind);
39
+ const level = resolveKemLevel(args.level, defaultLevel);
40
+ const { sharedSecret, algorithm } = (0, crypto_lib_1.mlKemDecap)(level, key.secret.toString("hex"), String(args.ciphertext));
41
+ const keyHandle = keystore_1.keyStore.add((0, keystore_1.symmetricKey)(Buffer.from(sharedSecret, "hex"), `${algorithm} decapsulation`));
17
42
  return (0, result_1.jsonResult)({ algorithm, keyHandle });
18
43
  };
19
44
  exports.kemDecapsulate = kemDecapsulate;
45
+ const hybridKemEncapsulateHandler = async (args) => {
46
+ const level = resolveKemLevel(args.level, 768);
47
+ const { x25519EphemeralPublic, mlKemCiphertext, sharedSecret, algorithm } = (0, crypto_lib_1.hybridKemEncapsulate)(level, String(args.x25519PublicKey), String(args.mlKemPublicKey));
48
+ const keyHandle = keystore_1.keyStore.add((0, keystore_1.symmetricKey)(Buffer.from(sharedSecret, "hex"), `${algorithm} encapsulation`));
49
+ return (0, result_1.jsonResult)({
50
+ algorithm,
51
+ x25519EphemeralPublic,
52
+ mlKemCiphertext,
53
+ keyHandle,
54
+ });
55
+ };
56
+ exports.hybridKemEncapsulateHandler = hybridKemEncapsulateHandler;
57
+ const hybridKemDecapsulateHandler = async (args) => {
58
+ const xKey = keystore_1.keyStore.use(String(args.x25519KeyHandle), ["x25519"]);
59
+ const kemKey = keystore_1.keyStore.use(String(args.mlKemKeyHandle), [
60
+ "ml-kem-512",
61
+ "ml-kem-768",
62
+ "ml-kem-1024",
63
+ ]);
64
+ const defaultLevel = inferLevelFromKey(kemKey.kind);
65
+ const level = resolveKemLevel(args.level, defaultLevel);
66
+ const { sharedSecret, algorithm } = (0, crypto_lib_1.hybridKemDecapsulate)(level, xKey.secret.toString("hex"), kemKey.secret.toString("hex"), String(args.x25519EphemeralPublic), String(args.mlKemCiphertext));
67
+ const keyHandle = keystore_1.keyStore.add((0, keystore_1.symmetricKey)(Buffer.from(sharedSecret, "hex"), `${algorithm} decapsulation`));
68
+ return (0, result_1.jsonResult)({ algorithm, keyHandle });
69
+ };
70
+ exports.hybridKemDecapsulateHandler = hybridKemDecapsulateHandler;
71
+ function parseHybridRecipients(raw) {
72
+ const parsed = JSON.parse(String(raw));
73
+ if (!Array.isArray(parsed) || parsed.length === 0) {
74
+ throw new Error("recipients must be a non-empty array of recipient objects");
75
+ }
76
+ return parsed;
77
+ }
78
+ const hybridKemMultiEncapsulateHandler = async (args) => {
79
+ const recipients = parseHybridRecipients(args.recipients);
80
+ let dek;
81
+ let keyHandle;
82
+ if (args.keyHandle !== undefined && args.keyHandle !== null) {
83
+ keyHandle = String(args.keyHandle);
84
+ const stored = keystore_1.keyStore.use(keyHandle, ["symmetric-256"]);
85
+ dek = Buffer.from(stored.secret);
86
+ }
87
+ else {
88
+ dek = node_crypto_1.default.randomBytes(32);
89
+ keyHandle = keystore_1.keyStore.add((0, keystore_1.symmetricKey)(dek, "multi-recipient hybrid KEM DEK"));
90
+ }
91
+ const encryptedRecipients = recipients.map((r) => {
92
+ const wrapped = (0, crypto_lib_1.wrapDekHybrid)(dek, String(r.x25519PublicKey), String(r.mlKemPublicKey));
93
+ return {
94
+ ...(r.id !== undefined ? { id: String(r.id) } : {}),
95
+ ephemeralPublicKey: wrapped.ephemeralPublicKey,
96
+ mlKemCiphertext: wrapped.mlKemCiphertext,
97
+ wrappedKey: wrapped.wrappedKey,
98
+ encryptedKey: wrapped.wrappedKey,
99
+ };
100
+ });
101
+ return (0, result_1.jsonResult)({
102
+ algorithm: "multi-hybrid-kem-768-aes-256-gcm",
103
+ keyHandle,
104
+ recipients: encryptedRecipients,
105
+ });
106
+ };
107
+ exports.hybridKemMultiEncapsulateHandler = hybridKemMultiEncapsulateHandler;
108
+ function resolveDirectRecipient(args) {
109
+ const encKey = args.wrappedKey ?? args.encryptedKey;
110
+ if (!args.ephemeralPublicKey || !args.mlKemCiphertext || !encKey) {
111
+ return undefined;
112
+ }
113
+ return {
114
+ ephemeralPublicKey: String(args.ephemeralPublicKey),
115
+ mlKemCiphertext: String(args.mlKemCiphertext),
116
+ wrappedKey: String(encKey),
117
+ };
118
+ }
119
+ function resolveListRecipient(args) {
120
+ if (args.recipients === undefined)
121
+ return undefined;
122
+ const list = JSON.parse(String(args.recipients));
123
+ const item = args.recipientId !== undefined
124
+ ? list.find((e) => e.id === String(args.recipientId))
125
+ : list[args.recipientIndex !== undefined ? Number(args.recipientIndex) : 0];
126
+ if (!item)
127
+ return undefined;
128
+ const key = item.wrappedKey ?? item.encryptedKey;
129
+ if (!key)
130
+ return undefined;
131
+ return {
132
+ ephemeralPublicKey: item.ephemeralPublicKey,
133
+ mlKemCiphertext: item.mlKemCiphertext,
134
+ wrappedKey: String(key),
135
+ };
136
+ }
137
+ function resolveRecipientEntry(args) {
138
+ const resolved = resolveDirectRecipient(args) ?? resolveListRecipient(args);
139
+ if (!resolved) {
140
+ throw new Error("Missing recipient encryption details (ephemeralPublicKey, mlKemCiphertext, wrappedKey)");
141
+ }
142
+ return resolved;
143
+ }
144
+ const hybridKemMultiDecapsulateHandler = async (args) => {
145
+ const xKey = keystore_1.keyStore.use(String(args.x25519KeyHandle), ["x25519"]);
146
+ const kemKey = keystore_1.keyStore.use(String(args.mlKemKeyHandle), ["ml-kem-768"]);
147
+ const entry = resolveRecipientEntry(args);
148
+ const dek = (0, crypto_lib_1.unwrapDekHybrid)(xKey.secret, kemKey.secret, entry.ephemeralPublicKey, entry.mlKemCiphertext, entry.wrappedKey);
149
+ const keyHandle = keystore_1.keyStore.add((0, keystore_1.symmetricKey)(Buffer.from(dek), "multi-recipient hybrid KEM DEK"));
150
+ return (0, result_1.jsonResult)({
151
+ algorithm: "multi-hybrid-kem-768-aes-256-gcm",
152
+ keyHandle,
153
+ });
154
+ };
155
+ exports.hybridKemMultiDecapsulateHandler = hybridKemMultiDecapsulateHandler;
20
156
  //# sourceMappingURL=kem.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keyimport.d.ts","sourceRoot":"","sources":["../../src/tools/keyimport.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,SAAS,CAAC;AAUzB,OAAO,EAAY,WAAW,EAAc,MAAM,UAAU,CAAC;AA2F7D,wBAAsB,UAAU,CAC9B,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,EAC5C,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CAajB;AAuKD,eAAO,MAAM,SAAS,EAAE,WAUvB,CAAC"}
1
+ {"version":3,"file":"keyimport.d.ts","sourceRoot":"","sources":["../../src/tools/keyimport.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,SAAS,CAAC;AAUzB,OAAO,EAAY,WAAW,EAAc,MAAM,UAAU,CAAC;AA4F7D,wBAAsB,UAAU,CAC9B,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,EAC5C,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CAajB;AAuKD,eAAO,MAAM,SAAS,EAAE,WAUvB,CAAC"}
@@ -12,6 +12,7 @@ const definitions_1 = require("./definitions");
12
12
  const keys_1 = require("./keys");
13
13
  const keystore_1 = require("./keystore");
14
14
  const result_1 = require("./result");
15
+ const crypto_lib_1 = require("@sebastienrousseau/crypto-lib");
15
16
  const RAW_KEY_BYTES = 32;
16
17
  const SOURCE = "crypto_key_import";
17
18
  const UNREADABLE = `Key file not found or not readable in ${definitions_1.KEY_DIR_ENV}`;
@@ -102,7 +103,7 @@ function decodeHex(text) {
102
103
  const high = hexDigit(text[2 * i]);
103
104
  const low = hexDigit(text[2 * i + 1]);
104
105
  if (high < 0 || low < 0) {
105
- out.fill(0);
106
+ (0, crypto_lib_1.wipeMemory)(out);
106
107
  return undefined;
107
108
  }
108
109
  out[i] = high * 16 + low;
@@ -199,7 +200,7 @@ const importKey = async (args) => {
199
200
  return (0, result_1.jsonResult)(keystore_1.keyStore.describe(keystore_1.keyStore.add(material)));
200
201
  }
201
202
  finally {
202
- bytes.fill(0);
203
+ (0, crypto_lib_1.wipeMemory)(bytes);
203
204
  }
204
205
  };
205
206
  exports.importKey = importKey;
@@ -1 +1 @@
1
- {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/tools/keys.ts"],"names":[],"mappings":"AAEA,OAAO,MAAM,MAAM,aAAa,CAAC;AAGjC,OAAO,EAAE,WAAW,EAA0B,MAAM,YAAY,CAAC;AACjE,OAAO,EAAY,WAAW,EAA2B,MAAM,UAAU,CAAC;AAG1E,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,GAAG,MAAM,CAEvD;AAGD,wBAAgB,UAAU,CACxB,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EACzB,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAA;CAAE,EACnE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,WAAW,CAOb;AAqED,eAAO,MAAM,WAAW,EAAE,WAOzB,CAAC;AAGF,eAAO,MAAM,QAAQ,EAAE,WAC6C,CAAC;AAGrE,eAAO,MAAM,UAAU,EAAE,WAMxB,CAAC;AAmBF,eAAO,MAAM,UAAU,EAAE,WAaxB,CAAC"}
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/tools/keys.ts"],"names":[],"mappings":"AAEA,OAAO,MAAM,MAAM,aAAa,CAAC;AAOjC,OAAO,EAAE,WAAW,EAA0B,MAAM,YAAY,CAAC;AACjE,OAAO,EAAY,WAAW,EAA2B,MAAM,UAAU,CAAC;AAG1E,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,GAAG,MAAM,CAEvD;AAGD,wBAAgB,UAAU,CACxB,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EACzB,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAA;CAAE,EACnE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,WAAW,CAOb;AA2GD,eAAO,MAAM,WAAW,EAAE,WAOzB,CAAC;AAGF,eAAO,MAAM,QAAQ,EAAE,WAC6C,CAAC;AAGrE,eAAO,MAAM,UAAU,EAAE,WAMxB,CAAC;AAmBF,eAAO,MAAM,UAAU,EAAE,WAaxB,CAAC"}
@@ -41,14 +41,30 @@ function generateEcc(args) {
41
41
  const pair = node_crypto_1.default.generateKeyPairSync("ec", { namedCurve });
42
42
  return asymmetric("ecc", pair, { curve: namedCurve });
43
43
  }
44
- function generateMlKem768() {
45
- const { publicKey, secretKey } = (0, crypto_lib_1.mlKemKeygen)(768);
44
+ function generateMlKem(level) {
45
+ const { publicKey, secretKey } = (0, crypto_lib_1.mlKemKeygen)(level);
46
+ const securityCategory = level === 512 ? 1 : level === 768 ? 3 : 5;
46
47
  return {
47
- kind: "ml-kem-768",
48
+ kind: `ml-kem-${level}`,
48
49
  secret: Buffer.from(secretKey, "hex"),
49
50
  info: {
50
51
  standard: "NIST FIPS 203",
51
- securityCategory: 3,
52
+ securityCategory,
53
+ quantumSafe: true,
54
+ encoding: "hex",
55
+ publicKey,
56
+ },
57
+ };
58
+ }
59
+ function generateMlDsa(level) {
60
+ const { publicKey, secretKey } = (0, crypto_lib_1.mlDsaKeygen)(level);
61
+ const securityCategory = level === 44 ? 2 : level === 65 ? 3 : 5;
62
+ return {
63
+ kind: `ml-dsa-${level}`,
64
+ secret: Buffer.from(secretKey, "hex"),
65
+ info: {
66
+ standard: "NIST FIPS 204",
67
+ securityCategory,
52
68
  quantumSafe: true,
53
69
  encoding: "hex",
54
70
  publicKey,
@@ -58,6 +74,19 @@ function generateMlKem768() {
58
74
  function generateSymmetric() {
59
75
  return (0, keystore_1.symmetricKey)(node_crypto_1.default.randomBytes(32), "generated");
60
76
  }
77
+ function generateX25519() {
78
+ const pair = (0, crypto_lib_1.generateX25519KeyPair)();
79
+ return {
80
+ kind: "x25519",
81
+ secret: Buffer.from(pair.privateKey, "hex"),
82
+ info: {
83
+ curve: "x25519",
84
+ quantumSafe: false,
85
+ encoding: "hex",
86
+ publicKey: pair.publicKey,
87
+ },
88
+ };
89
+ }
61
90
  function generateHmac() {
62
91
  return {
63
92
  kind: "hmac-sha256",
@@ -67,9 +96,15 @@ function generateHmac() {
67
96
  }
68
97
  const GENERATORS = {
69
98
  ed25519: generateEd25519,
99
+ x25519: generateX25519,
70
100
  rsa: generateRsa,
71
101
  ecc: generateEcc,
72
- "ml-kem-768": generateMlKem768,
102
+ "ml-kem-512": () => generateMlKem(512),
103
+ "ml-kem-768": () => generateMlKem(768),
104
+ "ml-kem-1024": () => generateMlKem(1024),
105
+ "ml-dsa-44": () => generateMlDsa(44),
106
+ "ml-dsa-65": () => generateMlDsa(65),
107
+ "ml-dsa-87": () => generateMlDsa(87),
73
108
  "symmetric-256": generateSymmetric,
74
109
  "hmac-sha256": generateHmac,
75
110
  };
@@ -1,5 +1,5 @@
1
1
  import crypto from "node:crypto";
2
- export type KeyKind = "ed25519" | "rsa" | "ecc" | "ml-kem-768" | "symmetric-256" | "hmac-sha256";
2
+ export type KeyKind = "ed25519" | "rsa" | "ecc" | "x25519" | "ml-kem-512" | "ml-kem-768" | "ml-kem-1024" | "ml-dsa-44" | "ml-dsa-65" | "ml-dsa-87" | "symmetric-256" | "hmac-sha256";
3
3
  export interface KeyMaterial {
4
4
  kind: KeyKind;
5
5
  info: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"keystore.d.ts","sourceRoot":"","sources":["../../src/tools/keystore.ts"],"names":[],"mappings":"AAEA,OAAO,MAAM,MAAM,aAAa,CAAC;AAYjC,MAAM,MAAM,OAAO,GACjB,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,YAAY,GAAG,eAAe,GAAG,aAAa,CAAC;AAG7E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAC;IAEd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE9B,UAAU,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC;IAE9B,SAAS,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC;IAE7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD,eAAO,MAAM,QAAQ,KAAK,CAAC;AAG3B,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AAMtD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAUxE;AAQD,qBAAa,QAAQ;aAIgB,QAAQ,EAAE,MAAM;IAHnD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgC;gBAGlB,QAAQ,GAAE,MAAiB;IAG9D,IAAW,IAAI,IAAI,MAAM,CAExB;IAGM,GAAG,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM;IAiBlC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,WAAW;IAkB3D,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAWjD,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAKtC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;CAOvC;AAGD,eAAO,MAAM,QAAQ,UAAiB,CAAC"}
1
+ {"version":3,"file":"keystore.d.ts","sourceRoot":"","sources":["../../src/tools/keystore.ts"],"names":[],"mappings":"AAEA,OAAO,MAAM,MAAM,aAAa,CAAC;AAajC,MAAM,MAAM,OAAO,GACf,SAAS,GACT,KAAK,GACL,KAAK,GACL,QAAQ,GACR,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,WAAW,GACX,WAAW,GACX,WAAW,GACX,eAAe,GACf,aAAa,CAAC;AAGlB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAC;IAEd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE9B,UAAU,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC;IAE9B,SAAS,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC;IAE7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD,eAAO,MAAM,QAAQ,KAAK,CAAC;AAG3B,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AAMtD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAUxE;AAUD,qBAAa,QAAQ;aAIgB,QAAQ,EAAE,MAAM;IAHnD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgC;gBAGlB,QAAQ,GAAE,MAAiB;IAG9D,IAAW,IAAI,IAAI,MAAM,CAExB;IAGM,GAAG,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM;IAiBlC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,WAAW;IAkB3D,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAWjD,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAKtC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;CAOvC;AAGD,eAAO,MAAM,QAAQ,UAAiB,CAAC"}
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.keyStore = exports.KeyStore = exports.KEY_HANDLE_PATTERN = exports.MAX_KEYS = void 0;
7
7
  exports.symmetricKey = symmetricKey;
8
8
  const node_crypto_1 = __importDefault(require("node:crypto"));
9
+ const crypto_lib_1 = require("@sebastienrousseau/crypto-lib");
9
10
  exports.MAX_KEYS = 64;
10
11
  exports.KEY_HANDLE_PATTERN = "^kh_[0-9a-f]{32}$";
11
12
  function symmetricKey(secret, source) {
@@ -20,7 +21,9 @@ function symmetricKey(secret, source) {
20
21
  };
21
22
  }
22
23
  function wipe(key) {
23
- key.secret?.fill(0);
24
+ if (key.secret) {
25
+ (0, crypto_lib_1.wipeMemory)(key.secret);
26
+ }
24
27
  }
25
28
  class KeyStore {
26
29
  capacity;
@@ -1 +1 @@
1
- {"version":3,"file":"kms.d.ts","sourceRoot":"","sources":["../../src/tools/kms.ts"],"names":[],"mappings":"AAIA,OAAO,EAAY,WAAW,EAAc,MAAM,UAAU,CAAC;AAe7D,eAAO,MAAM,cAAc,KAAK,CAAC;AA2CjC,eAAO,MAAM,OAAO,EAAE,WAmBrB,CAAC;AAMF,eAAO,MAAM,SAAS,EAAE,WAgBvB,CAAC"}
1
+ {"version":3,"file":"kms.d.ts","sourceRoot":"","sources":["../../src/tools/kms.ts"],"names":[],"mappings":"AAKA,OAAO,EAAY,WAAW,EAAc,MAAM,UAAU,CAAC;AAe7D,eAAO,MAAM,cAAc,KAAK,CAAC;AA2CjC,eAAO,MAAM,OAAO,EAAE,WAmBrB,CAAC;AAMF,eAAO,MAAM,SAAS,EAAE,WAgBvB,CAAC"}
package/dist/tools/kms.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.kmsUnwrap = exports.kmsWrap = exports.MAX_KEK_LABELS = void 0;
4
4
  const crypto_kms_1 = require("@sebastienrousseau/crypto-kms");
5
+ const crypto_lib_1 = require("@sebastienrousseau/crypto-lib");
5
6
  const keystore_1 = require("./keystore");
6
7
  const result_1 = require("./result");
7
8
  const symmetric_1 = require("./symmetric");
@@ -45,7 +46,7 @@ const kmsWrap = async (args) => {
45
46
  });
46
47
  }
47
48
  finally {
48
- dek.fill(0);
49
+ (0, crypto_lib_1.wipeMemory)(dek);
49
50
  }
50
51
  };
51
52
  exports.kmsWrap = kmsWrap;
@@ -58,7 +59,7 @@ const kmsUnwrap = async (args) => {
58
59
  const wrapped = Buffer.from(String(args.wrappedKey), "hex");
59
60
  const { plaintext } = await localKms.decrypt(kmsKeyId, wrapped.toString("base64"), wrapContext(keyId));
60
61
  const dek = Buffer.from(plaintext);
61
- plaintext.fill(0);
62
+ (0, crypto_lib_1.wipeMemory)(plaintext);
62
63
  const keyHandle = keystore_1.keyStore.add((0, keystore_1.symmetricKey)(dek, "crypto_kms_unwrap"));
63
64
  return (0, result_1.jsonResult)({ provider, keyId, status: "unwrapped", keyHandle });
64
65
  };
@@ -0,0 +1,12 @@
1
+ import { MCPToolParameterProperty } from "../types";
2
+ export declare const MAX_TEXT_LENGTH = 1048576;
3
+ export declare const MAX_KEY_LENGTH = 16384;
4
+ export declare const HEX_BYTES = "^(?:[0-9a-fA-F]{2})*$";
5
+ export declare const X25519_PUBLIC_KEY_HEX = 64;
6
+ export declare const ML_KEM_768_PUBLIC_KEY_HEX = 2368;
7
+ export declare const HANDLE_NOTE = "Secret key material stays inside the server; only an opaque keyHandle is returned.";
8
+ export declare function keyHandle(description: string): MCPToolParameterProperty;
9
+ export declare function text(description: string): MCPToolParameterProperty;
10
+ export declare function hex(description: string, length: number, upTo?: boolean): MCPToolParameterProperty;
11
+ export declare function oneOf(description: string, values: string[]): MCPToolParameterProperty;
12
+ //# sourceMappingURL=schema-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-helpers.d.ts","sourceRoot":"","sources":["../../src/tools/schema-helpers.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAIpD,eAAO,MAAM,eAAe,UAAY,CAAC;AAGzC,eAAO,MAAM,cAAc,QAAS,CAAC;AAGrC,eAAO,MAAM,SAAS,0BAA0B,CAAC;AAGjD,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAGxC,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAG9C,eAAO,MAAM,WAAW,uFAC8D,CAAC;AAGvF,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,wBAAwB,CAOvE;AAGD,wBAAgB,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,wBAAwB,CAElE;AAGD,wBAAgB,GAAG,CACjB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,IAAI,UAAQ,GACX,wBAAwB,CAQ1B;AAGD,wBAAgB,KAAK,CACnB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EAAE,GACf,wBAAwB,CAE1B"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HANDLE_NOTE = exports.ML_KEM_768_PUBLIC_KEY_HEX = exports.X25519_PUBLIC_KEY_HEX = exports.HEX_BYTES = exports.MAX_KEY_LENGTH = exports.MAX_TEXT_LENGTH = void 0;
4
+ exports.keyHandle = keyHandle;
5
+ exports.text = text;
6
+ exports.hex = hex;
7
+ exports.oneOf = oneOf;
8
+ const keystore_1 = require("./keystore");
9
+ exports.MAX_TEXT_LENGTH = 1_048_576;
10
+ exports.MAX_KEY_LENGTH = 16_384;
11
+ exports.HEX_BYTES = "^(?:[0-9a-fA-F]{2})*$";
12
+ exports.X25519_PUBLIC_KEY_HEX = 64;
13
+ exports.ML_KEM_768_PUBLIC_KEY_HEX = 2368;
14
+ exports.HANDLE_NOTE = "Secret key material stays inside the server; only an opaque keyHandle is returned.";
15
+ function keyHandle(description) {
16
+ return {
17
+ type: "string",
18
+ description: `${description} Key handles look like 'kh_' followed by 32 hex characters.`,
19
+ maxLength: 35,
20
+ pattern: keystore_1.KEY_HANDLE_PATTERN,
21
+ };
22
+ }
23
+ function text(description) {
24
+ return { type: "string", description, maxLength: exports.MAX_TEXT_LENGTH };
25
+ }
26
+ function hex(description, length, upTo = false) {
27
+ return {
28
+ type: "string",
29
+ description,
30
+ minLength: upTo ? 2 : length,
31
+ maxLength: length,
32
+ pattern: exports.HEX_BYTES,
33
+ };
34
+ }
35
+ function oneOf(description, values) {
36
+ return { type: "string", description, enum: values };
37
+ }
38
+ //# sourceMappingURL=schema-helpers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../src/tools/signing.ts"],"names":[],"mappings":"AAKA,OAAO,EAAY,WAAW,EAAc,MAAM,UAAU,CAAC;AA0D7D,eAAO,MAAM,IAAI,EAAE,WAalB,CAAC;AAwDF,eAAO,MAAM,MAAM,EAAE,WASpB,CAAC;AAGF,eAAO,MAAM,IAAI,EAAE,WAUlB,CAAC"}
1
+ {"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../src/tools/signing.ts"],"names":[],"mappings":"AAUA,OAAO,EAAY,WAAW,EAAc,MAAM,UAAU,CAAC;AA6D7D,eAAO,MAAM,IAAI,EAAE,WAmBlB,CAAC;AAmFF,eAAO,MAAM,MAAM,EAAE,WAsBpB,CAAC;AAGF,eAAO,MAAM,IAAI,EAAE,WAUlB,CAAC"}
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.hash = exports.verify = exports.sign = void 0;
7
7
  const node_crypto_1 = __importDefault(require("node:crypto"));
8
+ const crypto_lib_1 = require("@sebastienrousseau/crypto-lib");
8
9
  const definitions_1 = require("./definitions");
9
10
  const keystore_1 = require("./keystore");
10
11
  const result_1 = require("./result");
@@ -12,6 +13,9 @@ const SIGNING_KINDS = [
12
13
  "ed25519",
13
14
  "rsa",
14
15
  "ecc",
16
+ "ml-dsa-44",
17
+ "ml-dsa-65",
18
+ "ml-dsa-87",
15
19
  "hmac-sha256",
16
20
  ];
17
21
  function ecdsaScheme(key) {
@@ -53,6 +57,12 @@ const sign = async (args) => {
53
57
  const signature = hmac(key.secret, data).toString("hex");
54
58
  return (0, result_1.jsonResult)({ algorithm: "hmac-sha256", signature });
55
59
  }
60
+ if (key.kind.startsWith("ml-dsa-")) {
61
+ const level = Number(key.kind.slice(7));
62
+ const secretKeyHex = key.secret.toString("hex");
63
+ const { signature, algorithm } = (0, crypto_lib_1.mlDsaSign)(level, secretKeyHex, data);
64
+ return (0, result_1.jsonResult)({ algorithm, signature });
65
+ }
56
66
  const privateKey = key.privateKey;
57
67
  const scheme = schemeFor(privateKey);
58
68
  const signature = node_crypto_1.default
@@ -72,28 +82,57 @@ function verifyHmac(secret, data, signature) {
72
82
  node_crypto_1.default.timingSafeEqual(signature, expected);
73
83
  return { algorithm: "hmac-sha256", valid };
74
84
  }
85
+ const ML_DSA_LEVELS_BY_LEN = {
86
+ 2624: 44,
87
+ 3904: 65,
88
+ 5184: 87,
89
+ };
90
+ function verifierFromPublic(raw) {
91
+ const pub = raw.trim();
92
+ if (pub.includes("PRIVATE KEY")) {
93
+ throw new Error("publicKey must be a public key, not a private key");
94
+ }
95
+ const mlDsaLevel = /^[0-9a-fA-F]+$/.test(pub)
96
+ ? ML_DSA_LEVELS_BY_LEN[pub.length]
97
+ : undefined;
98
+ if (mlDsaLevel) {
99
+ return { kind: "ml-dsa", level: mlDsaLevel, publicKeyHex: pub };
100
+ }
101
+ return { kind: "asymmetric", publicKey: node_crypto_1.default.createPublicKey(pub) };
102
+ }
103
+ function verifierFromKey(handle) {
104
+ const key = keystore_1.keyStore.use(handle, SIGNING_KINDS);
105
+ if (key.kind === "hmac-sha256") {
106
+ return { kind: "hmac", secret: key.secret };
107
+ }
108
+ if (key.kind.startsWith("ml-dsa-")) {
109
+ const level = Number(key.kind.slice(7));
110
+ return { kind: "ml-dsa", level, publicKeyHex: String(key.info.publicKey) };
111
+ }
112
+ return { kind: "asymmetric", publicKey: key.publicKey };
113
+ }
75
114
  function verifierFor(args) {
76
- const hasPem = args.publicKey !== undefined;
77
- if (hasPem === (args.keyHandle !== undefined)) {
115
+ const hasPub = args.publicKey !== undefined;
116
+ if (hasPub === (args.keyHandle !== undefined)) {
78
117
  throw new Error("Pass exactly one of publicKey or keyHandle");
79
118
  }
80
- if (hasPem) {
81
- const pem = String(args.publicKey);
82
- if (pem.includes("PRIVATE KEY")) {
83
- throw new Error("publicKey must be a public key, not a private key");
84
- }
85
- return { publicKey: node_crypto_1.default.createPublicKey(pem) };
86
- }
87
- const key = keystore_1.keyStore.use(String(args.keyHandle), SIGNING_KINDS);
88
- return key.kind === "hmac-sha256"
89
- ? { secret: key.secret }
90
- : { publicKey: key.publicKey };
119
+ return hasPub
120
+ ? verifierFromPublic(String(args.publicKey))
121
+ : verifierFromKey(String(args.keyHandle));
91
122
  }
92
123
  const verify = async (args) => {
93
124
  const verifier = verifierFor(args);
94
125
  const data = Buffer.from(String(args.data), "utf8");
95
- const signature = Buffer.from(String(args.signature), "hex");
96
- const result = "secret" in verifier
126
+ const signatureHex = String(args.signature);
127
+ if (verifier.kind === "ml-dsa") {
128
+ const res = (0, crypto_lib_1.mlDsaVerify)(verifier.level, verifier.publicKeyHex, data, signatureHex);
129
+ return (0, result_1.jsonResult)({
130
+ algorithm: `ml-dsa-${verifier.level}`,
131
+ valid: res.valid,
132
+ });
133
+ }
134
+ const signature = Buffer.from(signatureHex, "hex");
135
+ const result = verifier.kind === "hmac"
97
136
  ? verifyHmac(verifier.secret, data, signature)
98
137
  : verifyAsymmetric(verifier.publicKey, data, signature);
99
138
  return (0, result_1.jsonResult)(result);
@@ -0,0 +1,3 @@
1
+ import { MCPTool } from "../types";
2
+ export declare const STREAM_TOOLS: MCPTool[];
3
+ //# sourceMappingURL=stream-definitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-definitions.d.ts","sourceRoot":"","sources":["../../src/tools/stream-definitions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AASnC,eAAO,MAAM,YAAY,EAAE,OAAO,EA0JjC,CAAC"}
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STREAM_TOOLS = void 0;
4
+ const schema_helpers_1 = require("./schema-helpers");
5
+ exports.STREAM_TOOLS = [
6
+ {
7
+ name: "crypto_stream_encrypt",
8
+ description: "Encrypt plaintext using post-quantum hybrid STREAM AEAD (X25519 + ML-KEM-768 + XChaCha20-Poly1305) with anti-truncation protection. Returns base64 ciphertext.",
9
+ inputSchema: {
10
+ type: "object",
11
+ additionalProperties: false,
12
+ properties: {
13
+ plaintext: (0, schema_helpers_1.text)("Plaintext string to encrypt."),
14
+ x25519PublicKey: (0, schema_helpers_1.hex)("Hex-encoded X25519 public key (64 hex characters).", schema_helpers_1.X25519_PUBLIC_KEY_HEX),
15
+ mlKemPublicKey: (0, schema_helpers_1.hex)("Hex-encoded ML-KEM-768 public key (2368 hex characters).", schema_helpers_1.ML_KEM_768_PUBLIC_KEY_HEX),
16
+ chunkSize: {
17
+ type: "integer",
18
+ description: "Chunk size in bytes (minimum 64, default 65536).",
19
+ minimum: 64,
20
+ },
21
+ },
22
+ required: ["plaintext", "x25519PublicKey", "mlKemPublicKey"],
23
+ },
24
+ },
25
+ {
26
+ name: "crypto_stream_decrypt",
27
+ description: "Decrypt a post-quantum hybrid STREAM AEAD ciphertext using server-held x25519 and ml-kem-768 key handles. Plaintext memory is wiped after decoding.",
28
+ inputSchema: {
29
+ type: "object",
30
+ additionalProperties: false,
31
+ properties: {
32
+ ciphertext: (0, schema_helpers_1.text)("Base64-encoded STREAM ciphertext."),
33
+ x25519KeyHandle: (0, schema_helpers_1.keyHandle)("Handle of the recipient X25519 key (or 32-byte symmetric-256 key)."),
34
+ mlKemKeyHandle: (0, schema_helpers_1.keyHandle)("Handle of the recipient ML-KEM-768 key."),
35
+ chunkSize: {
36
+ type: "integer",
37
+ description: "Chunk size used during encryption (default 65536).",
38
+ minimum: 64,
39
+ },
40
+ },
41
+ required: ["ciphertext", "x25519KeyHandle", "mlKemKeyHandle"],
42
+ },
43
+ },
44
+ {
45
+ name: "crypto_stream_multi_encrypt",
46
+ description: "Encrypt plaintext for multiple recipients using post-quantum hybrid STREAM AEAD (X25519 + ML-KEM-768 + XChaCha20-Poly1305) with anti-truncation framing. Returns base64 ciphertext.",
47
+ inputSchema: {
48
+ type: "object",
49
+ additionalProperties: false,
50
+ properties: {
51
+ plaintext: (0, schema_helpers_1.text)("Plaintext string to encrypt."),
52
+ recipients: (0, schema_helpers_1.text)("JSON-serialized array of recipient public key descriptors: [{ recipientId, recipientX25519Public, recipientMlKemPublic }]."),
53
+ chunkSize: {
54
+ type: "integer",
55
+ description: "Chunk size in bytes (minimum 1024, maximum 16777216, default 65536).",
56
+ minimum: 1024,
57
+ maximum: 16777216,
58
+ },
59
+ },
60
+ required: ["plaintext", "recipients"],
61
+ },
62
+ },
63
+ {
64
+ name: "crypto_stream_multi_decrypt",
65
+ description: "Decrypt a multi-recipient post-quantum hybrid STREAM AEAD ciphertext using server-held x25519 and ml-kem-768 key handles. Plaintext memory is wiped after decoding.",
66
+ inputSchema: {
67
+ type: "object",
68
+ additionalProperties: false,
69
+ properties: {
70
+ ciphertext: (0, schema_helpers_1.text)("Base64-encoded multi-recipient STREAM ciphertext."),
71
+ x25519KeyHandle: (0, schema_helpers_1.keyHandle)("Handle of the recipient X25519 key (or 32-byte symmetric-256 key)."),
72
+ mlKemKeyHandle: (0, schema_helpers_1.keyHandle)("Handle of the recipient ML-KEM-768 key."),
73
+ recipientId: (0, schema_helpers_1.text)("Optional recipient identifier for direct slot lookup."),
74
+ chunkSize: {
75
+ type: "integer",
76
+ description: "Chunk size in bytes (minimum 1024, maximum 16777216, default 65536).",
77
+ minimum: 1024,
78
+ maximum: 16777216,
79
+ },
80
+ },
81
+ required: ["ciphertext", "x25519KeyHandle", "mlKemKeyHandle"],
82
+ },
83
+ },
84
+ {
85
+ name: "crypto_hybrid_kem_multi_encapsulate",
86
+ description: "Encapsulate a symmetric key for multiple recipients using post-quantum hybrid KEM (X25519 + ML-KEM-768 + AES-256-GCM key wrapping). Returns recipient ciphertexts and a symmetric-256 keyHandle.",
87
+ inputSchema: {
88
+ type: "object",
89
+ additionalProperties: false,
90
+ properties: {
91
+ recipients: (0, schema_helpers_1.text)("JSON-serialized array of recipient public key objects: [{ id?, x25519PublicKey, mlKemPublicKey }]."),
92
+ keyHandle: (0, schema_helpers_1.keyHandle)("Optional handle of an existing symmetric-256 key to encapsulate. If omitted, a fresh 256-bit DEK is generated."),
93
+ },
94
+ required: ["recipients"],
95
+ },
96
+ },
97
+ {
98
+ name: "crypto_hybrid_kem_multi_decapsulate",
99
+ description: "Decapsulate a multi-recipient post-quantum hybrid KEM key using server-held x25519 and ml-kem-768 key handles. Returns a symmetric-256 keyHandle for the recovered DEK.",
100
+ inputSchema: {
101
+ type: "object",
102
+ additionalProperties: false,
103
+ properties: {
104
+ x25519KeyHandle: (0, schema_helpers_1.keyHandle)("Handle of recipient X25519 key."),
105
+ mlKemKeyHandle: (0, schema_helpers_1.keyHandle)("Handle of recipient ML-KEM-768 key."),
106
+ ephemeralPublicKey: (0, schema_helpers_1.hex)("Hex-encoded sender ephemeral X25519 public key (64 hex characters).", schema_helpers_1.X25519_PUBLIC_KEY_HEX),
107
+ mlKemCiphertext: (0, schema_helpers_1.hex)("Hex-encoded ML-KEM-768 ciphertext (2176 hex characters).", 2176, true),
108
+ wrappedKey: (0, schema_helpers_1.text)("Base64-encoded wrapped DEK (RFC 3394 AES Key Wrap)."),
109
+ encryptedKey: (0, schema_helpers_1.text)("Alias for wrappedKey."),
110
+ recipients: (0, schema_helpers_1.text)("Optional JSON-serialized array of encrypted recipient objects: [{ id?, ephemeralPublicKey, mlKemCiphertext, encryptedKey }]."),
111
+ recipientId: (0, schema_helpers_1.text)("Optional recipient ID to select from recipients array."),
112
+ recipientIndex: {
113
+ type: "integer",
114
+ description: "Optional index to select from recipients array (default 0).",
115
+ minimum: 0,
116
+ },
117
+ },
118
+ required: ["x25519KeyHandle", "mlKemKeyHandle"],
119
+ },
120
+ },
121
+ ];
122
+ //# sourceMappingURL=stream-definitions.js.map
@@ -0,0 +1,6 @@
1
+ import { ToolHandler } from "./result";
2
+ export declare const streamEncrypt: ToolHandler;
3
+ export declare const streamDecrypt: ToolHandler;
4
+ export declare const streamMultiEncrypt: ToolHandler;
5
+ export declare const streamMultiDecrypt: ToolHandler;
6
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/tools/stream.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,WAAW,EAAc,MAAM,UAAU,CAAC;AAMnD,eAAO,MAAM,aAAa,EAAE,WAmB3B,CAAC;AAOF,eAAO,MAAM,aAAa,EAAE,WAwB3B,CAAC;AAiBF,eAAO,MAAM,kBAAkB,EAAE,WAkBhC,CAAC;AAOF,eAAO,MAAM,kBAAkB,EAAE,WA4BhC,CAAC"}
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.streamMultiDecrypt = exports.streamMultiEncrypt = exports.streamDecrypt = exports.streamEncrypt = void 0;
4
+ const crypto_lib_1 = require("@sebastienrousseau/crypto-lib");
5
+ const streaming_1 = require("@sebastienrousseau/crypto-lib/streaming");
6
+ const keystore_1 = require("./keystore");
7
+ const result_1 = require("./result");
8
+ const streamEncrypt = async (args) => {
9
+ const plaintext = Buffer.from(String(args.plaintext), "utf8");
10
+ const recipientX25519Public = String(args.x25519PublicKey);
11
+ const recipientMlKemPublic = String(args.mlKemPublicKey);
12
+ const chunkSize = args.chunkSize !== undefined ? Number(args.chunkSize) : undefined;
13
+ const result = (0, streaming_1.streamPqEncrypt)({
14
+ recipientX25519Public,
15
+ recipientMlKemPublic,
16
+ plaintext,
17
+ chunkSize,
18
+ });
19
+ return (0, result_1.jsonResult)({
20
+ algorithm: result.algorithm,
21
+ ciphertext: Buffer.from(result.ciphertext).toString("base64"),
22
+ chunkSize: chunkSize ?? 65536,
23
+ });
24
+ };
25
+ exports.streamEncrypt = streamEncrypt;
26
+ const streamDecrypt = async (args) => {
27
+ const ciphertext = Buffer.from(String(args.ciphertext), "base64");
28
+ const xKey = keystore_1.keyStore.use(String(args.x25519KeyHandle), [
29
+ "x25519",
30
+ "symmetric-256",
31
+ ]);
32
+ const mlKey = keystore_1.keyStore.use(String(args.mlKemKeyHandle), ["ml-kem-768"]);
33
+ const chunkSize = args.chunkSize !== undefined ? Number(args.chunkSize) : undefined;
34
+ const decrypted = (0, streaming_1.streamPqDecrypt)({
35
+ recipientX25519Secret: xKey.secret,
36
+ recipientMlKemSecret: mlKey.secret,
37
+ ciphertext,
38
+ chunkSize,
39
+ });
40
+ const plaintext = Buffer.from(decrypted).toString("utf8");
41
+ (0, crypto_lib_1.wipeMemory)(decrypted);
42
+ return (0, result_1.jsonResult)({
43
+ algorithm: "x25519-ml-kem-768-xchacha20-poly1305-stream",
44
+ plaintext,
45
+ });
46
+ };
47
+ exports.streamDecrypt = streamDecrypt;
48
+ const parseMcpRecipients = (raw) => {
49
+ const list = JSON.parse(String(raw));
50
+ if (!Array.isArray(list) || list.length === 0) {
51
+ throw new Error("recipients must be a non-empty array of recipient objects");
52
+ }
53
+ return list;
54
+ };
55
+ const streamMultiEncrypt = async (args) => {
56
+ const plaintext = Buffer.from(String(args.plaintext), "utf8");
57
+ const recipients = parseMcpRecipients(args.recipients);
58
+ const chunkSize = args.chunkSize !== undefined ? Number(args.chunkSize) : undefined;
59
+ const result = (0, streaming_1.streamMultiPqEncrypt)({
60
+ recipients,
61
+ plaintext,
62
+ chunkSize,
63
+ });
64
+ return (0, result_1.jsonResult)({
65
+ algorithm: result.algorithm,
66
+ ciphertext: Buffer.from(result.ciphertext).toString("base64"),
67
+ recipientCount: result.recipientCount,
68
+ chunkSize: chunkSize ?? 65536,
69
+ });
70
+ };
71
+ exports.streamMultiEncrypt = streamMultiEncrypt;
72
+ const streamMultiDecrypt = async (args) => {
73
+ const ciphertext = Buffer.from(String(args.ciphertext), "base64");
74
+ const xKey = keystore_1.keyStore.use(String(args.x25519KeyHandle), [
75
+ "x25519",
76
+ "symmetric-256",
77
+ ]);
78
+ const mlKey = keystore_1.keyStore.use(String(args.mlKemKeyHandle), ["ml-kem-768"]);
79
+ const recipientId = args.recipientId !== undefined ? String(args.recipientId) : undefined;
80
+ const chunkSize = args.chunkSize !== undefined ? Number(args.chunkSize) : undefined;
81
+ const decrypted = (0, streaming_1.streamMultiPqDecrypt)({
82
+ recipientX25519Secret: xKey.secret,
83
+ recipientMlKemSecret: mlKey.secret,
84
+ ...(recipientId !== undefined ? { recipientId } : {}),
85
+ ciphertext,
86
+ chunkSize,
87
+ });
88
+ const plaintext = Buffer.from(decrypted.plaintext).toString("utf8");
89
+ (0, crypto_lib_1.wipeMemory)(decrypted.plaintext);
90
+ return (0, result_1.jsonResult)({
91
+ algorithm: "multi-x25519-ml-kem-768-xchacha20-poly1305-stream",
92
+ recipientId: decrypted.recipientId,
93
+ plaintext,
94
+ });
95
+ };
96
+ exports.streamMultiDecrypt = streamMultiDecrypt;
97
+ //# sourceMappingURL=stream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"symmetric.d.ts","sourceRoot":"","sources":["../../src/tools/symmetric.ts"],"names":[],"mappings":"AAIA,OAAO,EAAY,WAAW,EAAc,MAAM,UAAU,CAAC;AA0B7D,wBAAgB,eAAe,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAE1D;AAaD,eAAO,MAAM,OAAO,EAAE,WAmBrB,CAAC;AAGF,eAAO,MAAM,OAAO,EAAE,WAWrB,CAAC"}
1
+ {"version":3,"file":"symmetric.d.ts","sourceRoot":"","sources":["../../src/tools/symmetric.ts"],"names":[],"mappings":"AAKA,OAAO,EAAY,WAAW,EAAc,MAAM,UAAU,CAAC;AA0B7D,wBAAgB,eAAe,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAE1D;AAaD,eAAO,MAAM,OAAO,EAAE,WAmBrB,CAAC;AAGF,eAAO,MAAM,OAAO,EAAE,WAarB,CAAC"}
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.decrypt = exports.encrypt = void 0;
7
7
  exports.symmetricSecret = symmetricSecret;
8
8
  const node_crypto_1 = __importDefault(require("node:crypto"));
9
+ const crypto_lib_1 = require("@sebastienrousseau/crypto-lib");
9
10
  const keystore_1 = require("./keystore");
10
11
  const result_1 = require("./result");
11
12
  function aeadAlgorithm(value) {
@@ -63,7 +64,9 @@ const decrypt = async (args) => {
63
64
  decipher.update(Buffer.from(String(args.ciphertext), "hex")),
64
65
  decipher.final(),
65
66
  ]);
66
- return (0, result_1.jsonResult)({ algorithm, plaintext: decrypted.toString("utf8") });
67
+ const plaintext = decrypted.toString("utf8");
68
+ (0, crypto_lib_1.wipeMemory)(decrypted);
69
+ return (0, result_1.jsonResult)({ algorithm, plaintext });
67
70
  };
68
71
  exports.decrypt = decrypt;
69
72
  //# sourceMappingURL=symmetric.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sebastienrousseau/crypto-mcp",
3
- "version": "0.0.9",
3
+ "version": "0.0.25",
4
4
  "description": "Model Context Protocol (MCP) server for the Crypto Service Suite — exposing cryptographic operations, post-quantum primitives, and key management to AI assistants and agentic workflows.",
5
5
  "author": "Sebastien Rousseau <sebastienrousseau@users.noreply.github.com>",
6
6
  "license": "MIT OR Apache-2.0",
@@ -28,9 +28,9 @@
28
28
  "dist/**/*.d.ts.map"
29
29
  ],
30
30
  "dependencies": {
31
- "@sebastienrousseau/crypto-lib": "0.0.9",
32
- "@sebastienrousseau/crypto-kms": "0.0.9",
33
- "@sebastienrousseau/crypto-wasm": "0.0.9"
31
+ "@sebastienrousseau/crypto-kms": "0.0.25",
32
+ "@sebastienrousseau/crypto-lib": "0.0.25",
33
+ "@sebastienrousseau/crypto-wasm": "0.0.25"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/chai": "^5.2.3",