@sebastienrousseau/crypto-server 0.0.8 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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 +126 -0
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +7 -1
- 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 +37 -0
- package/dist/lib/key-store.d.ts.map +1 -0
- package/dist/lib/key-store.js +223 -0
- package/dist/lib/opaque-store.d.ts +34 -0
- package/dist/lib/opaque-store.d.ts.map +1 -0
- package/dist/lib/opaque-store.js +72 -0
- package/dist/lib/problem.d.ts +67 -0
- package/dist/lib/problem.d.ts.map +1 -0
- package/dist/lib/problem.js +162 -0
- package/dist/routes/v1/decrypt.d.ts.map +1 -1
- package/dist/routes/v1/decrypt.js +24 -16
- 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 +10 -12
- 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/hpke.d.ts +3 -0
- package/dist/routes/v2/hpke.d.ts.map +1 -0
- package/dist/routes/v2/hpke.js +168 -0
- package/dist/routes/v2/index.d.ts.map +1 -1
- package/dist/routes/v2/index.js +6 -0
- 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/kms.d.ts +7 -0
- package/dist/routes/v2/kms.d.ts.map +1 -0
- package/dist/routes/v2/kms.js +310 -0
- package/dist/routes/v2/mac.d.ts.map +1 -1
- package/dist/routes/v2/mac.js +10 -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/opaque.d.ts +4 -0
- package/dist/routes/v2/opaque.d.ts.map +1 -0
- package/dist/routes/v2/opaque.js +174 -0
- 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 +33 -24
- package/dist/routes/v2/pq-sign.d.ts.map +1 -1
- package/dist/routes/v2/pq-sign.js +31 -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 +17 -13
- package/dist/routes/v2/stream-schemas.d.ts +296 -0
- package/dist/routes/v2/stream-schemas.d.ts.map +1 -0
- package/dist/routes/v2/stream-schemas.js +207 -0
- package/dist/routes/v2/stream.d.ts.map +1 -1
- package/dist/routes/v2/stream.js +144 -151
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +19 -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/trace.d.ts +12 -0
- package/dist/utils/trace.d.ts.map +1 -0
- package/dist/utils/trace.js +62 -0
- 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 +22 -18
|
@@ -1,44 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
const route_helpers_1 = require("../../utils/route-helpers");
|
|
37
|
-
|
|
4
|
+
function registerEncrypt(app) {
|
|
38
5
|
app.post("/v2/password/encrypt", {
|
|
39
6
|
schema: {
|
|
40
7
|
tags: ["Password Encryption"],
|
|
41
8
|
summary: "Encrypt with password (Argon2id + XChaCha20-Poly1305)",
|
|
9
|
+
description: "Derives the key with Argon2id (t = 3, m = 64 MiB, p = 4) on a worker thread.",
|
|
42
10
|
body: {
|
|
43
11
|
type: "object",
|
|
44
12
|
required: ["password", "plaintext"],
|
|
@@ -50,21 +18,17 @@ exports.default = (app) => {
|
|
|
50
18
|
},
|
|
51
19
|
},
|
|
52
20
|
}, async (request, reply) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return reply.send({
|
|
57
|
-
data: passwordEncrypt({ password, plaintext }),
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Encryption");
|
|
62
|
-
}
|
|
21
|
+
const { password, plaintext } = request.body;
|
|
22
|
+
const result = await request.server.kdf.run("highLevel", "passwordEncrypt", { password, plaintext });
|
|
23
|
+
return reply.send({ data: result });
|
|
63
24
|
});
|
|
25
|
+
}
|
|
26
|
+
function registerDecrypt(app) {
|
|
64
27
|
app.post("/v2/password/decrypt", {
|
|
65
28
|
schema: {
|
|
66
29
|
tags: ["Password Encryption"],
|
|
67
30
|
summary: "Decrypt with password (Argon2id + XChaCha20-Poly1305)",
|
|
31
|
+
description: "Derives the key with the Argon2id parameters stored in the ciphertext, on a worker thread.",
|
|
68
32
|
body: {
|
|
69
33
|
type: "object",
|
|
70
34
|
required: ["password", "ciphertext"],
|
|
@@ -77,9 +41,8 @@ exports.default = (app) => {
|
|
|
77
41
|
},
|
|
78
42
|
}, async (request, reply) => {
|
|
79
43
|
try {
|
|
80
|
-
const { passwordDecrypt } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/dist/high-level/password-encrypt")));
|
|
81
44
|
const { password, ciphertext } = request.body;
|
|
82
|
-
const plaintext = passwordDecrypt
|
|
45
|
+
const plaintext = await request.server.kdf.run("highLevel", "passwordDecrypt", password, ciphertext);
|
|
83
46
|
return reply.send({
|
|
84
47
|
data: Buffer.from(plaintext).toString("utf8"),
|
|
85
48
|
});
|
|
@@ -88,5 +51,9 @@ exports.default = (app) => {
|
|
|
88
51
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Decryption");
|
|
89
52
|
}
|
|
90
53
|
});
|
|
54
|
+
}
|
|
55
|
+
exports.default = (app) => {
|
|
56
|
+
registerEncrypt(app);
|
|
57
|
+
registerDecrypt(app);
|
|
91
58
|
};
|
|
92
59
|
//# sourceMappingURL=password-encrypt.js.map
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { FastifyInstance } from "fastify";
|
|
2
|
+
export declare const ARGON2_FLOORS: Readonly<{
|
|
3
|
+
memoryCostKiB: 19456;
|
|
4
|
+
timeCost: 2;
|
|
5
|
+
}>;
|
|
2
6
|
declare const _default: (app: FastifyInstance) => void;
|
|
3
7
|
export default _default;
|
|
4
8
|
//# sourceMappingURL=password.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/password.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/password.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAY/C,eAAO,MAAM,aAAa;;;EAGxB,CAAC;yBA2Ga,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAGE"}
|
|
@@ -1,78 +1,51 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ARGON2_FLOORS = void 0;
|
|
36
4
|
const route_helpers_1 = require("../../utils/route-helpers");
|
|
37
|
-
exports.
|
|
5
|
+
exports.ARGON2_FLOORS = Object.freeze({
|
|
6
|
+
memoryCostKiB: 19456,
|
|
7
|
+
timeCost: 2,
|
|
8
|
+
});
|
|
9
|
+
function registerHash(app) {
|
|
38
10
|
app.post("/v2/password/hash", {
|
|
39
11
|
config: { rateLimit: { max: 5, timeWindow: "1 minute" } },
|
|
40
12
|
schema: {
|
|
41
13
|
tags: ["Password"],
|
|
42
14
|
summary: "Hash a password with Argon2id",
|
|
15
|
+
description: "Argon2id with at least 19 MiB of memory and two passes (OWASP); defaults are t = 3, m = 64 MiB, p = 4. Runs on a worker thread.",
|
|
43
16
|
body: {
|
|
44
17
|
type: "object",
|
|
45
18
|
required: ["password"],
|
|
46
19
|
additionalProperties: false,
|
|
47
20
|
properties: {
|
|
48
21
|
password: { type: "string", minLength: 1, maxLength: 1024 },
|
|
49
|
-
timeCost: {
|
|
50
|
-
|
|
22
|
+
timeCost: {
|
|
23
|
+
type: "integer",
|
|
24
|
+
minimum: exports.ARGON2_FLOORS.timeCost,
|
|
25
|
+
maximum: 10,
|
|
26
|
+
},
|
|
27
|
+
memoryCost: {
|
|
28
|
+
type: "integer",
|
|
29
|
+
minimum: exports.ARGON2_FLOORS.memoryCostKiB,
|
|
30
|
+
maximum: 262144,
|
|
31
|
+
},
|
|
51
32
|
parallelism: { type: "integer", minimum: 1, maximum: 8 },
|
|
52
33
|
},
|
|
53
34
|
},
|
|
54
35
|
},
|
|
55
36
|
}, async (request, reply) => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const result = hashPassword({
|
|
60
|
-
password: body.password,
|
|
61
|
-
...(body.timeCost ? { timeCost: body.timeCost } : {}),
|
|
62
|
-
...(body.memoryCost ? { memoryCost: body.memoryCost } : {}),
|
|
63
|
-
...(body.parallelism ? { parallelism: body.parallelism } : {}),
|
|
64
|
-
});
|
|
65
|
-
return reply.send({ data: result });
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Password hashing");
|
|
69
|
-
}
|
|
37
|
+
const body = request.body;
|
|
38
|
+
const result = await request.server.kdf.run("modern", "hashPassword", body);
|
|
39
|
+
return reply.send({ data: result });
|
|
70
40
|
});
|
|
41
|
+
}
|
|
42
|
+
function registerVerify(app) {
|
|
71
43
|
app.post("/v2/password/verify", {
|
|
72
44
|
config: { rateLimit: { max: 5, timeWindow: "1 minute" } },
|
|
73
45
|
schema: {
|
|
74
46
|
tags: ["Password"],
|
|
75
47
|
summary: "Verify a password against an Argon2id hash",
|
|
48
|
+
description: "Accepts the parameters of existing hashes, including ones below the floor for new hashes. Runs on a worker thread.",
|
|
76
49
|
body: {
|
|
77
50
|
type: "object",
|
|
78
51
|
required: ["password", "hash", "salt", "params"],
|
|
@@ -96,14 +69,16 @@ exports.default = (app) => {
|
|
|
96
69
|
},
|
|
97
70
|
}, async (request, reply) => {
|
|
98
71
|
try {
|
|
99
|
-
const
|
|
100
|
-
const body = request.body;
|
|
101
|
-
const result = verifyPassword(body);
|
|
72
|
+
const result = await request.server.kdf.run("modern", "verifyPassword", request.body);
|
|
102
73
|
return reply.send({ data: result });
|
|
103
74
|
}
|
|
104
75
|
catch (error) {
|
|
105
76
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Password verification");
|
|
106
77
|
}
|
|
107
78
|
});
|
|
79
|
+
}
|
|
80
|
+
exports.default = (app) => {
|
|
81
|
+
registerHash(app);
|
|
82
|
+
registerVerify(app);
|
|
108
83
|
};
|
|
109
84
|
//# sourceMappingURL=password.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pq-hash-sign.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/pq-hash-sign.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"pq-hash-sign.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/pq-hash-sign.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBAsJ/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAKE"}
|
|
@@ -34,6 +34,7 @@ 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
|
+
const keys_1 = require("../../utils/keys");
|
|
37
38
|
const SLH_DSA_VARIANTS = [
|
|
38
39
|
"sha2-128f",
|
|
39
40
|
"sha2-128s",
|
|
@@ -48,11 +49,14 @@ const SLH_DSA_VARIANTS = [
|
|
|
48
49
|
"shake-256f",
|
|
49
50
|
"shake-256s",
|
|
50
51
|
];
|
|
51
|
-
|
|
52
|
+
const SLH_DSA_ALGORITHMS = SLH_DSA_VARIANTS.map((v) => `slh-dsa-${v}`);
|
|
53
|
+
function registerKeygen(app) {
|
|
52
54
|
app.post("/v2/pq/slh-dsa/keygen", {
|
|
55
|
+
config: { rateLimit: { max: 10, timeWindow: "1 minute" } },
|
|
53
56
|
schema: {
|
|
54
57
|
tags: ["Post-Quantum Hash-Based Signatures"],
|
|
55
|
-
summary: "Generate SLH-DSA key pair (FIPS 205)",
|
|
58
|
+
summary: "Generate a server-held SLH-DSA key pair (FIPS 205)",
|
|
59
|
+
description: "Generates an SLH-DSA key pair, keeps the secret key on the server and returns its keyId with the public key.",
|
|
56
60
|
body: {
|
|
57
61
|
type: "object",
|
|
58
62
|
required: ["variant"],
|
|
@@ -63,42 +67,41 @@ exports.default = (app) => {
|
|
|
63
67
|
},
|
|
64
68
|
},
|
|
65
69
|
}, async (request, reply) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Key generation");
|
|
73
|
-
}
|
|
70
|
+
const { slhDsaKeygen } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/modern")));
|
|
71
|
+
const { variant } = request.body;
|
|
72
|
+
const { publicKey, secretKey, algorithm } = slhDsaKeygen(variant);
|
|
73
|
+
const stored = await (0, keys_1.storeKey)(request, algorithm, { publicKey }, { secretKey });
|
|
74
|
+
return reply.send({ data: (0, keys_1.publicView)(stored) });
|
|
74
75
|
});
|
|
76
|
+
}
|
|
77
|
+
function registerSign(app) {
|
|
75
78
|
app.post("/v2/pq/slh-dsa/sign", {
|
|
79
|
+
config: { rateLimit: { max: 10, timeWindow: "1 minute" } },
|
|
76
80
|
schema: {
|
|
77
81
|
tags: ["Post-Quantum Hash-Based Signatures"],
|
|
78
82
|
summary: "Sign with SLH-DSA (FIPS 205)",
|
|
83
|
+
description: "Signs with a server-held SLH-DSA key (keyId from POST /v2/pq/slh-dsa/keygen); the variant comes from the key.",
|
|
79
84
|
body: {
|
|
80
85
|
type: "object",
|
|
81
|
-
required: ["
|
|
86
|
+
required: ["keyId", "message"],
|
|
82
87
|
additionalProperties: false,
|
|
83
88
|
properties: {
|
|
84
|
-
|
|
85
|
-
secretKey: { type: "string", minLength: 1 },
|
|
89
|
+
keyId: keys_1.KEY_ID_SCHEMA,
|
|
86
90
|
message: { type: "string", minLength: 1 },
|
|
87
91
|
},
|
|
88
92
|
},
|
|
89
93
|
},
|
|
90
94
|
}, async (request, reply) => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Signing");
|
|
100
|
-
}
|
|
95
|
+
const { slhDsaSign } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/modern")));
|
|
96
|
+
const body = request.body;
|
|
97
|
+
const key = await (0, keys_1.resolveKey)(request, body.keyId, SLH_DSA_ALGORITHMS);
|
|
98
|
+
const variant = key.algorithm.slice("slh-dsa-".length);
|
|
99
|
+
return reply.send({
|
|
100
|
+
data: slhDsaSign(variant, key.privateParts["secretKey"], body.message),
|
|
101
|
+
});
|
|
101
102
|
});
|
|
103
|
+
}
|
|
104
|
+
function registerVerify(app) {
|
|
102
105
|
app.post("/v2/pq/slh-dsa/verify", {
|
|
103
106
|
schema: {
|
|
104
107
|
tags: ["Post-Quantum Hash-Based Signatures"],
|
|
@@ -115,9 +118,10 @@ exports.default = (app) => {
|
|
|
115
118
|
},
|
|
116
119
|
},
|
|
117
120
|
},
|
|
121
|
+
config: { rateLimit: { max: 100, timeWindow: "1 minute" } },
|
|
118
122
|
}, async (request, reply) => {
|
|
119
123
|
try {
|
|
120
|
-
const { slhDsaVerify } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/
|
|
124
|
+
const { slhDsaVerify } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/modern")));
|
|
121
125
|
const body = request.body;
|
|
122
126
|
return reply.send({
|
|
123
127
|
data: slhDsaVerify(body.variant, body.publicKey, body.message, body.signature),
|
|
@@ -127,5 +131,10 @@ exports.default = (app) => {
|
|
|
127
131
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Verification");
|
|
128
132
|
}
|
|
129
133
|
});
|
|
134
|
+
}
|
|
135
|
+
exports.default = (app) => {
|
|
136
|
+
registerKeygen(app);
|
|
137
|
+
registerSign(app);
|
|
138
|
+
registerVerify(app);
|
|
130
139
|
};
|
|
131
140
|
//# sourceMappingURL=pq-hash-sign.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pq-sign.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/pq-sign.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"pq-sign.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/pq-sign.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBAoI/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAKE"}
|
|
@@ -34,11 +34,14 @@ 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 ML_DSA_ALGORITHMS = ["ml-dsa-44", "ml-dsa-65", "ml-dsa-87"];
|
|
39
|
+
function registerKeygen(app) {
|
|
38
40
|
app.post("/v2/pq/dsa/keygen", {
|
|
39
41
|
schema: {
|
|
40
42
|
tags: ["Post-Quantum Signatures"],
|
|
41
|
-
summary: "Generate ML-DSA key pair (FIPS 204)",
|
|
43
|
+
summary: "Generate a server-held ML-DSA key pair (FIPS 204)",
|
|
44
|
+
description: "Generates an ML-DSA key pair, keeps the secret key on the server and returns its keyId with the public key.",
|
|
42
45
|
body: {
|
|
43
46
|
type: "object",
|
|
44
47
|
required: ["level"],
|
|
@@ -49,42 +52,40 @@ exports.default = (app) => {
|
|
|
49
52
|
},
|
|
50
53
|
},
|
|
51
54
|
}, async (request, reply) => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Key generation");
|
|
59
|
-
}
|
|
55
|
+
const { mlDsaKeygen } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/modern")));
|
|
56
|
+
const { level } = request.body;
|
|
57
|
+
const { publicKey, secretKey, algorithm } = mlDsaKeygen(level);
|
|
58
|
+
const stored = await (0, keys_1.storeKey)(request, algorithm, { publicKey }, { secretKey });
|
|
59
|
+
return reply.send({ data: (0, keys_1.publicView)(stored) });
|
|
60
60
|
});
|
|
61
|
+
}
|
|
62
|
+
function registerSign(app) {
|
|
61
63
|
app.post("/v2/pq/dsa/sign", {
|
|
62
64
|
schema: {
|
|
63
65
|
tags: ["Post-Quantum Signatures"],
|
|
64
66
|
summary: "Sign with ML-DSA (FIPS 204)",
|
|
67
|
+
description: "Signs with a server-held ML-DSA key (keyId from POST /v2/pq/dsa/keygen or POST /v2/keys/generate); the level comes from the key.",
|
|
65
68
|
body: {
|
|
66
69
|
type: "object",
|
|
67
|
-
required: ["
|
|
70
|
+
required: ["keyId", "message"],
|
|
68
71
|
additionalProperties: false,
|
|
69
72
|
properties: {
|
|
70
|
-
|
|
71
|
-
secretKey: { type: "string", minLength: 1 },
|
|
73
|
+
keyId: keys_1.KEY_ID_SCHEMA,
|
|
72
74
|
message: { type: "string", minLength: 1 },
|
|
73
75
|
},
|
|
74
76
|
},
|
|
75
77
|
},
|
|
76
78
|
}, async (request, reply) => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Signing");
|
|
86
|
-
}
|
|
79
|
+
const { mlDsaSign } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/modern")));
|
|
80
|
+
const body = request.body;
|
|
81
|
+
const key = await (0, keys_1.resolveKey)(request, body.keyId, ML_DSA_ALGORITHMS);
|
|
82
|
+
const level = Number(key.algorithm.slice("ml-dsa-".length));
|
|
83
|
+
return reply.send({
|
|
84
|
+
data: mlDsaSign(level, key.privateParts["secretKey"], body.message),
|
|
85
|
+
});
|
|
87
86
|
});
|
|
87
|
+
}
|
|
88
|
+
function registerVerify(app) {
|
|
88
89
|
app.post("/v2/pq/dsa/verify", {
|
|
89
90
|
schema: {
|
|
90
91
|
tags: ["Post-Quantum Signatures"],
|
|
@@ -101,9 +102,10 @@ exports.default = (app) => {
|
|
|
101
102
|
},
|
|
102
103
|
},
|
|
103
104
|
},
|
|
105
|
+
config: { rateLimit: { max: 100, timeWindow: "1 minute" } },
|
|
104
106
|
}, async (request, reply) => {
|
|
105
107
|
try {
|
|
106
|
-
const { mlDsaVerify } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/
|
|
108
|
+
const { mlDsaVerify } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/modern")));
|
|
107
109
|
const body = request.body;
|
|
108
110
|
return reply.send({
|
|
109
111
|
data: mlDsaVerify(body.level, body.publicKey, body.message, body.signature),
|
|
@@ -113,5 +115,10 @@ exports.default = (app) => {
|
|
|
113
115
|
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Verification");
|
|
114
116
|
}
|
|
115
117
|
});
|
|
118
|
+
}
|
|
119
|
+
exports.default = (app) => {
|
|
120
|
+
registerKeygen(app);
|
|
121
|
+
registerSign(app);
|
|
122
|
+
registerVerify(app);
|
|
116
123
|
};
|
|
117
124
|
//# sourceMappingURL=pq-sign.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pq.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/pq.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pq.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/pq.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBA0P/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAUE"}
|
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"}
|