@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.
Files changed (102) hide show
  1. package/README.md +159 -56
  2. package/dist/@types/types.d.ts +1 -2
  3. package/dist/@types/types.d.ts.map +1 -1
  4. package/dist/config/auth-policy.d.ts +18 -0
  5. package/dist/config/auth-policy.d.ts.map +1 -1
  6. package/dist/config/auth-policy.js +126 -0
  7. package/dist/config/constants.d.ts.map +1 -1
  8. package/dist/config/constants.js +7 -1
  9. package/dist/enterprise/metering.d.ts.map +1 -1
  10. package/dist/enterprise/metering.js +2 -4
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.js +1 -0
  13. package/dist/lib/auth.d.ts +4 -1
  14. package/dist/lib/auth.d.ts.map +1 -1
  15. package/dist/lib/auth.js +87 -40
  16. package/dist/lib/kdf-runner.d.ts +18 -0
  17. package/dist/lib/kdf-runner.d.ts.map +1 -0
  18. package/dist/lib/kdf-runner.js +27 -0
  19. package/dist/lib/key-store.d.ts +37 -0
  20. package/dist/lib/key-store.d.ts.map +1 -0
  21. package/dist/lib/key-store.js +223 -0
  22. package/dist/lib/opaque-store.d.ts +34 -0
  23. package/dist/lib/opaque-store.d.ts.map +1 -0
  24. package/dist/lib/opaque-store.js +72 -0
  25. package/dist/lib/problem.d.ts +67 -0
  26. package/dist/lib/problem.d.ts.map +1 -0
  27. package/dist/lib/problem.js +162 -0
  28. package/dist/routes/v1/decrypt.d.ts.map +1 -1
  29. package/dist/routes/v1/decrypt.js +24 -16
  30. package/dist/routes/v1/encrypt.d.ts.map +1 -1
  31. package/dist/routes/v1/encrypt.js +12 -13
  32. package/dist/routes/v1/generate.d.ts.map +1 -1
  33. package/dist/routes/v1/generate.js +22 -25
  34. package/dist/routes/v1/revoke.d.ts.map +1 -1
  35. package/dist/routes/v1/revoke.js +6 -11
  36. package/dist/routes/v1/verify.d.ts.map +1 -1
  37. package/dist/routes/v1/verify.js +10 -12
  38. package/dist/routes/v2/algorithms.js +1 -1
  39. package/dist/routes/v2/compliance.js +1 -1
  40. package/dist/routes/v2/encrypt.d.ts.map +1 -1
  41. package/dist/routes/v2/encrypt.js +1 -1
  42. package/dist/routes/v2/hash.d.ts.map +1 -1
  43. package/dist/routes/v2/hash.js +1 -1
  44. package/dist/routes/v2/hpke.d.ts +3 -0
  45. package/dist/routes/v2/hpke.d.ts.map +1 -0
  46. package/dist/routes/v2/hpke.js +168 -0
  47. package/dist/routes/v2/index.d.ts.map +1 -1
  48. package/dist/routes/v2/index.js +6 -0
  49. package/dist/routes/v2/kdf.d.ts +5 -0
  50. package/dist/routes/v2/kdf.d.ts.map +1 -1
  51. package/dist/routes/v2/kdf.js +27 -12
  52. package/dist/routes/v2/key-wrap.d.ts.map +1 -1
  53. package/dist/routes/v2/key-wrap.js +9 -3
  54. package/dist/routes/v2/keys.d.ts.map +1 -1
  55. package/dist/routes/v2/keys.js +39 -26
  56. package/dist/routes/v2/kms.d.ts +7 -0
  57. package/dist/routes/v2/kms.d.ts.map +1 -0
  58. package/dist/routes/v2/kms.js +310 -0
  59. package/dist/routes/v2/mac.d.ts.map +1 -1
  60. package/dist/routes/v2/mac.js +10 -3
  61. package/dist/routes/v2/multi-recipient.d.ts.map +1 -1
  62. package/dist/routes/v2/multi-recipient.js +12 -11
  63. package/dist/routes/v2/opaque.d.ts +4 -0
  64. package/dist/routes/v2/opaque.d.ts.map +1 -0
  65. package/dist/routes/v2/opaque.js +174 -0
  66. package/dist/routes/v2/password-encrypt.d.ts.map +1 -1
  67. package/dist/routes/v2/password-encrypt.js +13 -46
  68. package/dist/routes/v2/password.d.ts +4 -0
  69. package/dist/routes/v2/password.d.ts.map +1 -1
  70. package/dist/routes/v2/password.js +28 -53
  71. package/dist/routes/v2/pq-hash-sign.d.ts.map +1 -1
  72. package/dist/routes/v2/pq-hash-sign.js +33 -24
  73. package/dist/routes/v2/pq-sign.d.ts.map +1 -1
  74. package/dist/routes/v2/pq-sign.js +31 -24
  75. package/dist/routes/v2/pq.d.ts.map +1 -1
  76. package/dist/routes/v2/pq.js +57 -38
  77. package/dist/routes/v2/sealedbox.d.ts.map +1 -1
  78. package/dist/routes/v2/sealedbox.js +32 -14
  79. package/dist/routes/v2/secretbox.d.ts.map +1 -1
  80. package/dist/routes/v2/secretbox.js +10 -3
  81. package/dist/routes/v2/signing.d.ts.map +1 -1
  82. package/dist/routes/v2/signing.js +17 -13
  83. package/dist/routes/v2/stream-schemas.d.ts +296 -0
  84. package/dist/routes/v2/stream-schemas.d.ts.map +1 -0
  85. package/dist/routes/v2/stream-schemas.js +207 -0
  86. package/dist/routes/v2/stream.d.ts.map +1 -1
  87. package/dist/routes/v2/stream.js +144 -151
  88. package/dist/server.d.ts.map +1 -1
  89. package/dist/server.js +19 -5
  90. package/dist/utils/keys.d.ts +17 -0
  91. package/dist/utils/keys.d.ts.map +1 -0
  92. package/dist/utils/keys.js +36 -0
  93. package/dist/utils/route-helpers.d.ts +1 -5
  94. package/dist/utils/route-helpers.d.ts.map +1 -1
  95. package/dist/utils/route-helpers.js +16 -10
  96. package/dist/utils/trace.d.ts +12 -0
  97. package/dist/utils/trace.d.ts.map +1 -0
  98. package/dist/utils/trace.js +62 -0
  99. package/dist/utils/validation.d.ts +1 -0
  100. package/dist/utils/validation.d.ts.map +1 -1
  101. package/dist/utils/validation.js +17 -9
  102. 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
