@reallyme/crypto 0.1.8 → 0.3.0

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 (61) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +148 -18
  3. package/dist/aead.d.ts +4 -0
  4. package/dist/aead.js +40 -16
  5. package/dist/aesKw.d.ts +8 -2
  6. package/dist/aesKw.js +69 -12
  7. package/dist/algorithms.d.ts +12 -4
  8. package/dist/algorithms.js +8 -2
  9. package/dist/argon2id.d.ts +3 -0
  10. package/dist/argon2id.js +18 -3
  11. package/dist/cryptoFacade.d.ts +66 -5
  12. package/dist/cryptoFacade.js +99 -38
  13. package/dist/errors.d.ts +1 -1
  14. package/dist/hkdf.d.ts +1 -0
  15. package/dist/hkdf.js +5 -1
  16. package/dist/hmac.d.ts +3 -0
  17. package/dist/hmac.js +24 -3
  18. package/dist/hpke.d.ts +4 -1
  19. package/dist/hpke.js +45 -14
  20. package/dist/index.d.ts +14 -13
  21. package/dist/index.js +12 -10
  22. package/dist/jwaConcatKdf.js +8 -4
  23. package/dist/jwk.d.ts +2 -1
  24. package/dist/jwk.js +158 -122
  25. package/dist/kmac.d.ts +11 -0
  26. package/dist/kmac.js +49 -0
  27. package/dist/memory.d.ts +8 -0
  28. package/dist/memory.js +13 -0
  29. package/dist/mlDsa.d.ts +5 -0
  30. package/dist/mlDsa.js +43 -9
  31. package/dist/mlKem.d.ts +5 -2
  32. package/dist/mlKem.js +37 -26
  33. package/dist/operationResponse.d.ts +16 -0
  34. package/dist/operationResponse.js +46 -0
  35. package/dist/p256Ecdh.js +5 -1
  36. package/dist/p384Ecdh.js +5 -1
  37. package/dist/p521Ecdh.js +5 -1
  38. package/dist/pbkdf2.d.ts +6 -8
  39. package/dist/pbkdf2.js +12 -12
  40. package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.d.ts +2859 -128
  41. package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.js +992 -132
  42. package/dist/proto.d.ts +99 -7
  43. package/dist/proto.js +741 -16
  44. package/dist/rsa.d.ts +4 -1
  45. package/dist/rsa.js +23 -16
  46. package/dist/slhDsa.d.ts +5 -0
  47. package/dist/slhDsa.js +40 -9
  48. package/dist/validateBytes.d.ts +7 -1
  49. package/dist/validateBytes.js +63 -3
  50. package/dist/wasm/reallyme_crypto_wasm.js +77 -365
  51. package/dist/wasm/reallyme_crypto_wasm_bg.wasm +0 -0
  52. package/dist/wasmModuleTypes.d.ts +9 -21
  53. package/dist/wasmProvider.d.ts +12 -29
  54. package/dist/wasmProvider.js +25 -43
  55. package/dist/xWing.d.ts +5 -4
  56. package/dist/xWing.js +40 -40
  57. package/package.json +20 -2
  58. package/dist/codecs.d.ts +0 -35
  59. package/dist/codecs.js +0 -216
  60. package/dist/proto/generated/reallyme/codec/v1/codec_pb.d.ts +0 -253
  61. package/dist/proto/generated/reallyme/codec/v1/codec_pb.js +0 -160
