@sebastienrousseau/crypto-server 0.0.8 → 0.0.9
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 +159 -56
- package/dist/@types/types.d.ts +1 -2
- package/dist/@types/types.d.ts.map +1 -1
- package/dist/config/auth-policy.d.ts +18 -0
- package/dist/config/auth-policy.d.ts.map +1 -1
- package/dist/config/auth-policy.js +109 -0
- package/dist/enterprise/metering.d.ts.map +1 -1
- package/dist/enterprise/metering.js +2 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/auth.d.ts +4 -1
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +87 -40
- package/dist/lib/kdf-runner.d.ts +18 -0
- package/dist/lib/kdf-runner.d.ts.map +1 -0
- package/dist/lib/kdf-runner.js +27 -0
- package/dist/lib/key-store.d.ts +30 -0
- package/dist/lib/key-store.d.ts.map +1 -0
- package/dist/lib/key-store.js +126 -0
- package/dist/lib/problem.d.ts +66 -0
- package/dist/lib/problem.d.ts.map +1 -0
- package/dist/lib/problem.js +152 -0
- package/dist/routes/v1/decrypt.d.ts.map +1 -1
- package/dist/routes/v1/decrypt.js +20 -15
- package/dist/routes/v1/encrypt.d.ts.map +1 -1
- package/dist/routes/v1/encrypt.js +12 -13
- package/dist/routes/v1/generate.d.ts.map +1 -1
- package/dist/routes/v1/generate.js +22 -25
- package/dist/routes/v1/revoke.d.ts.map +1 -1
- package/dist/routes/v1/revoke.js +6 -11
- package/dist/routes/v1/verify.d.ts.map +1 -1
- package/dist/routes/v1/verify.js +6 -11
- package/dist/routes/v2/algorithms.js +1 -1
- package/dist/routes/v2/compliance.js +1 -1
- package/dist/routes/v2/encrypt.d.ts.map +1 -1
- package/dist/routes/v2/encrypt.js +1 -1
- package/dist/routes/v2/hash.d.ts.map +1 -1
- package/dist/routes/v2/hash.js +1 -1
- package/dist/routes/v2/kdf.d.ts +5 -0
- package/dist/routes/v2/kdf.d.ts.map +1 -1
- package/dist/routes/v2/kdf.js +27 -12
- package/dist/routes/v2/key-wrap.d.ts.map +1 -1
- package/dist/routes/v2/key-wrap.js +9 -3
- package/dist/routes/v2/keys.d.ts.map +1 -1
- package/dist/routes/v2/keys.js +39 -26
- package/dist/routes/v2/mac.d.ts.map +1 -1
- package/dist/routes/v2/mac.js +9 -3
- package/dist/routes/v2/multi-recipient.d.ts.map +1 -1
- package/dist/routes/v2/multi-recipient.js +12 -11
- package/dist/routes/v2/password-encrypt.d.ts.map +1 -1
- package/dist/routes/v2/password-encrypt.js +13 -46
- package/dist/routes/v2/password.d.ts +4 -0
- package/dist/routes/v2/password.d.ts.map +1 -1
- package/dist/routes/v2/password.js +28 -53
- package/dist/routes/v2/pq-hash-sign.d.ts.map +1 -1
- package/dist/routes/v2/pq-hash-sign.js +30 -24
- package/dist/routes/v2/pq-sign.d.ts.map +1 -1
- package/dist/routes/v2/pq-sign.js +30 -24
- package/dist/routes/v2/pq.d.ts.map +1 -1
- package/dist/routes/v2/pq.js +57 -38
- package/dist/routes/v2/sealedbox.d.ts.map +1 -1
- package/dist/routes/v2/sealedbox.js +32 -14
- package/dist/routes/v2/secretbox.d.ts.map +1 -1
- package/dist/routes/v2/secretbox.js +10 -3
- package/dist/routes/v2/signing.d.ts.map +1 -1
- package/dist/routes/v2/signing.js +16 -13
- package/dist/routes/v2/stream.d.ts.map +1 -1
- package/dist/routes/v2/stream.js +29 -24
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +15 -5
- package/dist/utils/keys.d.ts +17 -0
- package/dist/utils/keys.d.ts.map +1 -0
- package/dist/utils/keys.js +36 -0
- package/dist/utils/route-helpers.d.ts +1 -5
- package/dist/utils/route-helpers.d.ts.map +1 -1
- package/dist/utils/route-helpers.js +16 -10
- package/dist/utils/validation.d.ts +1 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +17 -9
- package/package.json +20 -17
package/dist/routes/v2/pq.js
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const modern_1 = require("@sebastienrousseau/crypto-lib/
|
|
3
|
+
const modern_1 = require("@sebastienrousseau/crypto-lib/modern");
|
|
4
4
|
const route_helpers_1 = require("../../utils/route-helpers");
|
|
5
|
-
|
|
5
|
+
const keys_1 = require("../../utils/keys");
|
|
6
|
+
const EMPTY_BODY = {
|
|
7
|
+
type: "object",
|
|
8
|
+
additionalProperties: false,
|
|
9
|
+
properties: {},
|
|
10
|
+
};
|
|
11
|
+
function registerMlKemKeygen(app) {
|
|
6
12
|
app.post("/v2/pq/keygen", {
|
|
7
13
|
schema: {
|
|
8
14
|
tags: ["Post-Quantum"],
|
|
9
|
-
summary: "Generate ML-KEM-768 key pair",
|
|
10
|
-
description: "
|
|
11
|
-
body:
|
|
15
|
+
summary: "Generate a server-held ML-KEM-768 key pair",
|
|
16
|
+
description: "Generates a NIST FIPS 203 ML-KEM-768 key pair, keeps the secret key on the server and returns its keyId with the public key.",
|
|
17
|
+
body: EMPTY_BODY,
|
|
12
18
|
},
|
|
13
19
|
}, async (request, reply) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Key generation");
|
|
20
|
-
}
|
|
20
|
+
const { publicKey, secretKey, algorithm } = (0, modern_1.mlKemGenerateKeyPair)();
|
|
21
|
+
const stored = await (0, keys_1.storeKey)(request, algorithm, { publicKey }, { secretKey });
|
|
22
|
+
return reply.send({ data: (0, keys_1.publicView)(stored) });
|
|
21
23
|
});
|
|
24
|
+
}
|
|
25
|
+
function registerMlKemEncapsulate(app) {
|
|
22
26
|
app.post("/v2/pq/encapsulate", {
|
|
23
27
|
schema: {
|
|
24
28
|
tags: ["Post-Quantum"],
|
|
@@ -43,47 +47,56 @@ exports.default = (app) => {
|
|
|
43
47
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Encapsulation");
|
|
44
48
|
}
|
|
45
49
|
});
|
|
50
|
+
}
|
|
51
|
+
function registerMlKemDecapsulate(app) {
|
|
46
52
|
app.post("/v2/pq/decapsulate", {
|
|
47
53
|
schema: {
|
|
48
54
|
tags: ["Post-Quantum"],
|
|
49
55
|
summary: "ML-KEM decapsulate",
|
|
50
|
-
description: "
|
|
56
|
+
description: "Recover the shared secret with a server-held ML-KEM-768 key (keyId from POST /v2/pq/keygen or POST /v2/keys/generate).",
|
|
51
57
|
body: {
|
|
52
58
|
type: "object",
|
|
53
|
-
required: ["
|
|
59
|
+
required: ["keyId", "ciphertext"],
|
|
54
60
|
additionalProperties: false,
|
|
55
61
|
properties: {
|
|
56
|
-
|
|
62
|
+
keyId: keys_1.KEY_ID_SCHEMA,
|
|
57
63
|
ciphertext: { type: "string", minLength: 1 },
|
|
58
64
|
},
|
|
59
65
|
},
|
|
60
66
|
},
|
|
61
67
|
}, async (request, reply) => {
|
|
68
|
+
const { keyId, ciphertext } = request.body;
|
|
69
|
+
const key = await (0, keys_1.resolveKey)(request, keyId, ["ml-kem-768"]);
|
|
62
70
|
try {
|
|
63
|
-
const
|
|
64
|
-
const result = (0, modern_1.mlKemDecapsulate)(secretKey, ciphertext);
|
|
71
|
+
const result = (0, modern_1.mlKemDecapsulate)(key.privateParts["secretKey"], ciphertext);
|
|
65
72
|
return reply.send({ data: result });
|
|
66
73
|
}
|
|
67
74
|
catch (error) {
|
|
68
75
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Decapsulation");
|
|
69
76
|
}
|
|
70
77
|
});
|
|
78
|
+
}
|
|
79
|
+
function registerHybridKeygen(app) {
|
|
71
80
|
app.post("/v2/pq/hybrid/keygen", {
|
|
72
81
|
schema: {
|
|
73
82
|
tags: ["Post-Quantum"],
|
|
74
|
-
summary: "Generate hybrid X25519 + ML-KEM-768 key pair",
|
|
75
|
-
description: "Generates
|
|
76
|
-
body:
|
|
83
|
+
summary: "Generate a server-held hybrid X25519 + ML-KEM-768 key pair",
|
|
84
|
+
description: "Generates classical (X25519) and post-quantum (ML-KEM-768) key pairs for hybrid key exchange, keeps the private keys on the server and returns a keyId with the public keys.",
|
|
85
|
+
body: EMPTY_BODY,
|
|
77
86
|
},
|
|
78
87
|
}, async (request, reply) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
const kp = (0, modern_1.hybridGenerateKeyPair)();
|
|
89
|
+
const stored = await (0, keys_1.storeKey)(request, kp.algorithm, {
|
|
90
|
+
x25519PublicKey: kp.x25519PublicKey,
|
|
91
|
+
mlKemPublicKey: kp.mlKemPublicKey,
|
|
92
|
+
}, {
|
|
93
|
+
x25519PrivateKey: kp.x25519PrivateKey,
|
|
94
|
+
mlKemSecretKey: kp.mlKemSecretKey,
|
|
95
|
+
});
|
|
96
|
+
return reply.send({ data: (0, keys_1.publicView)(stored) });
|
|
86
97
|
});
|
|
98
|
+
}
|
|
99
|
+
function registerHybridEncapsulate(app) {
|
|
87
100
|
app.post("/v2/pq/hybrid/encapsulate", {
|
|
88
101
|
schema: {
|
|
89
102
|
tags: ["Post-Quantum"],
|
|
@@ -109,23 +122,19 @@ exports.default = (app) => {
|
|
|
109
122
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Hybrid encapsulation");
|
|
110
123
|
}
|
|
111
124
|
});
|
|
125
|
+
}
|
|
126
|
+
function registerHybridDecapsulate(app) {
|
|
112
127
|
app.post("/v2/pq/hybrid/decapsulate", {
|
|
113
128
|
schema: {
|
|
114
129
|
tags: ["Post-Quantum"],
|
|
115
130
|
summary: "Hybrid decapsulate (X25519 + ML-KEM-768)",
|
|
116
|
-
description: "Recovers the combined shared secret
|
|
131
|
+
description: "Recovers the combined shared secret with a server-held x25519-ml-kem-768 key (keyId from POST /v2/pq/hybrid/keygen) and the sender's ephemeral data.",
|
|
117
132
|
body: {
|
|
118
133
|
type: "object",
|
|
119
|
-
required: [
|
|
120
|
-
"x25519PrivateKey",
|
|
121
|
-
"mlKemSecretKey",
|
|
122
|
-
"x25519EphemeralPublic",
|
|
123
|
-
"mlKemCiphertext",
|
|
124
|
-
],
|
|
134
|
+
required: ["keyId", "x25519EphemeralPublic", "mlKemCiphertext"],
|
|
125
135
|
additionalProperties: false,
|
|
126
136
|
properties: {
|
|
127
|
-
|
|
128
|
-
mlKemSecretKey: { type: "string", minLength: 1 },
|
|
137
|
+
keyId: keys_1.KEY_ID_SCHEMA,
|
|
129
138
|
x25519EphemeralPublic: {
|
|
130
139
|
type: "string",
|
|
131
140
|
minLength: 64,
|
|
@@ -136,14 +145,24 @@ exports.default = (app) => {
|
|
|
136
145
|
},
|
|
137
146
|
},
|
|
138
147
|
}, async (request, reply) => {
|
|
148
|
+
const body = request.body;
|
|
149
|
+
const key = await (0, keys_1.resolveKey)(request, body.keyId, ["x25519-ml-kem-768"]);
|
|
139
150
|
try {
|
|
140
|
-
const
|
|
141
|
-
const result = (0, modern_1.hybridDecapsulate)(
|
|
151
|
+
const { x25519PrivateKey, mlKemSecretKey } = key.privateParts;
|
|
152
|
+
const result = (0, modern_1.hybridDecapsulate)(x25519PrivateKey, mlKemSecretKey, body.x25519EphemeralPublic, body.mlKemCiphertext);
|
|
142
153
|
return reply.send({ data: result });
|
|
143
154
|
}
|
|
144
155
|
catch (error) {
|
|
145
156
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Hybrid decapsulation");
|
|
146
157
|
}
|
|
147
158
|
});
|
|
159
|
+
}
|
|
160
|
+
exports.default = (app) => {
|
|
161
|
+
registerMlKemKeygen(app);
|
|
162
|
+
registerMlKemEncapsulate(app);
|
|
163
|
+
registerMlKemDecapsulate(app);
|
|
164
|
+
registerHybridKeygen(app);
|
|
165
|
+
registerHybridEncapsulate(app);
|
|
166
|
+
registerHybridDecapsulate(app);
|
|
148
167
|
};
|
|
149
168
|
//# sourceMappingURL=pq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sealedbox.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/sealedbox.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"sealedbox.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/sealedbox.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBAmK/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAKE"}
|
|
@@ -34,7 +34,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
const route_helpers_1 = require("../../utils/route-helpers");
|
|
37
|
-
|
|
37
|
+
const keys_1 = require("../../utils/keys");
|
|
38
|
+
const loadSealedbox = async () => (await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/high-level")))).sealedbox;
|
|
39
|
+
function registerSeal(app) {
|
|
38
40
|
app.post("/v2/sealedbox/seal", {
|
|
39
41
|
schema: {
|
|
40
42
|
tags: ["Sealed Box"],
|
|
@@ -51,7 +53,7 @@ exports.default = (app) => {
|
|
|
51
53
|
},
|
|
52
54
|
}, async (request, reply) => {
|
|
53
55
|
try {
|
|
54
|
-
const { seal } = await
|
|
56
|
+
const { seal } = await loadSealedbox();
|
|
55
57
|
const { recipientPublicKey, plaintext } = request.body;
|
|
56
58
|
return reply.send({ data: seal(recipientPublicKey, plaintext) });
|
|
57
59
|
}
|
|
@@ -59,25 +61,29 @@ exports.default = (app) => {
|
|
|
59
61
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Encryption");
|
|
60
62
|
}
|
|
61
63
|
});
|
|
64
|
+
}
|
|
65
|
+
function registerOpen(app) {
|
|
62
66
|
app.post("/v2/sealedbox/open", {
|
|
63
67
|
schema: {
|
|
64
68
|
tags: ["Sealed Box"],
|
|
65
69
|
summary: "Decrypt an anonymous sealed box (X25519)",
|
|
70
|
+
description: "Opens a sealed box with a server-held x25519 key (keyId from POST /v2/keys/generate).",
|
|
66
71
|
body: {
|
|
67
72
|
type: "object",
|
|
68
|
-
required: ["
|
|
73
|
+
required: ["keyId", "sealed"],
|
|
69
74
|
additionalProperties: false,
|
|
70
75
|
properties: {
|
|
71
|
-
|
|
76
|
+
keyId: keys_1.KEY_ID_SCHEMA,
|
|
72
77
|
sealed: { type: "string", minLength: 1 },
|
|
73
78
|
},
|
|
74
79
|
},
|
|
75
80
|
},
|
|
76
81
|
}, async (request, reply) => {
|
|
82
|
+
const { keyId, sealed } = request.body;
|
|
83
|
+
const key = await (0, keys_1.resolveKey)(request, keyId, ["x25519"]);
|
|
77
84
|
try {
|
|
78
|
-
const { open } = await
|
|
79
|
-
const
|
|
80
|
-
const plaintext = open(recipientSecretKey, sealed);
|
|
85
|
+
const { open } = await loadSealedbox();
|
|
86
|
+
const plaintext = open(key.privateParts["privateKey"], sealed);
|
|
81
87
|
return reply.send({
|
|
82
88
|
data: Buffer.from(plaintext).toString("utf8"),
|
|
83
89
|
});
|
|
@@ -86,6 +92,8 @@ exports.default = (app) => {
|
|
|
86
92
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Decryption");
|
|
87
93
|
}
|
|
88
94
|
});
|
|
95
|
+
}
|
|
96
|
+
function registerSealPq(app) {
|
|
89
97
|
app.post("/v2/sealedbox/seal-pq", {
|
|
90
98
|
schema: {
|
|
91
99
|
tags: ["Sealed Box"],
|
|
@@ -103,7 +111,7 @@ exports.default = (app) => {
|
|
|
103
111
|
},
|
|
104
112
|
}, async (request, reply) => {
|
|
105
113
|
try {
|
|
106
|
-
const { sealPQ } = await
|
|
114
|
+
const { sealPQ } = await loadSealedbox();
|
|
107
115
|
const { x25519PublicKey, mlKemPublicKey, plaintext } = request.body;
|
|
108
116
|
return reply.send({
|
|
109
117
|
data: sealPQ(x25519PublicKey, mlKemPublicKey, plaintext),
|
|
@@ -113,26 +121,30 @@ exports.default = (app) => {
|
|
|
113
121
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Encryption");
|
|
114
122
|
}
|
|
115
123
|
});
|
|
124
|
+
}
|
|
125
|
+
function registerOpenPq(app) {
|
|
116
126
|
app.post("/v2/sealedbox/open-pq", {
|
|
117
127
|
schema: {
|
|
118
128
|
tags: ["Sealed Box"],
|
|
119
129
|
summary: "Decrypt a post-quantum sealed box (X25519 + ML-KEM-768)",
|
|
130
|
+
description: "Opens a hybrid sealed box with a server-held x25519-ml-kem-768 key (keyId from POST /v2/pq/hybrid/keygen).",
|
|
120
131
|
body: {
|
|
121
132
|
type: "object",
|
|
122
|
-
required: ["
|
|
133
|
+
required: ["keyId", "sealed"],
|
|
123
134
|
additionalProperties: false,
|
|
124
135
|
properties: {
|
|
125
|
-
|
|
126
|
-
mlKemSecretKey: { type: "string", minLength: 1 },
|
|
136
|
+
keyId: keys_1.KEY_ID_SCHEMA,
|
|
127
137
|
sealed: { type: "string", minLength: 1 },
|
|
128
138
|
},
|
|
129
139
|
},
|
|
130
140
|
},
|
|
131
141
|
}, async (request, reply) => {
|
|
142
|
+
const { keyId, sealed } = request.body;
|
|
143
|
+
const key = await (0, keys_1.resolveKey)(request, keyId, ["x25519-ml-kem-768"]);
|
|
132
144
|
try {
|
|
133
|
-
const { openPQ } = await
|
|
134
|
-
const {
|
|
135
|
-
const plaintext = openPQ(
|
|
145
|
+
const { openPQ } = await loadSealedbox();
|
|
146
|
+
const { x25519PrivateKey, mlKemSecretKey } = key.privateParts;
|
|
147
|
+
const plaintext = openPQ(x25519PrivateKey, mlKemSecretKey, sealed);
|
|
136
148
|
return reply.send({
|
|
137
149
|
data: Buffer.from(plaintext).toString("utf8"),
|
|
138
150
|
});
|
|
@@ -141,5 +153,11 @@ exports.default = (app) => {
|
|
|
141
153
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Decryption");
|
|
142
154
|
}
|
|
143
155
|
});
|
|
156
|
+
}
|
|
157
|
+
exports.default = (app) => {
|
|
158
|
+
registerSeal(app);
|
|
159
|
+
registerOpen(app);
|
|
160
|
+
registerSealPq(app);
|
|
161
|
+
registerOpenPq(app);
|
|
144
162
|
};
|
|
145
163
|
//# sourceMappingURL=sealedbox.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secretbox.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/secretbox.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"secretbox.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/secretbox.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBAqF/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAGE"}
|
|
@@ -34,7 +34,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
const route_helpers_1 = require("../../utils/route-helpers");
|
|
37
|
-
|
|
37
|
+
const loadSecretbox = async () => (await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/high-level")))).secretbox;
|
|
38
|
+
function registerSeal(app) {
|
|
38
39
|
app.post("/v2/secretbox/seal", {
|
|
39
40
|
schema: {
|
|
40
41
|
tags: ["Secretbox"],
|
|
@@ -52,7 +53,7 @@ exports.default = (app) => {
|
|
|
52
53
|
},
|
|
53
54
|
}, async (request, reply) => {
|
|
54
55
|
try {
|
|
55
|
-
const { seal } = await
|
|
56
|
+
const { seal } = await loadSecretbox();
|
|
56
57
|
const { key, plaintext, aad } = request.body;
|
|
57
58
|
const aadBytes = aad ? Buffer.from(aad, "utf8") : undefined;
|
|
58
59
|
return reply.send({ data: seal(key, plaintext, aadBytes) });
|
|
@@ -61,6 +62,8 @@ exports.default = (app) => {
|
|
|
61
62
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Encryption");
|
|
62
63
|
}
|
|
63
64
|
});
|
|
65
|
+
}
|
|
66
|
+
function registerOpen(app) {
|
|
64
67
|
app.post("/v2/secretbox/open", {
|
|
65
68
|
schema: {
|
|
66
69
|
tags: ["Secretbox"],
|
|
@@ -78,7 +81,7 @@ exports.default = (app) => {
|
|
|
78
81
|
},
|
|
79
82
|
}, async (request, reply) => {
|
|
80
83
|
try {
|
|
81
|
-
const { open } = await
|
|
84
|
+
const { open } = await loadSecretbox();
|
|
82
85
|
const { key, ciphertext, aad } = request.body;
|
|
83
86
|
const aadBytes = aad ? Buffer.from(aad, "utf8") : undefined;
|
|
84
87
|
const plaintext = open(key, ciphertext, aadBytes);
|
|
@@ -90,5 +93,9 @@ exports.default = (app) => {
|
|
|
90
93
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Decryption");
|
|
91
94
|
}
|
|
92
95
|
});
|
|
96
|
+
}
|
|
97
|
+
exports.default = (app) => {
|
|
98
|
+
registerSeal(app);
|
|
99
|
+
registerOpen(app);
|
|
93
100
|
};
|
|
94
101
|
//# sourceMappingURL=secretbox.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/signing.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/signing.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBAyF/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAIE"}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const modern_1 = require("@sebastienrousseau/crypto-lib/
|
|
3
|
+
const modern_1 = require("@sebastienrousseau/crypto-lib/modern");
|
|
4
4
|
const route_helpers_1 = require("../../utils/route-helpers");
|
|
5
|
-
|
|
5
|
+
const keys_1 = require("../../utils/keys");
|
|
6
|
+
function registerSign(app) {
|
|
6
7
|
app.post("/v2/sign", {
|
|
7
8
|
schema: {
|
|
8
9
|
tags: ["Signing"],
|
|
9
10
|
summary: "Sign with Ed25519",
|
|
10
|
-
description: "Create an Ed25519 digital signature over a message.",
|
|
11
|
+
description: "Create an Ed25519 digital signature over a message with a server-held ed25519 key (keyId from POST /v2/keys/generate).",
|
|
11
12
|
body: {
|
|
12
13
|
type: "object",
|
|
13
|
-
required: ["
|
|
14
|
+
required: ["keyId", "message"],
|
|
14
15
|
additionalProperties: false,
|
|
15
16
|
properties: {
|
|
16
|
-
|
|
17
|
+
keyId: keys_1.KEY_ID_SCHEMA,
|
|
17
18
|
message: {
|
|
18
19
|
type: "string",
|
|
19
20
|
minLength: 1,
|
|
@@ -23,15 +24,13 @@ exports.default = (app) => {
|
|
|
23
24
|
},
|
|
24
25
|
},
|
|
25
26
|
}, async (request, reply) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Signing");
|
|
33
|
-
}
|
|
27
|
+
const { keyId, message } = request.body;
|
|
28
|
+
const key = await (0, keys_1.resolveKey)(request, keyId, ["ed25519"]);
|
|
29
|
+
const result = (0, modern_1.ed25519Sign)(key.privateParts["privateKey"], message);
|
|
30
|
+
return reply.send({ data: result });
|
|
34
31
|
});
|
|
32
|
+
}
|
|
33
|
+
function registerVerify(app) {
|
|
35
34
|
app.post("/v2/verify", {
|
|
36
35
|
schema: {
|
|
37
36
|
tags: ["Signing"],
|
|
@@ -62,5 +61,9 @@ exports.default = (app) => {
|
|
|
62
61
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Verification");
|
|
63
62
|
}
|
|
64
63
|
});
|
|
64
|
+
}
|
|
65
|
+
exports.default = (app) => {
|
|
66
|
+
registerSign(app);
|
|
67
|
+
registerVerify(app);
|
|
65
68
|
};
|
|
66
69
|
//# sourceMappingURL=signing.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/stream.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/stream.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;yBAsR/C,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAIE"}
|
package/dist/routes/v2/stream.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const crypto_lib_1 = require("@sebastienrousseau/crypto-lib");
|
|
4
|
-
const
|
|
4
|
+
const protocols_1 = require("@sebastienrousseau/crypto-lib/protocols");
|
|
5
5
|
const route_helpers_1 = require("../../utils/route-helpers");
|
|
6
|
+
const keys_1 = require("../../utils/keys");
|
|
6
7
|
const SIGN_SCHEMA = {
|
|
7
8
|
tags: ["Streaming"],
|
|
8
9
|
summary: "Batch sign messages with sub-millisecond throughput",
|
|
@@ -18,12 +19,12 @@ const SIGN_SCHEMA = {
|
|
|
18
19
|
maxItems: 1000,
|
|
19
20
|
items: {
|
|
20
21
|
type: "object",
|
|
21
|
-
required: ["id", "message", "
|
|
22
|
+
required: ["id", "message", "keyId"],
|
|
22
23
|
additionalProperties: false,
|
|
23
24
|
properties: {
|
|
24
25
|
id: { type: "string" },
|
|
25
26
|
message: { type: "string", minLength: 1 },
|
|
26
|
-
|
|
27
|
+
keyId: keys_1.KEY_ID_SCHEMA,
|
|
27
28
|
},
|
|
28
29
|
},
|
|
29
30
|
},
|
|
@@ -129,28 +130,32 @@ const ISO20022_SCHEMA = {
|
|
|
129
130
|
},
|
|
130
131
|
},
|
|
131
132
|
};
|
|
133
|
+
async function resolveBatchKeys(request, items) {
|
|
134
|
+
const keys = new Map();
|
|
135
|
+
for (const keyId of new Set(items.map((i) => i.keyId))) {
|
|
136
|
+
keys.set(keyId, await (0, keys_1.resolveKey)(request, keyId, ["ed25519"]));
|
|
137
|
+
}
|
|
138
|
+
return keys;
|
|
139
|
+
}
|
|
132
140
|
function registerBatchSign(app) {
|
|
133
141
|
app.post("/v2/stream/sign", { schema: SIGN_SCHEMA }, async (request, reply) => {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
catch (error) {
|
|
152
|
-
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Batch signing");
|
|
153
|
-
}
|
|
142
|
+
const { items } = request.body;
|
|
143
|
+
const keys = await resolveBatchKeys(request, items);
|
|
144
|
+
const signatures = items.map((item) => {
|
|
145
|
+
const key = keys.get(item.keyId);
|
|
146
|
+
const res = (0, crypto_lib_1.ed25519Sign)(key.privateParts["privateKey"], item.message);
|
|
147
|
+
return {
|
|
148
|
+
id: item.id,
|
|
149
|
+
signature: res.signature,
|
|
150
|
+
algorithm: "ed25519",
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
return reply.send({
|
|
154
|
+
data: {
|
|
155
|
+
count: signatures.length,
|
|
156
|
+
signatures,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
154
159
|
});
|
|
155
160
|
}
|
|
156
161
|
function registerBatchVerify(app) {
|
|
@@ -187,7 +192,7 @@ function registerIso20022Verify(app) {
|
|
|
187
192
|
app.post("/v2/stream/iso20022", { schema: ISO20022_SCHEMA }, async (request, reply) => {
|
|
188
193
|
try {
|
|
189
194
|
const { envelope, payload, trustedKeys } = request.body;
|
|
190
|
-
const result = (0,
|
|
195
|
+
const result = (0, protocols_1.verifyIso20022Payment)(envelope, payload, {
|
|
191
196
|
classicalPublicKeyHex: trustedKeys.classicalPublicKey,
|
|
192
197
|
postQuantumPublicKeyHex: trustedKeys.postQuantumPublicKey,
|
|
193
198
|
});
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AA2CA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAuCnC,iBAAe,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CA6EtD;AAED,OAAO,EAAE,IAAI,EAAE,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -50,12 +50,13 @@ const swagger_ui_1 = __importDefault(require("@fastify/swagger-ui"));
|
|
|
50
50
|
const crypto_1 = require("crypto");
|
|
51
51
|
const logger_1 = __importDefault(require("./lib/logger"));
|
|
52
52
|
const auth_1 = require("./lib/auth");
|
|
53
|
+
const auth_policy_1 = require("./config/auth-policy");
|
|
53
54
|
const metering_1 = require("./enterprise/metering");
|
|
55
|
+
const key_store_1 = require("./lib/key-store");
|
|
56
|
+
const kdf_runner_1 = require("./lib/kdf-runner");
|
|
57
|
+
const problem_1 = require("./lib/problem");
|
|
54
58
|
const routes_1 = __importDefault(require("./routes"));
|
|
55
59
|
const fastify = __importStar(require("fastify"));
|
|
56
|
-
function isPublicPath(url) {
|
|
57
|
-
return (0, constants_1.isProbePath)(url) || url.startsWith("/docs");
|
|
58
|
-
}
|
|
59
60
|
async function registerDocs(app) {
|
|
60
61
|
await app.register(swagger_1.default, {
|
|
61
62
|
openapi: {
|
|
@@ -82,7 +83,12 @@ async function registerDocs(app) {
|
|
|
82
83
|
}
|
|
83
84
|
async function init() {
|
|
84
85
|
const app = fastify.fastify(constants_1.fastifyOptions);
|
|
86
|
+
const registered = [];
|
|
87
|
+
app.addHook("onRoute", (route) => {
|
|
88
|
+
registered.push({ method: route.method, url: route.url });
|
|
89
|
+
});
|
|
85
90
|
logger_1.default.info("\n\nEnvironment details: " + constants_1.consoleOutput);
|
|
91
|
+
(0, problem_1.registerProblemHandlers)(app);
|
|
86
92
|
app.addHook("onRequest", async (request, reply) => {
|
|
87
93
|
const reqId = request.headers["x-request-id"] ?? (0, crypto_1.randomUUID)();
|
|
88
94
|
reply.header("x-request-id", reqId);
|
|
@@ -107,18 +113,22 @@ async function init() {
|
|
|
107
113
|
});
|
|
108
114
|
await (0, auth_1.registerAuth)(app);
|
|
109
115
|
app.addHook("onRequest", async (request, reply) => {
|
|
110
|
-
if (
|
|
116
|
+
if ((0, auth_policy_1.isPublicRoute)(request.url))
|
|
111
117
|
return;
|
|
112
118
|
const auth = await (0, auth_1.authenticate)(request, reply);
|
|
113
|
-
if (!auth)
|
|
119
|
+
if (!auth || !(0, auth_1.authorizeRoute)(request, reply, auth))
|
|
114
120
|
return reply;
|
|
115
121
|
request.auth = auth;
|
|
116
122
|
});
|
|
123
|
+
app.decorate("keyStore", (0, key_store_1.keyStoreFromEnv)());
|
|
124
|
+
app.decorate("kdf", new kdf_runner_1.KdfRunner());
|
|
125
|
+
app.addHook("onClose", () => app.kdf.close());
|
|
117
126
|
(0, metering_1.registerMetering)(app);
|
|
118
127
|
await app.register(async (scope) => {
|
|
119
128
|
(0, routes_1.default)(scope);
|
|
120
129
|
});
|
|
121
130
|
await app.ready();
|
|
131
|
+
(0, auth_policy_1.assertRoutesCovered)(registered);
|
|
122
132
|
return app;
|
|
123
133
|
}
|
|
124
134
|
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { FastifyRequest } from "fastify";
|
|
2
|
+
import { type KeyParts, type KeyStore, type StoredKey } from "../lib/key-store";
|
|
3
|
+
declare module "fastify" {
|
|
4
|
+
interface FastifyInstance {
|
|
5
|
+
keyStore: KeyStore;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export declare const KEY_ID_SCHEMA: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly pattern: "^k_[A-Za-z0-9_-]{22}$";
|
|
11
|
+
readonly description: "Identifier of a server-held key, returned by a key-generation route.";
|
|
12
|
+
};
|
|
13
|
+
export declare function resolveKey(request: FastifyRequest, keyId: string, algorithms?: readonly string[]): Promise<StoredKey>;
|
|
14
|
+
export declare function storeKey(request: FastifyRequest, algorithm: string, publicParts: KeyParts, privateParts: KeyParts): Promise<StoredKey>;
|
|
15
|
+
export declare function serverPgpPrivateKey(): Promise<string>;
|
|
16
|
+
export declare function publicView(key: StoredKey): Record<string, string>;
|
|
17
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/utils/keys.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,eAAe;QAEvB,QAAQ,EAAE,QAAQ,CAAC;KACpB;CACF;AAGD,eAAO,MAAM,aAAa;;;;CAKhB,CAAC;AAeX,wBAAgB,UAAU,CACxB,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,GAC7B,OAAO,CAAC,SAAS,CAAC,CAEpB;AAGD,wBAAgB,QAAQ,CACtB,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,QAAQ,EACrB,YAAY,EAAE,QAAQ,GACrB,OAAO,CAAC,SAAS,CAAC,CAOpB;AAOD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAG3D;AAGD,wBAAgB,UAAU,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEjE"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KEY_ID_SCHEMA = void 0;
|
|
4
|
+
exports.resolveKey = resolveKey;
|
|
5
|
+
exports.storeKey = storeKey;
|
|
6
|
+
exports.serverPgpPrivateKey = serverPgpPrivateKey;
|
|
7
|
+
exports.publicView = publicView;
|
|
8
|
+
const pgp_1 = require("@sebastienrousseau/crypto-lib/pgp");
|
|
9
|
+
const key_store_1 = require("../lib/key-store");
|
|
10
|
+
exports.KEY_ID_SCHEMA = {
|
|
11
|
+
type: "string",
|
|
12
|
+
pattern: key_store_1.KEY_ID_PATTERN,
|
|
13
|
+
description: "Identifier of a server-held key, returned by a key-generation route.",
|
|
14
|
+
};
|
|
15
|
+
function principalOf(request) {
|
|
16
|
+
return request.auth.sub;
|
|
17
|
+
}
|
|
18
|
+
function resolveKey(request, keyId, algorithms) {
|
|
19
|
+
return request.server.keyStore.get(keyId, principalOf(request), algorithms);
|
|
20
|
+
}
|
|
21
|
+
function storeKey(request, algorithm, publicParts, privateParts) {
|
|
22
|
+
return request.server.keyStore.put({
|
|
23
|
+
algorithm,
|
|
24
|
+
owner: principalOf(request),
|
|
25
|
+
publicParts,
|
|
26
|
+
privateParts,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
async function serverPgpPrivateKey() {
|
|
30
|
+
const { privateKeyArmored } = await (0, pgp_1.loadKeystore)();
|
|
31
|
+
return Buffer.from(privateKeyArmored, "latin1").toString("base64");
|
|
32
|
+
}
|
|
33
|
+
function publicView(key) {
|
|
34
|
+
return { keyId: key.keyId, algorithm: key.algorithm, ...key.publicParts };
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -7,9 +7,5 @@ export declare function classifyCryptoError(error: unknown, request: {
|
|
|
7
7
|
log: {
|
|
8
8
|
error: (err: unknown, msg: string) => void;
|
|
9
9
|
};
|
|
10
|
-
}, reply:
|
|
11
|
-
status: (code: number) => {
|
|
12
|
-
send: (body: unknown) => unknown;
|
|
13
|
-
};
|
|
14
|
-
}, operation: string): unknown;
|
|
10
|
+
}, reply: FastifyReply, operation: string): FastifyReply;
|
|
15
11
|
//# sourceMappingURL=route-helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/route-helpers.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"route-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/route-helpers.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAGL,gBAAgB,EACjB,MAAM,cAAc,CAAC;AAOtB,wBAAgB,iBAAiB,CAC/B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAEnD,OAAO,EAAE,CAAC,EACV,KAAK,EAAE,YAAY,GAEjB;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,gBAAgB,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CAAE,GACtE,IAAI,CAmBP;AAsBD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;IAAE,GAAG,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAA;CAAE,EAChE,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,MAAM,GAChB,YAAY,CA6Bd"}
|