- exports.default = (app) => {
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
- try {
54
- const { passwordEncrypt } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/dist/high-level/password-encrypt")));
55
- const { password, plaintext } = request.body;
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(password, ciphertext);
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;yBAI/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAiGE"}
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.default = (app) => {
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: { type: "integer", minimum: 1, maximum: 10 },
50
- memoryCost: { type: "integer", minimum: 1024, maximum: 262144 },
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
- try {
57
- const { hashPassword } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/dist/modern/password")));
58
- const body = request.body;
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 { verifyPassword } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/dist/modern/password")));
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;yBAqB/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAiHE"}
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
- exports.default = (app) => {
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
- try {
67
- const { slhDsaKeygen } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/dist/modern/pq-hash-sign")));
68
- const { variant } = request.body;
69
- return reply.send({ data: slhDsaKeygen(variant) });
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: ["variant", "secretKey", "message"],
86
+ required: ["keyId", "message"],
82
87
  additionalProperties: false,
83
88
  properties: {
84
- variant: { type: "string", enum: SLH_DSA_VARIANTS },
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
- try {
92
- const { slhDsaSign } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/dist/modern/pq-hash-sign")));
93
- const body = request.body;
94
- return reply.send({
95
- data: slhDsaSign(body.variant, body.secretKey, body.message),
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/dist/modern/pq-hash-sign")));
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;yBAI/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBA6GE"}
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
- exports.default = (app) => {
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
- try {
53
- const { mlDsaKeygen } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/dist/modern/pq-sign")));
54
- const { level } = request.body;
55
- return reply.send({ data: mlDsaKeygen(level) });
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: ["level", "secretKey", "message"],
70
+ required: ["keyId", "message"],
68
71
  additionalProperties: false,
69
72
  properties: {
70
- level: { type: "number", enum: [44, 65, 87] },
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
- try {
78
- const { mlDsaSign } = await Promise.resolve().then(() => __importStar(require("@sebastienrousseau/crypto-lib/dist/modern/pq-sign")));
79
- const body = request.body;
80
- return reply.send({
81
- data: mlDsaSign(body.level, body.secretKey, body.message),
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/dist/modern/pq-sign")));
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":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBAY/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBA4ME"}
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"}
@@ -1,24 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const modern_1 = require("@sebastienrousseau/crypto-lib/dist/modern");
3
+ const modern_1 = require("@sebastienrousseau/crypto-lib/modern");
4
4
  const route_helpers_1 = require("../../utils/route-helpers");
5
- exports.default = (app) => {
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: "Generate a NIST FIPS 203 ML-KEM-768 key pair for quantum-resistant key encapsulation.",
11
- body: { type: "object", additionalProperties: false, properties: {} },
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
- try {
15
- const keyPair = (0, modern_1.mlKemGenerateKeyPair)();
16
- return reply.send({ data: keyPair });
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: "Decapsulate and recover the shared secret using the ML-KEM secret key.",
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: ["secretKey", "ciphertext"],
59
+ required: ["keyId", "ciphertext"],
54
60
  additionalProperties: false,
55
61
  properties: {
56
- secretKey: { type: "string", minLength: 1 },
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 { secretKey, ciphertext } = request.body;
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 both classical (X25519) and post-quantum (ML-KEM-768) key pairs for hybrid key exchange.",
76
- body: { type: "object", additionalProperties: false, properties: {} },
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
- try {
80
- const keyPair = (0, modern_1.hybridGenerateKeyPair)();
81
- return reply.send({ data: keyPair });
82
- }
83
- catch (error) {
84
- return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Key generation");
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 using private keys and sender's ephemeral data.",
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
- x25519PrivateKey: { type: "string", minLength: 64, maxLength: 64 },
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 body = request.body;
141
- const result = (0, modern_1.hybridDecapsulate)(body.x25519PrivateKey, body.mlKemSecretKey, body.x25519EphemeralPublic, body.mlKemCiphertext);
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;yBAI/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBA6IE"}
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"}