@enbox/crypto 0.0.1

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 (283) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +708 -0
  3. package/dist/browser.js +64 -0
  4. package/dist/browser.js.map +7 -0
  5. package/dist/browser.mjs +64 -0
  6. package/dist/browser.mjs.map +7 -0
  7. package/dist/cjs/algorithms/aes-ctr.js +188 -0
  8. package/dist/cjs/algorithms/aes-ctr.js.map +1 -0
  9. package/dist/cjs/algorithms/aes-gcm.js +196 -0
  10. package/dist/cjs/algorithms/aes-gcm.js.map +1 -0
  11. package/dist/cjs/algorithms/crypto-algorithm.js +13 -0
  12. package/dist/cjs/algorithms/crypto-algorithm.js.map +1 -0
  13. package/dist/cjs/algorithms/ecdsa.js +352 -0
  14. package/dist/cjs/algorithms/ecdsa.js.map +1 -0
  15. package/dist/cjs/algorithms/eddsa.js +325 -0
  16. package/dist/cjs/algorithms/eddsa.js.map +1 -0
  17. package/dist/cjs/algorithms/sha-2.js +119 -0
  18. package/dist/cjs/algorithms/sha-2.js.map +1 -0
  19. package/dist/cjs/index.js +41 -0
  20. package/dist/cjs/index.js.map +1 -0
  21. package/dist/cjs/jose/jwe.js +3 -0
  22. package/dist/cjs/jose/jwe.js.map +1 -0
  23. package/dist/cjs/jose/jwk.js +278 -0
  24. package/dist/cjs/jose/jwk.js.map +1 -0
  25. package/dist/cjs/jose/jws.js +3 -0
  26. package/dist/cjs/jose/jws.js.map +1 -0
  27. package/dist/cjs/jose/jwt.js +3 -0
  28. package/dist/cjs/jose/jwt.js.map +1 -0
  29. package/dist/cjs/jose/utils.js +60 -0
  30. package/dist/cjs/jose/utils.js.map +1 -0
  31. package/dist/cjs/local-key-manager.js +521 -0
  32. package/dist/cjs/local-key-manager.js.map +1 -0
  33. package/dist/cjs/package.json +1 -0
  34. package/dist/cjs/primitives/aes-ctr.js +398 -0
  35. package/dist/cjs/primitives/aes-ctr.js.map +1 -0
  36. package/dist/cjs/primitives/aes-gcm.js +425 -0
  37. package/dist/cjs/primitives/aes-gcm.js.map +1 -0
  38. package/dist/cjs/primitives/concat-kdf.js +215 -0
  39. package/dist/cjs/primitives/concat-kdf.js.map +1 -0
  40. package/dist/cjs/primitives/ed25519.js +651 -0
  41. package/dist/cjs/primitives/ed25519.js.map +1 -0
  42. package/dist/cjs/primitives/pbkdf2.js +120 -0
  43. package/dist/cjs/primitives/pbkdf2.js.map +1 -0
  44. package/dist/cjs/primitives/secp256k1.js +958 -0
  45. package/dist/cjs/primitives/secp256k1.js.map +1 -0
  46. package/dist/cjs/primitives/secp256r1.js +959 -0
  47. package/dist/cjs/primitives/secp256r1.js.map +1 -0
  48. package/dist/cjs/primitives/sha256.js +93 -0
  49. package/dist/cjs/primitives/sha256.js.map +1 -0
  50. package/dist/cjs/primitives/x25519.js +498 -0
  51. package/dist/cjs/primitives/x25519.js.map +1 -0
  52. package/dist/cjs/primitives/xchacha20-poly1305.js +340 -0
  53. package/dist/cjs/primitives/xchacha20-poly1305.js.map +1 -0
  54. package/dist/cjs/primitives/xchacha20.js +316 -0
  55. package/dist/cjs/primitives/xchacha20.js.map +1 -0
  56. package/dist/cjs/types/cipher.js +3 -0
  57. package/dist/cjs/types/cipher.js.map +1 -0
  58. package/dist/cjs/types/crypto-api.js +3 -0
  59. package/dist/cjs/types/crypto-api.js.map +1 -0
  60. package/dist/cjs/types/hasher.js +3 -0
  61. package/dist/cjs/types/hasher.js.map +1 -0
  62. package/dist/cjs/types/identifier.js +3 -0
  63. package/dist/cjs/types/identifier.js.map +1 -0
  64. package/dist/cjs/types/key-compressor.js +3 -0
  65. package/dist/cjs/types/key-compressor.js.map +1 -0
  66. package/dist/cjs/types/key-converter.js +3 -0
  67. package/dist/cjs/types/key-converter.js.map +1 -0
  68. package/dist/cjs/types/key-deriver.js +3 -0
  69. package/dist/cjs/types/key-deriver.js.map +1 -0
  70. package/dist/cjs/types/key-generator.js +3 -0
  71. package/dist/cjs/types/key-generator.js.map +1 -0
  72. package/dist/cjs/types/key-io.js +3 -0
  73. package/dist/cjs/types/key-io.js.map +1 -0
  74. package/dist/cjs/types/key-wrapper.js +3 -0
  75. package/dist/cjs/types/key-wrapper.js.map +1 -0
  76. package/dist/cjs/types/params-direct.js +3 -0
  77. package/dist/cjs/types/params-direct.js.map +1 -0
  78. package/dist/cjs/types/params-enclosed.js +3 -0
  79. package/dist/cjs/types/params-enclosed.js.map +1 -0
  80. package/dist/cjs/types/params-kms.js +3 -0
  81. package/dist/cjs/types/params-kms.js.map +1 -0
  82. package/dist/cjs/types/signer.js +3 -0
  83. package/dist/cjs/types/signer.js.map +1 -0
  84. package/dist/cjs/utils.js +173 -0
  85. package/dist/cjs/utils.js.map +1 -0
  86. package/dist/esm/algorithms/aes-ctr.js +124 -0
  87. package/dist/esm/algorithms/aes-ctr.js.map +1 -0
  88. package/dist/esm/algorithms/aes-gcm.js +132 -0
  89. package/dist/esm/algorithms/aes-gcm.js.map +1 -0
  90. package/dist/esm/algorithms/crypto-algorithm.js +6 -0
  91. package/dist/esm/algorithms/crypto-algorithm.js.map +1 -0
  92. package/dist/esm/algorithms/ecdsa.js +237 -0
  93. package/dist/esm/algorithms/ecdsa.js.map +1 -0
  94. package/dist/esm/algorithms/eddsa.js +213 -0
  95. package/dist/esm/algorithms/eddsa.js.map +1 -0
  96. package/dist/esm/algorithms/sha-2.js +57 -0
  97. package/dist/esm/algorithms/sha-2.js.map +1 -0
  98. package/dist/esm/index.js +25 -0
  99. package/dist/esm/index.js.map +1 -0
  100. package/dist/esm/jose/jwe.js +2 -0
  101. package/dist/esm/jose/jwe.js.map +1 -0
  102. package/dist/esm/jose/jwk.js +241 -0
  103. package/dist/esm/jose/jwk.js.map +1 -0
  104. package/dist/esm/jose/jws.js +2 -0
  105. package/dist/esm/jose/jws.js.map +1 -0
  106. package/dist/esm/jose/jwt.js +2 -0
  107. package/dist/esm/jose/jwt.js.map +1 -0
  108. package/dist/esm/jose/utils.js +34 -0
  109. package/dist/esm/jose/utils.js.map +1 -0
  110. package/dist/esm/local-key-manager.js +417 -0
  111. package/dist/esm/local-key-manager.js.map +1 -0
  112. package/dist/esm/primitives/aes-ctr.js +327 -0
  113. package/dist/esm/primitives/aes-ctr.js.map +1 -0
  114. package/dist/esm/primitives/aes-gcm.js +347 -0
  115. package/dist/esm/primitives/aes-gcm.js.map +1 -0
  116. package/dist/esm/primitives/concat-kdf.js +185 -0
  117. package/dist/esm/primitives/concat-kdf.js.map +1 -0
  118. package/dist/esm/primitives/ed25519.js +521 -0
  119. package/dist/esm/primitives/ed25519.js.map +1 -0
  120. package/dist/esm/primitives/pbkdf2.js +78 -0
  121. package/dist/esm/primitives/pbkdf2.js.map +1 -0
  122. package/dist/esm/primitives/secp256k1.js +805 -0
  123. package/dist/esm/primitives/secp256k1.js.map +1 -0
  124. package/dist/esm/primitives/secp256r1.js +806 -0
  125. package/dist/esm/primitives/secp256r1.js.map +1 -0
  126. package/dist/esm/primitives/sha256.js +55 -0
  127. package/dist/esm/primitives/sha256.js.map +1 -0
  128. package/dist/esm/primitives/x25519.js +392 -0
  129. package/dist/esm/primitives/x25519.js.map +1 -0
  130. package/dist/esm/primitives/xchacha20-poly1305.js +270 -0
  131. package/dist/esm/primitives/xchacha20-poly1305.js.map +1 -0
  132. package/dist/esm/primitives/xchacha20.js +246 -0
  133. package/dist/esm/primitives/xchacha20.js.map +1 -0
  134. package/dist/esm/types/cipher.js +2 -0
  135. package/dist/esm/types/cipher.js.map +1 -0
  136. package/dist/esm/types/crypto-api.js +2 -0
  137. package/dist/esm/types/crypto-api.js.map +1 -0
  138. package/dist/esm/types/hasher.js +2 -0
  139. package/dist/esm/types/hasher.js.map +1 -0
  140. package/dist/esm/types/identifier.js +2 -0
  141. package/dist/esm/types/identifier.js.map +1 -0
  142. package/dist/esm/types/key-compressor.js +2 -0
  143. package/dist/esm/types/key-compressor.js.map +1 -0
  144. package/dist/esm/types/key-converter.js +2 -0
  145. package/dist/esm/types/key-converter.js.map +1 -0
  146. package/dist/esm/types/key-deriver.js +2 -0
  147. package/dist/esm/types/key-deriver.js.map +1 -0
  148. package/dist/esm/types/key-generator.js +2 -0
  149. package/dist/esm/types/key-generator.js.map +1 -0
  150. package/dist/esm/types/key-io.js +2 -0
  151. package/dist/esm/types/key-io.js.map +1 -0
  152. package/dist/esm/types/key-wrapper.js +2 -0
  153. package/dist/esm/types/key-wrapper.js.map +1 -0
  154. package/dist/esm/types/params-direct.js +2 -0
  155. package/dist/esm/types/params-direct.js.map +1 -0
  156. package/dist/esm/types/params-enclosed.js +2 -0
  157. package/dist/esm/types/params-enclosed.js.map +1 -0
  158. package/dist/esm/types/params-kms.js +2 -0
  159. package/dist/esm/types/params-kms.js.map +1 -0
  160. package/dist/esm/types/signer.js +2 -0
  161. package/dist/esm/types/signer.js.map +1 -0
  162. package/dist/esm/utils.js +165 -0
  163. package/dist/esm/utils.js.map +1 -0
  164. package/dist/types/algorithms/aes-ctr.d.ts +121 -0
  165. package/dist/types/algorithms/aes-ctr.d.ts.map +1 -0
  166. package/dist/types/algorithms/aes-gcm.d.ts +152 -0
  167. package/dist/types/algorithms/aes-gcm.d.ts.map +1 -0
  168. package/dist/types/algorithms/crypto-algorithm.d.ts +6 -0
  169. package/dist/types/algorithms/crypto-algorithm.d.ts.map +1 -0
  170. package/dist/types/algorithms/ecdsa.d.ts +154 -0
  171. package/dist/types/algorithms/ecdsa.d.ts.map +1 -0
  172. package/dist/types/algorithms/eddsa.d.ts +151 -0
  173. package/dist/types/algorithms/eddsa.d.ts.map +1 -0
  174. package/dist/types/algorithms/sha-2.d.ts +51 -0
  175. package/dist/types/algorithms/sha-2.d.ts.map +1 -0
  176. package/dist/types/index.d.ts +39 -0
  177. package/dist/types/index.d.ts.map +1 -0
  178. package/dist/types/jose/jwe.d.ts +135 -0
  179. package/dist/types/jose/jwe.d.ts.map +1 -0
  180. package/dist/types/jose/jwk.d.ts +439 -0
  181. package/dist/types/jose/jwk.d.ts.map +1 -0
  182. package/dist/types/jose/jws.d.ts +67 -0
  183. package/dist/types/jose/jws.d.ts.map +1 -0
  184. package/dist/types/jose/jwt.d.ts +139 -0
  185. package/dist/types/jose/jwt.d.ts.map +1 -0
  186. package/dist/types/jose/utils.d.ts +14 -0
  187. package/dist/types/jose/utils.d.ts.map +1 -0
  188. package/dist/types/local-key-manager.d.ts +307 -0
  189. package/dist/types/local-key-manager.d.ts.map +1 -0
  190. package/dist/types/primitives/aes-ctr.d.ts +219 -0
  191. package/dist/types/primitives/aes-ctr.d.ts.map +1 -0
  192. package/dist/types/primitives/aes-gcm.d.ts +245 -0
  193. package/dist/types/primitives/aes-gcm.d.ts.map +1 -0
  194. package/dist/types/primitives/concat-kdf.d.ts +160 -0
  195. package/dist/types/primitives/concat-kdf.d.ts.map +1 -0
  196. package/dist/types/primitives/ed25519.d.ts +359 -0
  197. package/dist/types/primitives/ed25519.d.ts.map +1 -0
  198. package/dist/types/primitives/pbkdf2.d.ts +94 -0
  199. package/dist/types/primitives/pbkdf2.d.ts.map +1 -0
  200. package/dist/types/primitives/secp256k1.d.ts +598 -0
  201. package/dist/types/primitives/secp256k1.d.ts.map +1 -0
  202. package/dist/types/primitives/secp256r1.d.ts +599 -0
  203. package/dist/types/primitives/secp256r1.d.ts.map +1 -0
  204. package/dist/types/primitives/sha256.d.ts +42 -0
  205. package/dist/types/primitives/sha256.d.ts.map +1 -0
  206. package/dist/types/primitives/x25519.d.ts +283 -0
  207. package/dist/types/primitives/x25519.d.ts.map +1 -0
  208. package/dist/types/primitives/xchacha20-poly1305.d.ts +210 -0
  209. package/dist/types/primitives/xchacha20-poly1305.d.ts.map +1 -0
  210. package/dist/types/primitives/xchacha20.d.ts +186 -0
  211. package/dist/types/primitives/xchacha20.d.ts.map +1 -0
  212. package/dist/types/types/cipher.d.ts +49 -0
  213. package/dist/types/types/cipher.d.ts.map +1 -0
  214. package/dist/types/types/crypto-api.d.ts +40 -0
  215. package/dist/types/types/crypto-api.d.ts.map +1 -0
  216. package/dist/types/types/hasher.d.ts +33 -0
  217. package/dist/types/types/hasher.d.ts.map +1 -0
  218. package/dist/types/types/identifier.d.ts +16 -0
  219. package/dist/types/types/identifier.d.ts.map +1 -0
  220. package/dist/types/types/key-compressor.d.ts +28 -0
  221. package/dist/types/types/key-compressor.d.ts.map +1 -0
  222. package/dist/types/types/key-converter.d.ts +57 -0
  223. package/dist/types/types/key-converter.d.ts.map +1 -0
  224. package/dist/types/types/key-deriver.d.ts +39 -0
  225. package/dist/types/types/key-deriver.d.ts.map +1 -0
  226. package/dist/types/types/key-generator.d.ts +105 -0
  227. package/dist/types/types/key-generator.d.ts.map +1 -0
  228. package/dist/types/types/key-io.d.ts +37 -0
  229. package/dist/types/types/key-io.d.ts.map +1 -0
  230. package/dist/types/types/key-wrapper.d.ts +38 -0
  231. package/dist/types/types/key-wrapper.d.ts.map +1 -0
  232. package/dist/types/types/params-direct.d.ts +90 -0
  233. package/dist/types/types/params-direct.d.ts.map +1 -0
  234. package/dist/types/types/params-enclosed.d.ts +47 -0
  235. package/dist/types/types/params-enclosed.d.ts.map +1 -0
  236. package/dist/types/types/params-kms.d.ts +131 -0
  237. package/dist/types/types/params-kms.d.ts.map +1 -0
  238. package/dist/types/types/signer.d.ts +46 -0
  239. package/dist/types/types/signer.d.ts.map +1 -0
  240. package/dist/types/utils.d.ts +112 -0
  241. package/dist/types/utils.d.ts.map +1 -0
  242. package/dist/utils.js +7 -0
  243. package/dist/utils.js.map +7 -0
  244. package/package.json +103 -0
  245. package/src/algorithms/aes-ctr.ts +156 -0
  246. package/src/algorithms/aes-gcm.ts +187 -0
  247. package/src/algorithms/crypto-algorithm.ts +4 -0
  248. package/src/algorithms/ecdsa.ts +269 -0
  249. package/src/algorithms/eddsa.ts +243 -0
  250. package/src/algorithms/sha-2.ts +65 -0
  251. package/src/index.ts +42 -0
  252. package/src/jose/jwe.ts +196 -0
  253. package/src/jose/jwk.ts +632 -0
  254. package/src/jose/jws.ts +95 -0
  255. package/src/jose/jwt.ts +147 -0
  256. package/src/jose/utils.ts +34 -0
  257. package/src/local-key-manager.ts +540 -0
  258. package/src/primitives/aes-ctr.ts +352 -0
  259. package/src/primitives/aes-gcm.ts +378 -0
  260. package/src/primitives/concat-kdf.ts +240 -0
  261. package/src/primitives/ed25519.ts +548 -0
  262. package/src/primitives/pbkdf2.ts +122 -0
  263. package/src/primitives/secp256k1.ts +848 -0
  264. package/src/primitives/secp256r1.ts +850 -0
  265. package/src/primitives/sha256.ts +47 -0
  266. package/src/primitives/x25519.ts +403 -0
  267. package/src/primitives/xchacha20-poly1305.ts +274 -0
  268. package/src/primitives/xchacha20.ts +247 -0
  269. package/src/types/cipher.ts +53 -0
  270. package/src/types/crypto-api.ts +56 -0
  271. package/src/types/hasher.ts +32 -0
  272. package/src/types/identifier.ts +16 -0
  273. package/src/types/key-compressor.ts +25 -0
  274. package/src/types/key-converter.ts +53 -0
  275. package/src/types/key-deriver.ts +43 -0
  276. package/src/types/key-generator.ts +119 -0
  277. package/src/types/key-io.ts +42 -0
  278. package/src/types/key-wrapper.ts +42 -0
  279. package/src/types/params-direct.ts +106 -0
  280. package/src/types/params-enclosed.ts +50 -0
  281. package/src/types/params-kms.ts +156 -0
  282. package/src/types/signer.ts +50 -0
  283. package/src/utils.ts +181 -0