@@ -4,15 +4,23 @@ export declare const REALLYME_HASH_ALGORITHMS: readonly ["SHA2-256", "SHA2-384",
4
4
  export type ReallyMeHashAlgorithm = (typeof REALLYME_HASH_ALGORITHMS)[number];
5
5
  export declare const REALLYME_AEAD_ALGORITHMS: readonly ["AES-128-GCM", "AES-192-GCM", "AES-256-GCM", "AES-256-GCM-SIV", "ChaCha20-Poly1305", "XChaCha20-Poly1305"];
6
6
  export type ReallyMeAeadAlgorithm = (typeof REALLYME_AEAD_ALGORITHMS)[number];
7
- export declare const REALLYME_KEM_ALGORITHMS: readonly ["ML-KEM-512", "ML-KEM-768", "ML-KEM-1024", "X-Wing-768", "X-Wing-1024"];
7
+ export declare const REALLYME_KEM_ALGORITHMS: readonly ["ML-KEM-512", "ML-KEM-768", "ML-KEM-1024", "X-Wing-768"];
8
8
  export type ReallyMeKemAlgorithm = (typeof REALLYME_KEM_ALGORITHMS)[number];
9
9
  export declare const REALLYME_KEY_AGREEMENT_ALGORITHMS: readonly ["X25519", "P-256-ECDH", "P-384-ECDH", "P-521-ECDH"];
10
10
  export type ReallyMeKeyAgreementAlgorithm = (typeof REALLYME_KEY_AGREEMENT_ALGORITHMS)[number];
11
- export declare const REALLYME_MAC_ALGORITHMS: readonly ["HMAC-SHA-256", "HMAC-SHA-512"];
11
+ export declare const REALLYME_MAC_ALGORITHMS: readonly ["HMAC-SHA-256", "HMAC-SHA-384", "HMAC-SHA-512"];
12
12
  export type ReallyMeMacAlgorithm = (typeof REALLYME_MAC_ALGORITHMS)[number];
13
- export declare const REALLYME_KDF_ALGORITHMS: readonly ["HKDF-SHA256", "Argon2id", "PBKDF2-HMAC-SHA-256", "PBKDF2-HMAC-SHA-512", "JWA-CONCAT-KDF-SHA256"];
13
+ export declare const REALLYME_KDF_ALGORITHMS: readonly ["HKDF-SHA256", "HKDF-SHA384", "Argon2id", "KMAC256", "PBKDF2-HMAC-SHA-256", "PBKDF2-HMAC-SHA-512", "JWA-CONCAT-KDF-SHA256"];
14
14
  export type ReallyMeKdfAlgorithm = (typeof REALLYME_KDF_ALGORITHMS)[number];
15
- export declare const REALLYME_KEY_WRAP_ALGORITHMS: readonly ["AES-256-KW"];
15
+ /** PBKDF2 selectors accepted by the password-based `deriveKey` facade. */
16
+ export type ReallyMePbkdf2Algorithm = Extract<ReallyMeKdfAlgorithm, "PBKDF2-HMAC-SHA-256" | "PBKDF2-HMAC-SHA-512">;
17
+ /** HKDF selectors accepted by the `deriveHkdf` facade. */
18
+ export type ReallyMeHkdfAlgorithm = Extract<ReallyMeKdfAlgorithm, "HKDF-SHA256" | "HKDF-SHA384">;
19
+ /** JWA Concat KDF selector accepted by its dedicated facade. */
20
+ export type ReallyMeJwaConcatKdfAlgorithm = Extract<ReallyMeKdfAlgorithm, "JWA-CONCAT-KDF-SHA256">;
21
+ /** KMAC KDF selector accepted by its dedicated facade. */
22
+ export type ReallyMeKmacKdfAlgorithm = Extract<ReallyMeKdfAlgorithm, "KMAC256">;
23
+ export declare const REALLYME_KEY_WRAP_ALGORITHMS: readonly ["AES-128-KW", "AES-192-KW", "AES-256-KW"];
16
24
  export type ReallyMeKeyWrapAlgorithm = (typeof REALLYME_KEY_WRAP_ALGORITHMS)[number];
17
25
  export declare const REALLYME_HPKE_SUITES: readonly ["DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM", "DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305"];
18
26
  export type ReallyMeHpkeSuite = (typeof REALLYME_HPKE_SUITES)[number];
@@ -43,7 +43,6 @@ export const REALLYME_KEM_ALGORITHMS = [
43
43
  "ML-KEM-768",
44
44
  "ML-KEM-1024",
45
45
  "X-Wing-768",
46
- "X-Wing-1024",
47
46
  ];
48
47
  export const REALLYME_KEY_AGREEMENT_ALGORITHMS = [
49
48
  "X25519",
@@ -53,16 +52,23 @@ export const REALLYME_KEY_AGREEMENT_ALGORITHMS = [
53
52
  ];
54
53
  export const REALLYME_MAC_ALGORITHMS = [
55
54
  "HMAC-SHA-256",
55
+ "HMAC-SHA-384",
56
56
  "HMAC-SHA-512",
57
57
  ];
58
58
  export const REALLYME_KDF_ALGORITHMS = [
59
59
  "HKDF-SHA256",
60
+ "HKDF-SHA384",
60
61
  "Argon2id",
62
+ "KMAC256",
61
63
  "PBKDF2-HMAC-SHA-256",
62
64
  "PBKDF2-HMAC-SHA-512",
63
65
  "JWA-CONCAT-KDF-SHA256",
64
66
  ];
65
- export const REALLYME_KEY_WRAP_ALGORITHMS = ["AES-256-KW"];
67
+ export const REALLYME_KEY_WRAP_ALGORITHMS = [
68
+ "AES-128-KW",
69
+ "AES-192-KW",
70
+ "AES-256-KW",
71
+ ];
66
72
  export const REALLYME_HPKE_SUITES = [
67
73
  "DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM",
68
74
  "DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305",
@@ -1,8 +1,11 @@
1
+ import type { ReallyMeWasmProvider } from "./wasmProvider.js";
1
2
  export declare const ARGON2ID_DERIVED_KEY_LENGTH = 32;
2
3
  export declare const ARGON2ID_SALT_MIN_LENGTH = 16;
3
4
  export declare const ARGON2ID_SALT_MAX_LENGTH = 32;
5
+ export declare const ARGON2ID_SECRET_MAX_LENGTH = 1048576;
4
6
  export declare const ARGON2ID_V1 = 1;
5
7
  export declare const ARGON2ID_V2 = 2;
6
8
  export declare const ReallyMeArgon2id: {
7
9
  readonly deriveKey: (kdfVersion: number, secret: Uint8Array, salt: Uint8Array) => Uint8Array;
10
+ readonly deriveKeyWithProvider: (provider: ReallyMeWasmProvider, kdfVersion: number, secret: Uint8Array, salt: Uint8Array) => Uint8Array;
8
11
  };
package/dist/argon2id.js CHANGED
@@ -2,10 +2,12 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
+ import { ensureByteArrayAtMost, ensureIndependentByteArray, } from "./validateBytes.js";
5
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
6
7
  export const ARGON2ID_DERIVED_KEY_LENGTH = 32;
7
8
  export const ARGON2ID_SALT_MIN_LENGTH = 16;
8
9
  export const ARGON2ID_SALT_MAX_LENGTH = 32;
10
+ export const ARGON2ID_SECRET_MAX_LENGTH = 1_048_576;
9
11
  export const ARGON2ID_V1 = 1;
10
12
  export const ARGON2ID_V2 = 2;
11
13
  const validateVersion = (kdfVersion) => {
@@ -15,17 +17,24 @@ const validateVersion = (kdfVersion) => {
15
17
  }
16
18
  };
17
19
  const validateSecret = (secret) => {
20
+ ensureByteArrayAtMost(secret, ARGON2ID_SECRET_MAX_LENGTH);
18
21
  if (secret.length === 0) {
19
22
  throw new ReallyMeCryptoError("invalid-input");
20
23
  }
21
24
  };
22
25
  const validateSalt = (salt) => {
26
+ ensureByteArrayAtMost(salt, ARGON2ID_SALT_MAX_LENGTH);
23
27
  if (salt.length < ARGON2ID_SALT_MIN_LENGTH || salt.length > ARGON2ID_SALT_MAX_LENGTH) {
24
28
  throw new ReallyMeCryptoError("invalid-input");
25
29
  }
26
30
  };
27
- const requireDerivedKey = (value) => {
28
- if (!(value instanceof Uint8Array) || value.length !== ARGON2ID_DERIVED_KEY_LENGTH) {
31
+ const requireDerivedKey = (value, inputs) => {
32
+ if (!(value instanceof Uint8Array)) {
33
+ throw new ReallyMeCryptoError("provider-failure");
34
+ }
35
+ ensureIndependentByteArray(value, inputs);
36
+ if (value.length !== ARGON2ID_DERIVED_KEY_LENGTH) {
37
+ value.fill(0);
29
38
  throw new ReallyMeCryptoError("provider-failure");
30
39
  }
31
40
  return value;
@@ -35,6 +44,12 @@ export const ReallyMeArgon2id = {
35
44
  validateVersion(kdfVersion);
36
45
  validateSecret(secret);
37
46
  validateSalt(salt);
38
- return requireDerivedKey(requireReallyMeWasmProvider().argon2idDeriveKey(kdfVersion, secret, salt));
47
+ return requireDerivedKey(requireReallyMeWasmProvider().argon2idDeriveKey(kdfVersion, secret, salt), [secret, salt]);
48
+ },
49
+ deriveKeyWithProvider(provider, kdfVersion, secret, salt) {
50
+ validateVersion(kdfVersion);
51
+ validateSecret(secret);
52
+ validateSalt(salt);
53
+ return requireDerivedKey(provider.argon2idDeriveKey(kdfVersion, secret, salt), [secret, salt]);
39
54
  },
40
55
  };
@@ -1,5 +1,6 @@
1
- import type { ReallyMeAeadAlgorithm, ReallyMeHashAlgorithm, ReallyMeHpkeSuite, ReallyMeKdfAlgorithm, ReallyMeKemAlgorithm, ReallyMeKeyAgreementAlgorithm, ReallyMeKeyWrapAlgorithm, ReallyMeMacAlgorithm, ReallyMeSignatureAlgorithm } from "./algorithms.js";
1
+ import type { ReallyMeAeadAlgorithm, ReallyMeHashAlgorithm, ReallyMeHkdfAlgorithm, ReallyMeHpkeSuite, ReallyMeJwaConcatKdfAlgorithm, ReallyMeKemAlgorithm, ReallyMeKeyAgreementAlgorithm, ReallyMeKeyWrapAlgorithm, ReallyMeKmacKdfAlgorithm, ReallyMeMacAlgorithm, ReallyMePbkdf2Algorithm, ReallyMeSignatureAlgorithm } from "./algorithms.js";
2
2
  import type { ReallyMeRsaPublicKeyDerEncoding } from "./rsa.js";
3
+ import type { ReallyMeWasmProvider } from "./wasmProvider.js";
3
4
  export type ReallyMeSignatureKeyPair = Readonly<{
4
5
  publicKey: Uint8Array;
5
6
  secretKey: Uint8Array;
@@ -20,20 +21,78 @@ export type ReallyMeHpkeSealedMessage = Readonly<{
20
21
  encapsulatedKey: Uint8Array;
21
22
  ciphertext: Uint8Array;
22
23
  }>;
24
+ export type ReallyMeCryptoProviders = Readonly<{
25
+ wasmProvider?: ReallyMeWasmProvider;
26
+ }>;
23
27
  /**
24
28
  * Generic package facade. Algorithm-specific objects remain available for
25
29
  * callers that want direct provider access; this facade gives consumers a
26
- * stable typed route that fails closed for not-yet-exposed algorithms.
30
+ * stable typed route and rejects algorithm/operation combinations that the
31
+ * selected method does not define.
27
32
  */
33
+ declare const createReallyMeCryptoFacade: (resolveWasmProvider: () => ReallyMeWasmProvider) => {
34
+ /**
35
+ * Executes a generated binary request and returns a binary
36
+ * `CryptoOperationResponse`.
37
+ */
38
+ readonly processOperationResponse: (request: Uint8Array) => Uint8Array;
39
+ /**
40
+ * Executes a permitted non-secret generated ProtoJSON request and returns
41
+ * the same binary `CryptoOperationResponse`. Secret-bearing selectors fail
42
+ * before JSON value deserialization.
43
+ */
44
+ readonly processOperationResponseJson: (requestJson: Uint8Array) => Uint8Array;
45
+ readonly hash: (algorithm: ReallyMeHashAlgorithm, bytes: Uint8Array) => Uint8Array;
46
+ readonly seal: (algorithm: ReallyMeAeadAlgorithm, key: Uint8Array, nonce: Uint8Array, aad: Uint8Array, plaintext: Uint8Array) => Uint8Array;
47
+ readonly open: (algorithm: ReallyMeAeadAlgorithm, key: Uint8Array, nonce: Uint8Array, aad: Uint8Array, ciphertextWithTag: Uint8Array) => Uint8Array;
48
+ readonly authenticate: (algorithm: ReallyMeMacAlgorithm, key: Uint8Array, message: Uint8Array) => Uint8Array;
49
+ readonly verifyMac: (algorithm: ReallyMeMacAlgorithm, tag: Uint8Array, key: Uint8Array, message: Uint8Array) => boolean;
50
+ readonly deriveArgon2id: (kdfVersion: number, secret: Uint8Array, salt: Uint8Array) => Uint8Array;
51
+ readonly deriveKey: (algorithm: ReallyMePbkdf2Algorithm, password: Uint8Array, salt: Uint8Array, iterations: number, outputLength: number) => Uint8Array;
52
+ readonly deriveHkdf: (algorithm: ReallyMeHkdfAlgorithm, inputKeyMaterial: Uint8Array, salt: Uint8Array, info: Uint8Array, outputLength: number) => Uint8Array;
53
+ readonly deriveJwaConcatKdfSha256: (algorithm: ReallyMeJwaConcatKdfAlgorithm, sharedSecret: Uint8Array, algorithmId: Uint8Array, partyUInfo: Uint8Array, partyVInfo: Uint8Array, outputLength: number) => Uint8Array;
54
+ readonly deriveKmac256: (algorithm: ReallyMeKmacKdfAlgorithm, key: Uint8Array, context: Uint8Array, customization: Uint8Array, outputLength: number) => Uint8Array;
55
+ readonly wrapKey: (algorithm: ReallyMeKeyWrapAlgorithm, wrappingKey: Uint8Array, keyToWrap: Uint8Array) => Uint8Array;
56
+ readonly unwrapKey: (algorithm: ReallyMeKeyWrapAlgorithm, wrappingKey: Uint8Array, wrappedKey: Uint8Array) => Uint8Array;
57
+ readonly generateKeyPair: (algorithm: ReallyMeSignatureAlgorithm) => ReallyMeSignatureKeyPair;
58
+ readonly deriveKeyPair: (algorithm: ReallyMeSignatureAlgorithm, secretKey: Uint8Array) => ReallyMeSignatureKeyPair;
59
+ readonly sign: (algorithm: ReallyMeSignatureAlgorithm, message: Uint8Array, secretKey: Uint8Array) => Uint8Array;
60
+ readonly signBip340Schnorr: (message32: Uint8Array, secretKey: Uint8Array, auxRand32: Uint8Array) => Uint8Array;
61
+ readonly verify: (algorithm: ReallyMeSignatureAlgorithm, signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array) => void;
62
+ readonly verifyRsa: (algorithm: ReallyMeSignatureAlgorithm, signature: Uint8Array, message: Uint8Array, publicKeyDer: Uint8Array, publicKeyEncoding: ReallyMeRsaPublicKeyDerEncoding) => void;
63
+ readonly deriveSharedSecret: (algorithm: ReallyMeKeyAgreementAlgorithm, publicKey: Uint8Array, secretKey: Uint8Array) => Uint8Array;
64
+ readonly deriveKeyAgreementKeyPair: (algorithm: ReallyMeKeyAgreementAlgorithm, secretKey: Uint8Array) => ReallyMeKeyAgreementKeyPair;
65
+ readonly generateKemKeyPair: (algorithm: ReallyMeKemAlgorithm) => ReallyMeKemKeyPair;
66
+ readonly deriveKemKeyPair: (algorithm: ReallyMeKemAlgorithm, secretKey: Uint8Array) => ReallyMeKemKeyPair;
67
+ readonly encapsulate: (algorithm: ReallyMeKemAlgorithm, publicKey: Uint8Array) => ReallyMeKemEncapsulation;
68
+ readonly decapsulate: (algorithm: ReallyMeKemAlgorithm, ciphertext: Uint8Array, secretKey: Uint8Array) => Uint8Array;
69
+ readonly sealHpke: (suite: ReallyMeHpkeSuite, recipientPublicKey: Uint8Array, info: Uint8Array, aad: Uint8Array, plaintext: Uint8Array) => ReallyMeHpkeSealedMessage;
70
+ readonly openHpke: (suite: ReallyMeHpkeSuite, recipientSecretKey: Uint8Array, encapsulatedKey: Uint8Array, info: Uint8Array, aad: Uint8Array, ciphertext: Uint8Array) => Uint8Array;
71
+ };
72
+ export type ReallyMeCryptoFacade = ReturnType<typeof createReallyMeCryptoFacade>;
73
+ export declare const createReallyMeCrypto: (providers?: ReallyMeCryptoProviders) => ReallyMeCryptoFacade;
28
74
  export declare const ReallyMeCrypto: {
75
+ /**
76
+ * Executes a generated binary request and returns a binary
77
+ * `CryptoOperationResponse`.
78
+ */
79
+ readonly processOperationResponse: (request: Uint8Array) => Uint8Array;
80
+ /**
81
+ * Executes a permitted non-secret generated ProtoJSON request and returns
82
+ * the same binary `CryptoOperationResponse`. Secret-bearing selectors fail
83
+ * before JSON value deserialization.
84
+ */
85
+ readonly processOperationResponseJson: (requestJson: Uint8Array) => Uint8Array;
29
86
  readonly hash: (algorithm: ReallyMeHashAlgorithm, bytes: Uint8Array) => Uint8Array;
30
87
  readonly seal: (algorithm: ReallyMeAeadAlgorithm, key: Uint8Array, nonce: Uint8Array, aad: Uint8Array, plaintext: Uint8Array) => Uint8Array;
31
88
  readonly open: (algorithm: ReallyMeAeadAlgorithm, key: Uint8Array, nonce: Uint8Array, aad: Uint8Array, ciphertextWithTag: Uint8Array) => Uint8Array;
32
89
  readonly authenticate: (algorithm: ReallyMeMacAlgorithm, key: Uint8Array, message: Uint8Array) => Uint8Array;
33
90
  readonly verifyMac: (algorithm: ReallyMeMacAlgorithm, tag: Uint8Array, key: Uint8Array, message: Uint8Array) => boolean;
34
- readonly deriveKey: (algorithm: ReallyMeKdfAlgorithm, password: Uint8Array, salt: Uint8Array, iterations: number, outputLength: number) => Uint8Array;
35
- readonly deriveHkdf: (algorithm: ReallyMeKdfAlgorithm, inputKeyMaterial: Uint8Array, salt: Uint8Array, info: Uint8Array, outputLength: number) => Uint8Array;
36
- readonly deriveJwaConcatKdfSha256: (algorithm: ReallyMeKdfAlgorithm, sharedSecret: Uint8Array, algorithmId: Uint8Array, partyUInfo: Uint8Array, partyVInfo: Uint8Array, outputLength: number) => Uint8Array;
91
+ readonly deriveArgon2id: (kdfVersion: number, secret: Uint8Array, salt: Uint8Array) => Uint8Array;
92
+ readonly deriveKey: (algorithm: ReallyMePbkdf2Algorithm, password: Uint8Array, salt: Uint8Array, iterations: number, outputLength: number) => Uint8Array;
93
+ readonly deriveHkdf: (algorithm: ReallyMeHkdfAlgorithm, inputKeyMaterial: Uint8Array, salt: Uint8Array, info: Uint8Array, outputLength: number) => Uint8Array;
94
+ readonly deriveJwaConcatKdfSha256: (algorithm: ReallyMeJwaConcatKdfAlgorithm, sharedSecret: Uint8Array, algorithmId: Uint8Array, partyUInfo: Uint8Array, partyVInfo: Uint8Array, outputLength: number) => Uint8Array;
95
+ readonly deriveKmac256: (algorithm: ReallyMeKmacKdfAlgorithm, key: Uint8Array, context: Uint8Array, customization: Uint8Array, outputLength: number) => Uint8Array;
37
96
  readonly wrapKey: (algorithm: ReallyMeKeyWrapAlgorithm, wrappingKey: Uint8Array, keyToWrap: Uint8Array) => Uint8Array;
38
97
  readonly unwrapKey: (algorithm: ReallyMeKeyWrapAlgorithm, wrappingKey: Uint8Array, wrappedKey: Uint8Array) => Uint8Array;
39
98
  readonly generateKeyPair: (algorithm: ReallyMeSignatureAlgorithm) => ReallyMeSignatureKeyPair;
@@ -45,8 +104,10 @@ export declare const ReallyMeCrypto: {
45
104
  readonly deriveSharedSecret: (algorithm: ReallyMeKeyAgreementAlgorithm, publicKey: Uint8Array, secretKey: Uint8Array) => Uint8Array;
46
105
  readonly deriveKeyAgreementKeyPair: (algorithm: ReallyMeKeyAgreementAlgorithm, secretKey: Uint8Array) => ReallyMeKeyAgreementKeyPair;
47
106
  readonly generateKemKeyPair: (algorithm: ReallyMeKemAlgorithm) => ReallyMeKemKeyPair;
107
+ readonly deriveKemKeyPair: (algorithm: ReallyMeKemAlgorithm, secretKey: Uint8Array) => ReallyMeKemKeyPair;
48
108
  readonly encapsulate: (algorithm: ReallyMeKemAlgorithm, publicKey: Uint8Array) => ReallyMeKemEncapsulation;
49
109
  readonly decapsulate: (algorithm: ReallyMeKemAlgorithm, ciphertext: Uint8Array, secretKey: Uint8Array) => Uint8Array;
50
110
  readonly sealHpke: (suite: ReallyMeHpkeSuite, recipientPublicKey: Uint8Array, info: Uint8Array, aad: Uint8Array, plaintext: Uint8Array) => ReallyMeHpkeSealedMessage;
51
111
  readonly openHpke: (suite: ReallyMeHpkeSuite, recipientSecretKey: Uint8Array, encapsulatedKey: Uint8Array, info: Uint8Array, aad: Uint8Array, ciphertext: Uint8Array) => Uint8Array;
52
112
  };
113
+ export {};
@@ -12,6 +12,7 @@ import { ReallyMeHkdf } from "./hkdf.js";
12
12
  import { ReallyMeHmac } from "./hmac.js";
13
13
  import { ReallyMeHpke } from "./hpke.js";
14
14
  import { ReallyMeJwaConcatKdf } from "./jwaConcatKdf.js";
15
+ import { ReallyMeKmac } from "./kmac.js";
15
16
  import { ReallyMeMlDsa } from "./mlDsa.js";
16
17
  import { ReallyMeMlKem } from "./mlKem.js";
17
18
  import { ReallyMeP256Ecdsa } from "./p256Ecdsa.js";
@@ -24,6 +25,9 @@ import { ReallyMePbkdf2 } from "./pbkdf2.js";
24
25
  import { ReallyMeRsa } from "./rsa.js";
25
26
  import { ReallyMeSecp256k1 } from "./secp256k1.js";
26
27
  import { ReallyMeSlhDsa } from "./slhDsa.js";
28
+ import { requireReallyMeWasmProvider } from "./wasmProvider.js";
29
+ import { processOperationResponseJsonWithProvider, processOperationResponseWithProvider, } from "./operationResponse.js";
30
+ import { ensureByteArray } from "./validateBytes.js";
27
31
  import { ReallyMeX25519 } from "./x25519.js";
28
32
  import { ReallyMeXWing } from "./xWing.js";
29
33
  const SECP256K1_ECDSA = "ECDSA-secp256k1-SHA256";
@@ -35,9 +39,27 @@ const ED25519 = "Ed25519";
35
39
  /**
36
40
  * Generic package facade. Algorithm-specific objects remain available for
37
41
  * callers that want direct provider access; this facade gives consumers a
38
- * stable typed route that fails closed for not-yet-exposed algorithms.
42
+ * stable typed route and rejects algorithm/operation combinations that the
43
+ * selected method does not define.
39
44
  */
40
- export const ReallyMeCrypto = {
45
+ const createReallyMeCryptoFacade = (resolveWasmProvider) => ({
46
+ /**
47
+ * Executes a generated binary request and returns a binary
48
+ * `CryptoOperationResponse`.
49
+ */
50
+ processOperationResponse(request) {
51
+ ensureByteArray(request);
52
+ return processOperationResponseWithProvider(resolveWasmProvider(), request);
53
+ },
54
+ /**
55
+ * Executes a permitted non-secret generated ProtoJSON request and returns
56
+ * the same binary `CryptoOperationResponse`. Secret-bearing selectors fail
57
+ * before JSON value deserialization.
58
+ */
59
+ processOperationResponseJson(requestJson) {
60
+ ensureByteArray(requestJson);
61
+ return processOperationResponseJsonWithProvider(resolveWasmProvider(), requestJson);
62
+ },
41
63
  hash(algorithm, bytes) {
42
64
  switch (algorithm) {
43
65
  case "SHA2-256":
@@ -66,7 +88,7 @@ export const ReallyMeCrypto = {
66
88
  case "AES-256-GCM-SIV":
67
89
  case "ChaCha20-Poly1305":
68
90
  case "XChaCha20-Poly1305":
69
- return ReallyMeAead.seal(algorithm, key, nonce, aad, plaintext);
91
+ return ReallyMeAead.sealWithProvider(resolveWasmProvider(), algorithm, key, nonce, aad, plaintext);
70
92
  default:
71
93
  throw new ReallyMeCryptoError("unsupported-algorithm");
72
94
  }
@@ -79,7 +101,7 @@ export const ReallyMeCrypto = {
79
101
  case "AES-256-GCM-SIV":
80
102
  case "ChaCha20-Poly1305":
81
103
  case "XChaCha20-Poly1305":
82
- return ReallyMeAead.open(algorithm, key, nonce, aad, ciphertextWithTag);
104
+ return ReallyMeAead.openWithProvider(resolveWasmProvider(), algorithm, key, nonce, aad, ciphertextWithTag);
83
105
  default:
84
106
  throw new ReallyMeCryptoError("unsupported-algorithm");
85
107
  }
@@ -88,6 +110,8 @@ export const ReallyMeCrypto = {
88
110
  switch (algorithm) {
89
111
  case "HMAC-SHA-256":
90
112
  return ReallyMeHmac.authenticateSha256(key, message);
113
+ case "HMAC-SHA-384":
114
+ return ReallyMeHmac.authenticateSha384(key, message);
91
115
  case "HMAC-SHA-512":
92
116
  return ReallyMeHmac.authenticateSha512(key, message);
93
117
  default:
@@ -98,22 +122,23 @@ export const ReallyMeCrypto = {
98
122
  switch (algorithm) {
99
123
  case "HMAC-SHA-256":
100
124
  return ReallyMeHmac.verifySha256(tag, key, message);
125
+ case "HMAC-SHA-384":
126
+ return ReallyMeHmac.verifySha384(tag, key, message);
101
127
  case "HMAC-SHA-512":
102
128
  return ReallyMeHmac.verifySha512(tag, key, message);
103
129
  default:
104
130
  throw new ReallyMeCryptoError("unsupported-algorithm");
105
131
  }
106
132
  },
133
+ deriveArgon2id(kdfVersion, secret, salt) {
134
+ return ReallyMeArgon2id.deriveKeyWithProvider(resolveWasmProvider(), kdfVersion, secret, salt);
135
+ },
107
136
  deriveKey(algorithm, password, salt, iterations, outputLength) {
108
137
  switch (algorithm) {
109
- case "Argon2id":
110
- return ReallyMeArgon2id.deriveKey(iterations, password, salt);
111
138
  case "PBKDF2-HMAC-SHA-256":
112
139
  return ReallyMePbkdf2.deriveHmacSha256(password, salt, iterations, outputLength);
113
140
  case "PBKDF2-HMAC-SHA-512":
114
141
  return ReallyMePbkdf2.deriveHmacSha512(password, salt, iterations, outputLength);
115
- case "HKDF-SHA256":
116
- throw new ReallyMeCryptoError("unsupported-algorithm");
117
142
  default:
118
143
  throw new ReallyMeCryptoError("unsupported-algorithm");
119
144
  }
@@ -122,11 +147,8 @@ export const ReallyMeCrypto = {
122
147
  switch (algorithm) {
123
148
  case "HKDF-SHA256":
124
149
  return ReallyMeHkdf.deriveSha256(inputKeyMaterial, salt, info, outputLength);
125
- case "Argon2id":
126
- case "PBKDF2-HMAC-SHA-256":
127
- case "PBKDF2-HMAC-SHA-512":
128
- case "JWA-CONCAT-KDF-SHA256":
129
- throw new ReallyMeCryptoError("unsupported-algorithm");
150
+ case "HKDF-SHA384":
151
+ return ReallyMeHkdf.deriveSha384(inputKeyMaterial, salt, info, outputLength);
130
152
  default:
131
153
  throw new ReallyMeCryptoError("unsupported-algorithm");
132
154
  }
@@ -135,27 +157,34 @@ export const ReallyMeCrypto = {
135
157
  switch (algorithm) {
136
158
  case "JWA-CONCAT-KDF-SHA256":
137
159
  return ReallyMeJwaConcatKdf.deriveSha256(sharedSecret, algorithmId, partyUInfo, partyVInfo, outputLength);
138
- case "Argon2id":
139
- case "HKDF-SHA256":
140
- case "PBKDF2-HMAC-SHA-256":
141
- case "PBKDF2-HMAC-SHA-512":
160
+ default:
142
161
  throw new ReallyMeCryptoError("unsupported-algorithm");
162
+ }
163
+ },
164
+ deriveKmac256(algorithm, key, context, customization, outputLength) {
165
+ switch (algorithm) {
166
+ case "KMAC256":
167
+ return ReallyMeKmac.deriveKmac256WithProvider(resolveWasmProvider(), key, context, customization, outputLength);
143
168
  default:
144
169
  throw new ReallyMeCryptoError("unsupported-algorithm");
145
170
  }
146
171
  },
147
172
  wrapKey(algorithm, wrappingKey, keyToWrap) {
148
173
  switch (algorithm) {
174
+ case "AES-128-KW":
175
+ case "AES-192-KW":
149
176
  case "AES-256-KW":
150
- return ReallyMeAesKw.wrapKey(wrappingKey, keyToWrap);
177
+ return ReallyMeAesKw.wrapKeyWithProvider(algorithm, resolveWasmProvider(), wrappingKey, keyToWrap);
151
178
  default:
152
179
  throw new ReallyMeCryptoError("unsupported-algorithm");
153
180
  }
154
181
  },
155
182
  unwrapKey(algorithm, wrappingKey, wrappedKey) {
156
183
  switch (algorithm) {
184
+ case "AES-128-KW":
185
+ case "AES-192-KW":
157
186
  case "AES-256-KW":
158
- return ReallyMeAesKw.unwrapKey(wrappingKey, wrappedKey);
187
+ return ReallyMeAesKw.unwrapKeyWithProvider(algorithm, resolveWasmProvider(), wrappingKey, wrappedKey);
159
188
  default:
160
189
  throw new ReallyMeCryptoError("unsupported-algorithm");
161
190
  }
@@ -178,9 +207,9 @@ export const ReallyMeCrypto = {
178
207
  case "ML-DSA-44":
179
208
  case "ML-DSA-65":
180
209
  case "ML-DSA-87":
181
- return ReallyMeMlDsa.generateKeyPair(algorithm);
210
+ return ReallyMeMlDsa.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
182
211
  case "SLH-DSA-SHA2-128s":
183
- return ReallyMeSlhDsa.generateKeyPair(algorithm);
212
+ return ReallyMeSlhDsa.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
184
213
  default:
185
214
  throw new ReallyMeCryptoError("unsupported-algorithm");
186
215
  }
@@ -206,7 +235,7 @@ export const ReallyMeCrypto = {
206
235
  case "ML-DSA-44":
207
236
  case "ML-DSA-65":
208
237
  case "ML-DSA-87":
209
- return ReallyMeMlDsa.deriveKeyPair(algorithm, secretKey);
238
+ return ReallyMeMlDsa.deriveKeyPairWithProvider(resolveWasmProvider(), algorithm, secretKey);
210
239
  case "SLH-DSA-SHA2-128s":
211
240
  // SLH-DSA deterministic derivation uses three FIPS seed components,
212
241
  // so it deliberately does not fit this single-secret import shape.
@@ -231,9 +260,9 @@ export const ReallyMeCrypto = {
231
260
  case "ML-DSA-44":
232
261
  case "ML-DSA-65":
233
262
  case "ML-DSA-87":
234
- return ReallyMeMlDsa.sign(algorithm, message, secretKey);
263
+ return ReallyMeMlDsa.signWithProvider(resolveWasmProvider(), algorithm, message, secretKey);
235
264
  case "SLH-DSA-SHA2-128s":
236
- return ReallyMeSlhDsa.sign(algorithm, message, secretKey);
265
+ return ReallyMeSlhDsa.signWithProvider(resolveWasmProvider(), algorithm, message, secretKey);
237
266
  default:
238
267
  throw new ReallyMeCryptoError("unsupported-algorithm");
239
268
  }
@@ -265,17 +294,30 @@ export const ReallyMeCrypto = {
265
294
  case "ML-DSA-44":
266
295
  case "ML-DSA-65":
267
296
  case "ML-DSA-87":
268
- ReallyMeMlDsa.verify(algorithm, signature, message, publicKey);
297
+ ReallyMeMlDsa.verifyWithProvider(resolveWasmProvider(), algorithm, signature, message, publicKey);
269
298
  return;
270
299
  case "SLH-DSA-SHA2-128s":
271
- ReallyMeSlhDsa.verify(algorithm, signature, message, publicKey);
300
+ ReallyMeSlhDsa.verifyWithProvider(resolveWasmProvider(), algorithm, signature, message, publicKey);
272
301
  return;
273
302
  default:
274
303
  throw new ReallyMeCryptoError("unsupported-algorithm");
275
304
  }
276
305
  },
277
306
  verifyRsa(algorithm, signature, message, publicKeyDer, publicKeyEncoding) {
278
- ReallyMeRsa.verify(algorithm, signature, message, publicKeyDer, publicKeyEncoding);
307
+ switch (algorithm) {
308
+ case "RSA-PKCS1v15-SHA1":
309
+ case "RSA-PKCS1v15-SHA256":
310
+ case "RSA-PKCS1v15-SHA384":
311
+ case "RSA-PKCS1v15-SHA512":
312
+ case "RSA-PSS-SHA1-MGF1-SHA1":
313
+ case "RSA-PSS-SHA256-MGF1-SHA256":
314
+ case "RSA-PSS-SHA384-MGF1-SHA384":
315
+ case "RSA-PSS-SHA512-MGF1-SHA512":
316
+ ReallyMeRsa.verifyWithProvider(resolveWasmProvider(), algorithm, signature, message, publicKeyDer, publicKeyEncoding);
317
+ return;
318
+ default:
319
+ throw new ReallyMeCryptoError("unsupported-algorithm");
320
+ }
279
321
  },
280
322
  deriveSharedSecret(algorithm, publicKey, secretKey) {
281
323
  switch (algorithm) {
@@ -308,12 +350,23 @@ export const ReallyMeCrypto = {
308
350
  generateKemKeyPair(algorithm) {
309
351
  switch (algorithm) {
310
352
  case "X-Wing-768":
311
- case "X-Wing-1024":
312
- return ReallyMeXWing.generateKeyPair(algorithm);
353
+ return ReallyMeXWing.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
313
354
  case "ML-KEM-512":
314
355
  case "ML-KEM-768":
315
356
  case "ML-KEM-1024":
316
- return ReallyMeMlKem.generateKeyPair(algorithm);
357
+ return ReallyMeMlKem.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
358
+ default:
359
+ throw new ReallyMeCryptoError("unsupported-algorithm");
360
+ }
361
+ },
362
+ deriveKemKeyPair(algorithm, secretKey) {
363
+ switch (algorithm) {
364
+ case "X-Wing-768":
365
+ return ReallyMeXWing.deriveKeyPairWithProvider(resolveWasmProvider(), algorithm, secretKey);
366
+ case "ML-KEM-512":
367
+ case "ML-KEM-768":
368
+ case "ML-KEM-1024":
369
+ return ReallyMeMlKem.deriveKeyPairWithProvider(resolveWasmProvider(), algorithm, secretKey);
317
370
  default:
318
371
  throw new ReallyMeCryptoError("unsupported-algorithm");
319
372
  }
@@ -321,12 +374,11 @@ export const ReallyMeCrypto = {
321
374
  encapsulate(algorithm, publicKey) {
322
375
  switch (algorithm) {
323
376
  case "X-Wing-768":
324
- case "X-Wing-1024":
325
- return ReallyMeXWing.encapsulate(algorithm, publicKey);
377
+ return ReallyMeXWing.encapsulateWithProvider(resolveWasmProvider(), algorithm, publicKey);
326
378
  case "ML-KEM-512":
327
379
  case "ML-KEM-768":
328
380
  case "ML-KEM-1024":
329
- return ReallyMeMlKem.encapsulate(algorithm, publicKey);
381
+ return ReallyMeMlKem.encapsulateWithProvider(resolveWasmProvider(), algorithm, publicKey);
330
382
  default:
331
383
  throw new ReallyMeCryptoError("unsupported-algorithm");
332
384
  }
@@ -334,12 +386,11 @@ export const ReallyMeCrypto = {
334
386
  decapsulate(algorithm, ciphertext, secretKey) {
335
387
  switch (algorithm) {
336
388
  case "X-Wing-768":
337
- case "X-Wing-1024":
338
- return ReallyMeXWing.decapsulate(algorithm, ciphertext, secretKey);
389
+ return ReallyMeXWing.decapsulateWithProvider(resolveWasmProvider(), algorithm, ciphertext, secretKey);
339
390
  case "ML-KEM-512":
340
391
  case "ML-KEM-768":
341
392
  case "ML-KEM-1024":
342
- return ReallyMeMlKem.decapsulate(algorithm, ciphertext, secretKey);
393
+ return ReallyMeMlKem.decapsulateWithProvider(resolveWasmProvider(), algorithm, ciphertext, secretKey);
343
394
  default:
344
395
  throw new ReallyMeCryptoError("unsupported-algorithm");
345
396
  }
@@ -348,7 +399,7 @@ export const ReallyMeCrypto = {
348
399
  switch (suite) {
349
400
  case "DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM":
350
401
  case "DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305":
351
- return ReallyMeHpke.sealBase(suite, recipientPublicKey, info, aad, plaintext);
402
+ return ReallyMeHpke.sealBaseWithProvider(resolveWasmProvider(), suite, recipientPublicKey, info, aad, plaintext);
352
403
  default:
353
404
  throw new ReallyMeCryptoError("unsupported-algorithm");
354
405
  }
@@ -357,9 +408,19 @@ export const ReallyMeCrypto = {
357
408
  switch (suite) {
358
409
  case "DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM":
359
410
  case "DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305":
360
- return ReallyMeHpke.openBase(suite, recipientSecretKey, encapsulatedKey, info, aad, ciphertext);
411
+ return ReallyMeHpke.openBaseWithProvider(resolveWasmProvider(), suite, recipientSecretKey, encapsulatedKey, info, aad, ciphertext);
361
412
  default:
362
413
  throw new ReallyMeCryptoError("unsupported-algorithm");
363
414
  }
364
415
  },
416
+ });
417
+ export const createReallyMeCrypto = (providers = {}) => {
418
+ const configuredProvider = providers.wasmProvider;
419
+ return createReallyMeCryptoFacade(() => {
420
+ if (configuredProvider === undefined) {
421
+ throw new ReallyMeCryptoError("provider-failure");
422
+ }
423
+ return configuredProvider;
424
+ });
365
425
  };
426
+ export const ReallyMeCrypto = createReallyMeCryptoFacade(requireReallyMeWasmProvider);
package/dist/errors.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * user-provided bytes so callers can log them without leaking key material
4
4
  * or PII.
5
5
  */
6
- export type ReallyMeCryptoErrorCode = "invalid-input" | "invalid-signature" | "provider-failure" | "unsupported-algorithm";
6
+ export type ReallyMeCryptoErrorCode = "invalid-input" | "invalid-signature" | "authentication-failed" | "provider-failure" | "unsupported-algorithm";
7
7
  export declare class ReallyMeCryptoError extends Error {
8
8
  readonly code: ReallyMeCryptoErrorCode;
9
9
  constructor(code: ReallyMeCryptoErrorCode);
package/dist/hkdf.d.ts CHANGED
@@ -4,4 +4,5 @@ export declare const HKDF_MIN_OUTPUT_LENGTH = 1;
4
4
  export declare const HKDF_MAX_OUTPUT_LENGTH = 4096;
5
5
  export declare const ReallyMeHkdf: {
6
6
  readonly deriveSha256: (inputKeyMaterial: Uint8Array, salt: Uint8Array, info: Uint8Array, outputLength: number) => Uint8Array;
7
+ readonly deriveSha384: (inputKeyMaterial: Uint8Array, salt: Uint8Array, info: Uint8Array, outputLength: number) => Uint8Array;
7
8
  };
package/dist/hkdf.js CHANGED
@@ -2,7 +2,7 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import { hkdf } from "@noble/hashes/hkdf.js";
5
- import { sha256 } from "@noble/hashes/sha2.js";
5
+ import { sha256, sha384 } from "@noble/hashes/sha2.js";
6
6
  import { ReallyMeCryptoError } from "./errors.js";
7
7
  export const HKDF_MIN_INPUT_KEY_MATERIAL_LENGTH = 1;
8
8
  export const HKDF_MAX_INPUT_LENGTH = 4096;
@@ -13,6 +13,10 @@ export const ReallyMeHkdf = {
13
13
  validate(inputKeyMaterial, salt, info, outputLength);
14
14
  return hkdf(sha256, inputKeyMaterial, salt, info, outputLength);
15
15
  },
16
+ deriveSha384(inputKeyMaterial, salt, info, outputLength) {
17
+ validate(inputKeyMaterial, salt, info, outputLength);
18
+ return hkdf(sha384, inputKeyMaterial, salt, info, outputLength);
19
+ },
16
20
  };
17
21
  function validate(inputKeyMaterial, salt, info, outputLength) {
18
22
  if (inputKeyMaterial.length < HKDF_MIN_INPUT_KEY_MATERIAL_LENGTH ||
package/dist/hmac.d.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  export declare const HMAC_MAX_KEY_LENGTH = 4096;
2
2
  export declare const HMAC_SHA256_TAG_LENGTH = 32;
3
+ export declare const HMAC_SHA384_TAG_LENGTH = 48;
3
4
  export declare const HMAC_SHA512_TAG_LENGTH = 64;
4
5
  export declare const ReallyMeHmac: {
5
6
  readonly authenticateSha256: (key: Uint8Array, message: Uint8Array) => Uint8Array;
7
+ readonly authenticateSha384: (key: Uint8Array, message: Uint8Array) => Uint8Array;
6
8
  readonly authenticateSha512: (key: Uint8Array, message: Uint8Array) => Uint8Array;
7
9
  readonly verifySha256: (tag: Uint8Array, key: Uint8Array, message: Uint8Array) => boolean;
10
+ readonly verifySha384: (tag: Uint8Array, key: Uint8Array, message: Uint8Array) => boolean;
8
11
  readonly verifySha512: (tag: Uint8Array, key: Uint8Array, message: Uint8Array) => boolean;
9
12
  };
package/dist/hmac.js CHANGED
@@ -2,16 +2,21 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import { hmac } from "@noble/hashes/hmac.js";
5
- import { sha256, sha512 } from "@noble/hashes/sha2.js";
5
+ import { sha256, sha384, sha512 } from "@noble/hashes/sha2.js";
6
6
  import { ReallyMeCryptoError } from "./errors.js";
7
7
  export const HMAC_MAX_KEY_LENGTH = 4096;
8
8
  export const HMAC_SHA256_TAG_LENGTH = 32;
9
+ export const HMAC_SHA384_TAG_LENGTH = 48;
9
10
  export const HMAC_SHA512_TAG_LENGTH = 64;
10
11
  export const ReallyMeHmac = {
11
12
  authenticateSha256(key, message) {
12
13
  validateKey(key);
13
14
  return hmac(sha256, key, message);
14
15
  },
16
+ authenticateSha384(key, message) {
17
+ validateKey(key);
18
+ return hmac(sha384, key, message);
19
+ },
15
20
  authenticateSha512(key, message) {
16
21
  validateKey(key);
17
22
  return hmac(sha512, key, message);
@@ -20,13 +25,19 @@ export const ReallyMeHmac = {
20
25
  if (tag.length !== HMAC_SHA256_TAG_LENGTH) {
21
26
  throw new ReallyMeCryptoError("invalid-input");
22
27
  }
23
- return constantTimeEquals(tag, ReallyMeHmac.authenticateSha256(key, message));
28
+ return verifyAndClearExpectedTag(tag, ReallyMeHmac.authenticateSha256(key, message));
29
+ },
30
+ verifySha384(tag, key, message) {
31
+ if (tag.length !== HMAC_SHA384_TAG_LENGTH) {
32
+ throw new ReallyMeCryptoError("invalid-input");
33
+ }
34
+ return verifyAndClearExpectedTag(tag, ReallyMeHmac.authenticateSha384(key, message));
24
35
  },
25
36
  verifySha512(tag, key, message) {
26
37
  if (tag.length !== HMAC_SHA512_TAG_LENGTH) {
27
38
  throw new ReallyMeCryptoError("invalid-input");
28
39
  }
29
- return constantTimeEquals(tag, ReallyMeHmac.authenticateSha512(key, message));
40
+ return verifyAndClearExpectedTag(tag, ReallyMeHmac.authenticateSha512(key, message));
30
41
  },
31
42
  };
32
43
  function validateKey(key) {
@@ -48,3 +59,13 @@ function constantTimeEquals(left, right) {
48
59
  }
49
60
  return difference === 0;
50
61
  }
62
+ function verifyAndClearExpectedTag(tag, expectedTag) {
63
+ try {
64
+ return constantTimeEquals(tag, expectedTag);
65
+ }
66
+ finally {
67
+ // Noble returns a new typed array. Clear it immediately so verification
68
+ // does not retain key-derived authentication material until a GC cycle.
69
+ expectedTag.fill(0);
70
+ }
71
+ }