@@ -0,0 +1,540 @@
1
+ import { KeyValueStore, MemoryStore } from '@enbox/common';
2
+
3
+ import type { Jwk } from './jose/jwk.js';
4
+ import type { Hasher } from './types/hasher.js';
5
+ import type { Signer } from './types/signer.js';
6
+ import type { CryptoApi } from './types/crypto-api.js';
7
+ import type { KeyIdentifier } from './types/identifier.js';
8
+ import type { KeyImporterExporter } from './types/key-io.js';
9
+ import type { KeyGenerator, AsymmetricKeyGenerator } from './types/key-generator.js';
10
+ import type { GetPublicKeyParams, SignParams, VerifyParams } from './types/params-direct.js';
11
+ import type {
12
+ KmsSignParams,
13
+ KmsDigestParams,
14
+ KmsVerifyParams,
15
+ KmsExportKeyParams,
16
+ KmsGetKeyUriParams,
17
+ KmsImportKeyParams,
18
+ KmsGenerateKeyParams,
19
+ KmsGetPublicKeyParams,
20
+ } from './types/params-kms.js';
21
+
22
+ import { Sha2Algorithm } from './algorithms/sha-2.js';
23
+ import { EcdsaAlgorithm } from './algorithms/ecdsa.js';
24
+ import { EdDsaAlgorithm } from './algorithms/eddsa.js';
25
+ import { CryptoAlgorithm } from './algorithms/crypto-algorithm.js';
26
+ import { computeJwkThumbprint, isPrivateJwk, KEY_URI_PREFIX_JWK } from './jose/jwk.js';
27
+
28
+ /**
29
+ * `supportedAlgorithms` is an object mapping algorithm names to their respective implementations
30
+ * Each entry in this map specifies the algorithm name and its associated properties, including the
31
+ * implementation class and any relevant names or identifiers for the algorithm. This structure
32
+ * allows for easy retrieval and instantiation of algorithm implementations based on the algorithm
33
+ * name or key specification. It facilitates the support of multiple algorithms within the
34
+ * `LocalKeyManager` class.
35
+ */
36
+ const supportedAlgorithms = {
37
+ 'Ed25519': {
38
+ implementation : EdDsaAlgorithm,
39
+ names : ['Ed25519'],
40
+ },
41
+ 'secp256k1': {
42
+ implementation : EcdsaAlgorithm,
43
+ names : ['ES256K', 'secp256k1'],
44
+ },
45
+ 'secp256r1': {
46
+ implementation : EcdsaAlgorithm,
47
+ names : ['ES256', 'secp256r1'],
48
+ },
49
+ 'SHA-256': {
50
+ implementation : Sha2Algorithm,
51
+ names : ['SHA-256']
52
+ }
53
+ } satisfies {
54
+ [key: string]: {
55
+ implementation : typeof CryptoAlgorithm;
56
+ names : string[];
57
+ }
58
+ };
59
+
60
+ /* Helper type for `supportedAlgorithms`. */
61
+ type SupportedAlgorithm = keyof typeof supportedAlgorithms;
62
+
63
+ /* Helper type for `supportedAlgorithms` implementations. */
64
+ type AlgorithmConstructor = typeof supportedAlgorithms[SupportedAlgorithm]['implementation'];
65
+
66
+ /**
67
+ * The `LocalKeyManagerParams` interface specifies the parameters for initializing an instance of
68
+ * `LocalKeyManager`. It allows the optional inclusion of a `KeyValueStore` instance for key
69
+ * management. If not provided, a default `MemoryStore` instance will be used for storing keys in
70
+ * memory. Note that the `MemoryStore` is not persistent and will be cleared when the application
71
+ * exits.
72
+ */
73
+ export type LocalKeyManagerParams = {
74
+ /**
75
+ * An optional property to specify a custom `KeyValueStore` instance for key management. If not
76
+ * provided, {@link LocalKeyManager | `LocalKeyManager`} uses a default `MemoryStore` instance.
77
+ * This store is responsible for managing cryptographic keys, allowing them to be retrieved,
78
+ * stored, and managed during cryptographic operations.
79
+ */
80
+ keyStore?: KeyValueStore<KeyIdentifier, Jwk>;
81
+ };
82
+
83
+ /**
84
+ * The `LocalKeyManagerDigestParams` interface defines the algorithm-specific parameters that should
85
+ * be passed into the {@link LocalKeyManager.digest | `LocalKeyManager.digest()`} method.
86
+ */
87
+ export interface LocalKeyManagerDigestParams extends KmsDigestParams {
88
+ /**
89
+ * A string defining the name of hash function to use. The value must be one of the following:
90
+ * - `"SHA-256"`: Generates a 256-bit digest.
91
+ */
92
+ algorithm: 'SHA-256';
93
+ }
94
+
95
+ /**
96
+ * The `LocalKeyManagerGenerateKeyParams` interface defines the algorithm-specific parameters that
97
+ * should be passed into the {@link LocalKeyManager.generateKey | `LocalKeyManager.generateKey()`}
98
+ * method when generating a key in the local KMS.
99
+ */
100
+ export interface LocalKeyManagerGenerateKeyParams extends KmsGenerateKeyParams {
101
+ /**
102
+ * A string defining the type of key to generate. The value must be one of the following:
103
+ * - `"Ed25519"`
104
+ * - `"secp256k1"`
105
+ */
106
+ algorithm: 'Ed25519' | 'secp256k1' | 'secp256r1';
107
+ }
108
+
109
+ export class LocalKeyManager implements
110
+ CryptoApi,
111
+ KeyImporterExporter<KmsImportKeyParams, KeyIdentifier, KmsExportKeyParams> {
112
+
113
+ /**
114
+ * A private map that stores instances of cryptographic algorithm implementations. Each key in
115
+ * this map is an `AlgorithmConstructor`, and its corresponding value is an instance of a class
116
+ * that implements a specific cryptographic algorithm. This map is used to cache and reuse
117
+ * instances for performance optimization, ensuring that each algorithm is instantiated only once.
118
+ */
119
+ private _algorithmInstances: Map<AlgorithmConstructor, InstanceType<typeof CryptoAlgorithm>> = new Map();
120
+
121
+ /**
122
+ * The `_keyStore` private variable in `LocalKeyManager` is a `KeyValueStore` instance used for
123
+ * storing and managing cryptographic keys. It allows the `LocalKeyManager` class to save,
124
+ * retrieve, and handle keys efficiently within the local Key Management System (KMS) context.
125
+ * This variable can be configured to use different storage backends, like in-memory storage or
126
+ * persistent storage, providing flexibility in key management according to the application's
127
+ * requirements.
128
+ */
129
+ private _keyStore: KeyValueStore<KeyIdentifier, Jwk>;
130
+
131
+ constructor(params?: LocalKeyManagerParams) {
132
+ this._keyStore = params?.keyStore ?? new MemoryStore<KeyIdentifier, Jwk>();
133
+ }
134
+
135
+ /**
136
+ * Generates a hash digest of the provided data.
137
+ *
138
+ * @remarks
139
+ * A digest is the output of the hash function. It's a fixed-size string of bytes
140
+ * that uniquely represents the data input into the hash function. The digest is often used for
141
+ * data integrity checks, as any alteration in the input data results in a significantly
142
+ * different digest.
143
+ *
144
+ * It takes the algorithm identifier of the hash function and data to digest as input and returns
145
+ * the digest of the data.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * const keyManager = new LocalKeyManager();
150
+ * const data = new Uint8Array([...]);
151
+ * const digest = await keyManager.digest({ algorithm: 'SHA-256', data });
152
+ * ```
153
+ *
154
+ * @param params - The parameters for the digest operation.
155
+ * @param params.algorithm - The name of hash function to use.
156
+ * @param params.data - The data to digest.
157
+ *
158
+ * @returns A Promise which will be fulfilled with the hash digest.
159
+ */
160
+ public async digest({ algorithm, data }:
161
+ LocalKeyManagerDigestParams
162
+ ): Promise<Uint8Array> {
163
+ // Get the hash function implementation based on the specified `algorithm` parameter.
164
+ const hasher = this.getAlgorithm({ algorithm }) as Hasher<KmsDigestParams>;
165
+
166
+ // Compute the hash.
167
+ const hash = await hasher.digest({ algorithm, data });
168
+
169
+ return hash;
170
+ }
171
+
172
+ /**
173
+ * Exports a private key identified by the provided key URI from the local KMS.
174
+ *
175
+ * @remarks
176
+ * This method retrieves the key from the key store and returns it. It is primarily used
177
+ * for extracting keys for backup or transfer purposes.
178
+ *
179
+ * @example
180
+ * ```ts
181
+ * const keyManager = new LocalKeyManager();
182
+ * const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
183
+ * const privateKey = await keyManager.exportKey({ keyUri });
184
+ * ```
185
+ *
186
+ * @param params - Parameters for exporting the key.
187
+ * @param params.keyUri - The key URI identifying the key to export.
188
+ *
189
+ * @returns A Promise resolving to the JWK representation of the exported key.
190
+ */
191
+ public async exportKey({ keyUri }:
192
+ KmsExportKeyParams
193
+ ): Promise<Jwk> {
194
+ // Get the private key from the key store.
195
+ const privateKey = await this.getPrivateKey({ keyUri });
196
+
197
+ return privateKey;
198
+ }
199
+
200
+ /**
201
+ * Generates a new cryptographic key in the local KMS with the specified algorithm and returns a
202
+ * unique key URI which can be used to reference the key in subsequent operations.
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * const keyManager = new LocalKeyManager();
207
+ * const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
208
+ * console.log(keyUri); // Outputs the key URI
209
+ * ```
210
+ *
211
+ * @param params - The parameters for key generation.
212
+ * @param params.algorithm - The algorithm to use for key generation, defined in `SupportedAlgorithm`.
213
+ *
214
+ * @returns A Promise that resolves to the key URI, a unique identifier for the generated key.
215
+ */
216
+ public async generateKey({ algorithm }:
217
+ LocalKeyManagerGenerateKeyParams
218
+ ): Promise<KeyIdentifier> {
219
+ // Get the key generator implementation based on the specified `algorithm` parameter.
220
+ const keyGenerator = this.getAlgorithm({ algorithm }) as KeyGenerator<LocalKeyManagerGenerateKeyParams, Jwk>;
221
+
222
+ // Generate the key.
223
+ const key = await keyGenerator.generateKey({ algorithm });
224
+
225
+ if (key?.kid === undefined) {
226
+ throw new Error('Generated key is missing a required property: kid');
227
+ }
228
+
229
+ // Construct the key URI.
230
+ const keyUri = `${KEY_URI_PREFIX_JWK}${key.kid}`;
231
+
232
+ // Store the key in the key store.
233
+ await this._keyStore.set(keyUri, key);
234
+
235
+ return keyUri;
236
+ }
237
+
238
+ /**
239
+ * Computes the Key URI for a given public JWK (JSON Web Key).
240
+ *
241
+ * @remarks
242
+ * This method generates a {@link https://datatracker.ietf.org/doc/html/rfc3986 | URI}
243
+ * (Uniform Resource Identifier) for the given JWK, which uniquely identifies the key across all
244
+ * `CryptoApi` implementations. The key URI is constructed by appending the
245
+ * {@link https://datatracker.ietf.org/doc/html/rfc7638 | JWK thumbprint} to the prefix
246
+ * `urn:jwk:`. The JWK thumbprint is deterministically computed from the JWK and is consistent
247
+ * regardless of property order or optional property inclusion in the JWK. This ensures that the
248
+ * same key material represented as a JWK will always yield the same thumbprint, and therefore,
249
+ * the same key URI.
250
+ *
251
+ * @example
252
+ * ```ts
253
+ * const keyManager = new LocalKeyManager();
254
+ * const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
255
+ * const publicKey = await keyManager.getPublicKey({ keyUri });
256
+ * const keyUriFromPublicKey = await keyManager.getKeyUri({ key: publicKey });
257
+ * console.log(keyUri === keyUriFromPublicKey); // Outputs `true`
258
+ * ```
259
+ *
260
+ * @param params - The parameters for getting the key URI.
261
+ * @param params.key - The JWK for which to compute the key URI.
262
+ *
263
+ * @returns A Promise that resolves to the key URI as a string.
264
+ */
265
+ public async getKeyUri({ key }:
266
+ KmsGetKeyUriParams
267
+ ): Promise<KeyIdentifier> {
268
+ // Compute the JWK thumbprint.
269
+ const jwkThumbprint = await computeJwkThumbprint({ jwk: key });
270
+
271
+ // Construct the key URI by appending the JWK thumbprint to the key URI prefix.
272
+ const keyUri = `${KEY_URI_PREFIX_JWK}${jwkThumbprint}`;
273
+
274
+ return keyUri;
275
+ }
276
+
277
+ /**
278
+ * Retrieves the public key associated with a previously generated private key, identified by
279
+ * the provided key URI.
280
+ *
281
+ * @example
282
+ * ```ts
283
+ * const keyManager = new LocalKeyManager();
284
+ * const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
285
+ * const publicKey = await keyManager.getPublicKey({ keyUri });
286
+ * ```
287
+ *
288
+ * @param params - The parameters for retrieving the public key.
289
+ * @param params.keyUri - The key URI of the private key to retrieve the public key for.
290
+ *
291
+ * @returns A Promise that resolves to the public key in JWK format.
292
+ */
293
+ public async getPublicKey({ keyUri }:
294
+ KmsGetPublicKeyParams
295
+ ): Promise<Jwk> {
296
+ // Get the private key from the key store.
297
+ const privateKey = await this.getPrivateKey({ keyUri });
298
+
299
+ // Determine the algorithm name based on the JWK's `alg` and `crv` properties.
300
+ const algorithm = this.getAlgorithmName({ key: privateKey });
301
+
302
+ // Get the key generator based on the algorithm name.
303
+ const keyGenerator = this.getAlgorithm({ algorithm }) as AsymmetricKeyGenerator<LocalKeyManagerGenerateKeyParams, Jwk, GetPublicKeyParams>;
304
+
305
+ // Get the public key properties from the private JWK.
306
+ const publicKey = await keyGenerator.getPublicKey({ key: privateKey });
307
+
308
+ return publicKey;
309
+ }
310
+
311
+ /**
312
+ * Imports a private key into the local KMS.
313
+ *
314
+ * @remarks
315
+ * This method stores the provided JWK in the key store, making it available for subsequent
316
+ * cryptographic operations. It is particularly useful for initializing the KMS with pre-existing
317
+ * keys or for restoring keys from backups.
318
+ *
319
+ * Note that, if defined, the `kid` (key ID) property of the JWK is used as the key URI for the
320
+ * imported key. If the `kid` property is not provided, the key URI is computed from the JWK
321
+ * thumbprint of the key.
322
+ *
323
+ * @example
324
+ * ```ts
325
+ * const keyManager = new LocalKeyManager();
326
+ * const privateKey = { ... } // A private key in JWK format
327
+ * const keyUri = await keyManager.importKey({ key: privateKey });
328
+ * ```
329
+ *
330
+ * @param params - Parameters for importing the key.
331
+ * @param params.key - The private key to import to in JWK format.
332
+ *
333
+ * @returns A Promise resolving to the key URI, uniquely identifying the imported key.
334
+ */
335
+ public async importKey({ key }:
336
+ KmsImportKeyParams
337
+ ): Promise<KeyIdentifier> {
338
+ if (!isPrivateJwk(key)) throw new TypeError('Invalid key provided. Must be a private key in JWK format.');
339
+
340
+ // Make a deep copy of the key to avoid mutating the original.
341
+ const privateKey = structuredClone(key);
342
+
343
+ // If the key ID is undefined, set it to the JWK thumbprint.
344
+ privateKey.kid ??= await computeJwkThumbprint({ jwk: privateKey });
345
+
346
+ // Compute the key URI for the key.
347
+ const keyUri = await this.getKeyUri({ key: privateKey });
348
+
349
+ // Store the key in the key store.
350
+ await this._keyStore.set(keyUri, privateKey);
351
+
352
+ return keyUri;
353
+ }
354
+
355
+ /**
356
+ * Signs the provided data using the private key identified by the provided key URI.
357
+ *
358
+ * @remarks
359
+ * This method uses the signature algorithm determined by the `alg` and/or `crv` properties of the
360
+ * private key identified by the provided key URI to sign the provided data. The signature can
361
+ * later be verified by parties with access to the corresponding public key, ensuring that the
362
+ * data has not been tampered with and was indeed signed by the holder of the private key.
363
+ *
364
+ * @example
365
+ * ```ts
366
+ * const keyManager = new LocalKeyManager();
367
+ * const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
368
+ * const data = new TextEncoder().encode('Message to sign');
369
+ * const signature = await keyManager.sign({ keyUri, data });
370
+ * ```
371
+ *
372
+ * @param params - The parameters for the signing operation.
373
+ * @param params.keyUri - The key URI of the private key to use for signing.
374
+ * @param params.data - The data to sign.
375
+ *
376
+ * @returns A Promise resolving to the digital signature as a `Uint8Array`.
377
+ */
378
+ public async sign({ keyUri, data }:
379
+ KmsSignParams
380
+ ): Promise<Uint8Array> {
381
+ // Get the private key from the key store.
382
+ const privateKey = await this.getPrivateKey({ keyUri });
383
+
384
+ // Determine the algorithm name based on the JWK's `alg` and `crv` properties.
385
+ const algorithm = this.getAlgorithmName({ key: privateKey });
386
+
387
+ // Get the signature algorithm based on the algorithm name.
388
+ const signer = this.getAlgorithm({ algorithm }) as Signer<SignParams, VerifyParams>;
389
+
390
+ // Sign the data.
391
+ const signature = signer.sign({ data, key: privateKey });
392
+
393
+ return signature;
394
+ }
395
+
396
+ /**
397
+ * Verifies a digital signature associated the provided data using the provided key.
398
+ *
399
+ * @remarks
400
+ * This method uses the signature algorithm determined by the `alg` and/or `crv` properties of the
401
+ * provided key to check the validity of a digital signature against the original data. It
402
+ * confirms whether the signature was created by the holder of the corresponding private key and
403
+ * that the data has not been tampered with.
404
+ *
405
+ * @example
406
+ * ```ts
407
+ * const keyManager = new LocalKeyManager();
408
+ * const keyUri = await keyManager.generateKey({ algorithm: 'Ed25519' });
409
+ * const data = new TextEncoder().encode('Message to sign');
410
+ * const signature = await keyManager.sign({ keyUri, data });
411
+ * const isSignatureValid = await keyManager.verify({ keyUri, data, signature });
412
+ * ```
413
+ *
414
+ * @param params - The parameters for the verification operation.
415
+ * @param params.key - The key to use for verification.
416
+ * @param params.signature - The signature to verify.
417
+ * @param params.data - The data to verify.
418
+ *
419
+ * @returns A Promise resolving to a boolean indicating whether the signature is valid.
420
+ */
421
+ public async verify({ key, signature, data }:
422
+ KmsVerifyParams
423
+ ): Promise<boolean> {
424
+ // Determine the algorithm name based on the JWK's `alg` and `crv` properties.
425
+ const algorithm = this.getAlgorithmName({ key });
426
+
427
+ // Get the signature algorithm based on the algorithm name.
428
+ const signer = this.getAlgorithm({ algorithm }) as Signer<SignParams, VerifyParams>;
429
+
430
+ // Verify the signature.
431
+ const isSignatureValid = signer.verify({ key, signature, data });
432
+
433
+ return isSignatureValid;
434
+ }
435
+
436
+ /**
437
+ * Retrieves an algorithm implementation instance based on the provided algorithm name.
438
+ *
439
+ * @remarks
440
+ * This method checks if the requested algorithm is supported and returns a cached instance
441
+ * if available. If an instance does not exist, it creates and caches a new one. This approach
442
+ * optimizes performance by reusing algorithm instances across cryptographic operations.
443
+ *
444
+ * @example
445
+ * ```ts
446
+ * const signer = this.getAlgorithm({ algorithm: 'Ed25519' });
447
+ * ```
448
+ *
449
+ * @param params - The parameters for retrieving the algorithm implementation.
450
+ * @param params.algorithm - The name of the algorithm to retrieve.
451
+ *
452
+ * @returns An instance of the requested algorithm implementation.
453
+ *
454
+ * @throws Error if the requested algorithm is not supported.
455
+ */
456
+ private getAlgorithm({ algorithm }: {
457
+ algorithm: SupportedAlgorithm;
458
+ }): InstanceType<typeof CryptoAlgorithm> {
459
+ // Check if algorithm is supported.
460
+ const AlgorithmImplementation = supportedAlgorithms[algorithm]?.['implementation'];
461
+ if (!AlgorithmImplementation) {
462
+ throw new Error(`Algorithm not supported: ${algorithm}`);
463
+ }
464
+
465
+ // Check if instance already exists for the `AlgorithmImplementation`.
466
+ if (!this._algorithmInstances.has(AlgorithmImplementation)) {
467
+ // If not, create a new instance and store it in the cache
468
+ this._algorithmInstances.set(AlgorithmImplementation, new AlgorithmImplementation());
469
+ }
470
+
471
+ // Return the cached instance
472
+ return this._algorithmInstances.get(AlgorithmImplementation)!;
473
+ }
474
+
475
+ /**
476
+ * Determines the name of the algorithm based on the key's properties.
477
+ *
478
+ * @remarks
479
+ * This method facilitates the identification of the correct algorithm for cryptographic
480
+ * operations based on the `alg` or `crv` properties of a {@link Jwk | JWK}.
481
+ *
482
+ * @example
483
+ * ```ts
484
+ * const publicKey = { ... }; // Public key in JWK format
485
+ * const algorithm = this.getAlgorithmName({ key: publicKey });
486
+ * ```
487
+ *
488
+ * @param params - The parameters for determining the algorithm name.
489
+ * @param params.key - A JWK containing the `alg` or `crv` properties.
490
+ *
491
+ * @returns The name of the algorithm associated with the key.
492
+ *
493
+ * @throws Error if the algorithm cannot be determined from the provided input.
494
+ */
495
+ private getAlgorithmName({ key }: {
496
+ key: { alg?: string, crv?: string };
497
+ }): SupportedAlgorithm {
498
+ const algProperty = key.alg;
499
+ const crvProperty = key.crv;
500
+
501
+ for (const algName in supportedAlgorithms) {
502
+ const algorithmInfo = supportedAlgorithms[algName as SupportedAlgorithm];
503
+ if (algProperty && algorithmInfo.names.includes(algProperty)) {
504
+ return algName as SupportedAlgorithm;
505
+ } else if (crvProperty && algorithmInfo.names.includes(crvProperty)) {
506
+ return algName as SupportedAlgorithm;
507
+ }
508
+ }
509
+
510
+ throw new Error(`Unable to determine algorithm based on provided input: alg=${algProperty}, crv=${crvProperty}`);
511
+ }
512
+
513
+ /**
514
+ * Retrieves a private key from the key store based on the provided key URI.
515
+ *
516
+ * @example
517
+ * ```ts
518
+ * const privateKey = this.getPrivateKey({ keyUri: 'urn:jwk:...' });
519
+ * ```
520
+ *
521
+ * @param params - Parameters for retrieving the private key.
522
+ * @param params.keyUri - The key URI identifying the private key to retrieve.
523
+ *
524
+ * @returns A Promise resolving to the JWK representation of the private key.
525
+ *
526
+ * @throws Error if the key is not found in the key store.
527
+ */
528
+ private async getPrivateKey({ keyUri }: {
529
+ keyUri: KeyIdentifier;
530
+ }): Promise<Jwk> {
531
+ // Get the private key from the key store.
532
+ const privateKey = await this._keyStore.get(keyUri);
533
+
534
+ if (!privateKey) {
535
+ throw new Error(`Key not found: ${keyUri}`);
536
+ }
537
+
538
+ return privateKey;
539
+ }
540
+ }