@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
package/dist/rsa.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { ReallyMeSignatureAlgorithm } from "./algorithms.js";
2
+ import type { ReallyMeWasmProvider } from "./wasmProvider.js";
2
3
  export type ReallyMeRsaPublicKeyDerEncoding = "PKCS1" | "SPKI";
3
4
  export declare const RSA_PUBLIC_KEY_DER_MAX_LENGTH = 4096;
4
5
  export declare const RSA_SIGNATURE_MAX_LENGTH = 1024;
@@ -6,8 +7,10 @@ export declare const RSA_SIGNATURE_MAX_LENGTH = 1024;
6
7
  * RSA signature verification through the ReallyMe Rust WASM provider.
7
8
  *
8
9
  * RSA is verification-only in this SDK. It exists for X.509, eMRTD passive
9
- * authentication, and legacy interoperability; no RSA signing API is exposed.
10
+ * authentication, and historical document interoperability; no RSA signing
11
+ * API is exposed.
10
12
  */
11
13
  export declare const ReallyMeRsa: {
12
14
  readonly verify: (algorithm: ReallyMeSignatureAlgorithm, signature: Uint8Array, message: Uint8Array, publicKeyDer: Uint8Array, publicKeyEncoding: ReallyMeRsaPublicKeyDerEncoding) => void;
15
+ readonly verifyWithProvider: (provider: ReallyMeWasmProvider, algorithm: ReallyMeSignatureAlgorithm, signature: Uint8Array, message: Uint8Array, publicKeyDer: Uint8Array, publicKeyEncoding: ReallyMeRsaPublicKeyDerEncoding) => void;
13
16
  };
package/dist/rsa.js CHANGED
@@ -2,6 +2,7 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
+ import { ensureByteArray, ensureByteArrayAtMost, MAX_CRYPTO_INPUT_LENGTH, } from "./validateBytes.js";
5
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
6
7
  export const RSA_PUBLIC_KEY_DER_MAX_LENGTH = 4_096;
7
8
  export const RSA_SIGNATURE_MAX_LENGTH = 1_024;
@@ -12,6 +13,7 @@ const RSA_HASH_SHA512 = 4;
12
13
  const RSA_PUBLIC_KEY_ENCODING_PKCS1_DER = 1;
13
14
  const RSA_PUBLIC_KEY_ENCODING_SPKI_DER = 2;
14
15
  const validateBytes = (bytes, maxLength) => {
16
+ ensureByteArray(bytes);
15
17
  if (bytes.length === 0 || bytes.length > maxLength) {
16
18
  throw new ReallyMeCryptoError("invalid-input");
17
19
  }
@@ -75,28 +77,33 @@ const readVoid = (value) => {
75
77
  throw new ReallyMeCryptoError("provider-failure");
76
78
  }
77
79
  };
80
+ const verifyWithProvider = (provider, algorithm, signature, message, publicKeyDer, publicKeyEncoding) => {
81
+ validateBytes(publicKeyDer, RSA_PUBLIC_KEY_DER_MAX_LENGTH);
82
+ validateBytes(signature, RSA_SIGNATURE_MAX_LENGTH);
83
+ ensureByteArrayAtMost(message, MAX_CRYPTO_INPUT_LENGTH);
84
+ const encoding = encodingId(publicKeyEncoding);
85
+ const pkcs1 = pkcs1v15Suite(algorithm);
86
+ if (pkcs1 !== undefined) {
87
+ readVoid(provider.rsaVerifyPkcs1v15(publicKeyDer, encoding, pkcs1.hashSuite, message, signature));
88
+ return;
89
+ }
90
+ const pss = pssSuite(algorithm);
91
+ if (pss !== undefined) {
92
+ readVoid(provider.rsaVerifyPss(publicKeyDer, encoding, pss.messageHashSuite, pss.mgf1HashSuite, pss.saltLength, message, signature));
93
+ return;
94
+ }
95
+ throw new ReallyMeCryptoError("unsupported-algorithm");
96
+ };
78
97
  /**
79
98
  * RSA signature verification through the ReallyMe Rust WASM provider.
80
99
  *
81
100
  * RSA is verification-only in this SDK. It exists for X.509, eMRTD passive
82
- * authentication, and legacy interoperability; no RSA signing API is exposed.
101
+ * authentication, and historical document interoperability; no RSA signing
102
+ * API is exposed.
83
103
  */
84
104
  export const ReallyMeRsa = {
85
105
  verify(algorithm, signature, message, publicKeyDer, publicKeyEncoding) {
86
- validateBytes(publicKeyDer, RSA_PUBLIC_KEY_DER_MAX_LENGTH);
87
- validateBytes(signature, RSA_SIGNATURE_MAX_LENGTH);
88
- const encoding = encodingId(publicKeyEncoding);
89
- const pkcs1 = pkcs1v15Suite(algorithm);
90
- const provider = requireReallyMeWasmProvider();
91
- if (pkcs1 !== undefined) {
92
- readVoid(provider.rsaVerifyPkcs1v15(publicKeyDer, encoding, pkcs1.hashSuite, message, signature));
93
- return;
94
- }
95
- const pss = pssSuite(algorithm);
96
- if (pss !== undefined) {
97
- readVoid(provider.rsaVerifyPss(publicKeyDer, encoding, pss.messageHashSuite, pss.mgf1HashSuite, pss.saltLength, message, signature));
98
- return;
99
- }
100
- throw new ReallyMeCryptoError("unsupported-algorithm");
106
+ verifyWithProvider(requireReallyMeWasmProvider(), algorithm, signature, message, publicKeyDer, publicKeyEncoding);
101
107
  },
108
+ verifyWithProvider,
102
109
  };
package/dist/slhDsa.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { ReallyMeSignatureAlgorithm } from "./algorithms.js";
2
+ import type { ReallyMeWasmProvider } from "./wasmProvider.js";
2
3
  export declare const SLH_DSA_SHA2_128S_PUBLIC_KEY_LENGTH = 32;
3
4
  export declare const SLH_DSA_SHA2_128S_SECRET_KEY_LENGTH = 64;
4
5
  export declare const SLH_DSA_SHA2_128S_SIGNATURE_LENGTH = 7856;
@@ -9,7 +10,11 @@ export type ReallyMeSlhDsaKeyPair = Readonly<{
9
10
  }>;
10
11
  export declare const ReallyMeSlhDsa: {
11
12
  readonly generateKeyPair: (algorithm: ReallyMeSignatureAlgorithm) => ReallyMeSlhDsaKeyPair;
13
+ readonly generateKeyPairWithProvider: (provider: ReallyMeWasmProvider, algorithm: ReallyMeSignatureAlgorithm) => ReallyMeSlhDsaKeyPair;
12
14
  readonly sign: (algorithm: ReallyMeSignatureAlgorithm, message: Uint8Array, secretKey: Uint8Array) => Uint8Array;
15
+ readonly signWithProvider: (provider: ReallyMeWasmProvider, algorithm: ReallyMeSignatureAlgorithm, message: Uint8Array, secretKey: Uint8Array) => Uint8Array;
13
16
  readonly verify: (algorithm: ReallyMeSignatureAlgorithm, signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array) => void;
17
+ readonly verifyWithProvider: (provider: ReallyMeWasmProvider, algorithm: ReallyMeSignatureAlgorithm, signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array) => void;
14
18
  };
15
19
  export declare const deriveSlhDsaSha2128sKeypairForTest: (skSeed: Uint8Array, skPrf: Uint8Array, pkSeed: Uint8Array) => ReallyMeSlhDsaKeyPair;
20
+ export declare const deriveSlhDsaSha2128sKeypairWithProviderForTest: (provider: ReallyMeWasmProvider, skSeed: Uint8Array, skPrf: Uint8Array, pkSeed: Uint8Array) => ReallyMeSlhDsaKeyPair;
package/dist/slhDsa.js CHANGED
@@ -2,7 +2,7 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
- import { ensureBytes, readByteArrayProperty } from "./validateBytes.js";
5
+ import { ensureByteArrayAtMost, ensureBytes, ensureIndependentByteArray, MAX_CRYPTO_INPUT_LENGTH, readIndependentByteArrayProperty, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
7
7
  export const SLH_DSA_SHA2_128S_PUBLIC_KEY_LENGTH = 32;
8
8
  export const SLH_DSA_SHA2_128S_SECRET_KEY_LENGTH = 64;
@@ -13,15 +13,21 @@ const assertSlhDsa = (algorithm) => {
13
13
  throw new ReallyMeCryptoError("unsupported-algorithm");
14
14
  }
15
15
  };
16
- const readKeyPair = (value) => ({
17
- publicKey: readByteArrayProperty(value, "publicKey", SLH_DSA_SHA2_128S_PUBLIC_KEY_LENGTH),
18
- secretKey: readByteArrayProperty(value, "secretKey", SLH_DSA_SHA2_128S_SECRET_KEY_LENGTH),
19
- });
20
- const readSignature = (value) => {
16
+ const readKeyPair = (value, inputs = []) => {
17
+ const publicKey = readIndependentByteArrayProperty(value, "publicKey", SLH_DSA_SHA2_128S_PUBLIC_KEY_LENGTH, inputs);
18
+ const secretKey = readIndependentByteArrayProperty(value, "secretKey", SLH_DSA_SHA2_128S_SECRET_KEY_LENGTH, [...inputs, publicKey]);
19
+ return { publicKey, secretKey };
20
+ };
21
+ const readSignature = (value, inputs) => {
21
22
  if (!(value instanceof Uint8Array)) {
22
23
  throw new ReallyMeCryptoError("provider-failure");
23
24
  }
24
- ensureBytes(value, SLH_DSA_SHA2_128S_SIGNATURE_LENGTH);
25
+ // Signature bytes are public, but their shape and ownership are provider
26
+ // postconditions rather than caller validation failures.
27
+ ensureIndependentByteArray(value, inputs);
28
+ if (value.length !== SLH_DSA_SHA2_128S_SIGNATURE_LENGTH) {
29
+ throw new ReallyMeCryptoError("provider-failure");
30
+ }
25
31
  return value;
26
32
  };
27
33
  const readVoid = (value) => {
@@ -34,21 +40,46 @@ export const ReallyMeSlhDsa = {
34
40
  assertSlhDsa(algorithm);
35
41
  return readKeyPair(requireReallyMeWasmProvider().slhDsaSha2128sGenerateKeypair());
36
42
  },
43
+ generateKeyPairWithProvider(provider, algorithm) {
44
+ assertSlhDsa(algorithm);
45
+ return readKeyPair(provider.slhDsaSha2128sGenerateKeypair());
46
+ },
37
47
  sign(algorithm, message, secretKey) {
38
48
  assertSlhDsa(algorithm);
49
+ ensureByteArrayAtMost(message, MAX_CRYPTO_INPUT_LENGTH);
50
+ ensureBytes(secretKey, SLH_DSA_SHA2_128S_SECRET_KEY_LENGTH);
51
+ return readSignature(requireReallyMeWasmProvider().slhDsaSha2128sSign(secretKey, message), [secretKey, message]);
52
+ },
53
+ signWithProvider(provider, algorithm, message, secretKey) {
54
+ assertSlhDsa(algorithm);
55
+ ensureByteArrayAtMost(message, MAX_CRYPTO_INPUT_LENGTH);
39
56
  ensureBytes(secretKey, SLH_DSA_SHA2_128S_SECRET_KEY_LENGTH);
40
- return readSignature(requireReallyMeWasmProvider().slhDsaSha2128sSign(secretKey, message));
57
+ return readSignature(provider.slhDsaSha2128sSign(secretKey, message), [secretKey, message]);
41
58
  },
42
59
  verify(algorithm, signature, message, publicKey) {
43
60
  assertSlhDsa(algorithm);
61
+ ensureByteArrayAtMost(message, MAX_CRYPTO_INPUT_LENGTH);
44
62
  ensureBytes(publicKey, SLH_DSA_SHA2_128S_PUBLIC_KEY_LENGTH);
45
63
  ensureBytes(signature, SLH_DSA_SHA2_128S_SIGNATURE_LENGTH);
46
64
  readVoid(requireReallyMeWasmProvider().slhDsaSha2128sVerify(publicKey, message, signature));
47
65
  },
66
+ verifyWithProvider(provider, algorithm, signature, message, publicKey) {
67
+ assertSlhDsa(algorithm);
68
+ ensureByteArrayAtMost(message, MAX_CRYPTO_INPUT_LENGTH);
69
+ ensureBytes(publicKey, SLH_DSA_SHA2_128S_PUBLIC_KEY_LENGTH);
70
+ ensureBytes(signature, SLH_DSA_SHA2_128S_SIGNATURE_LENGTH);
71
+ readVoid(provider.slhDsaSha2128sVerify(publicKey, message, signature));
72
+ },
48
73
  };
49
74
  export const deriveSlhDsaSha2128sKeypairForTest = (skSeed, skPrf, pkSeed) => {
50
75
  ensureBytes(skSeed, SLH_DSA_SHA2_128S_KEYGEN_SEED_LENGTH);
51
76
  ensureBytes(skPrf, SLH_DSA_SHA2_128S_KEYGEN_SEED_LENGTH);
52
77
  ensureBytes(pkSeed, SLH_DSA_SHA2_128S_KEYGEN_SEED_LENGTH);
53
- return readKeyPair(requireReallyMeWasmProvider().slhDsaSha2128sDeriveKeypair(skSeed, skPrf, pkSeed));
78
+ return readKeyPair(requireReallyMeWasmProvider().slhDsaSha2128sDeriveKeypair(skSeed, skPrf, pkSeed), [skSeed, skPrf, pkSeed]);
79
+ };
80
+ export const deriveSlhDsaSha2128sKeypairWithProviderForTest = (provider, skSeed, skPrf, pkSeed) => {
81
+ ensureBytes(skSeed, SLH_DSA_SHA2_128S_KEYGEN_SEED_LENGTH);
82
+ ensureBytes(skPrf, SLH_DSA_SHA2_128S_KEYGEN_SEED_LENGTH);
83
+ ensureBytes(pkSeed, SLH_DSA_SHA2_128S_KEYGEN_SEED_LENGTH);
84
+ return readKeyPair(provider.slhDsaSha2128sDeriveKeypair(skSeed, skPrf, pkSeed), [skSeed, skPrf, pkSeed]);
54
85
  };
@@ -1,2 +1,8 @@
1
+ export declare const MAX_CRYPTO_INPUT_LENGTH = 1048576;
2
+ export declare const ensureByteArray: (value: Uint8Array) => void;
3
+ export declare const ensureByteArrayAtMost: (value: Uint8Array, maximumLength: number) => void;
1
4
  export declare const ensureBytes: (value: Uint8Array, expectedLength: number) => void;
2
- export declare const readByteArrayProperty: (value: unknown, propertyName: string, expectedLength: number) => Uint8Array;
5
+ export declare const byteArraysOverlap: (left: Uint8Array, right: Uint8Array) => boolean;
6
+ export declare const ensureIndependentByteArray: (value: Uint8Array, disallowedViews: ReadonlyArray<Uint8Array>) => void;
7
+ export declare const readIndependentByteArrayProperty: (value: unknown, propertyName: string, expectedLength: number, disallowedViews: ReadonlyArray<Uint8Array>) => Uint8Array;
8
+ export declare const readIndependentProviderBytes: (value: unknown, expectedLength: number, disallowedViews: ReadonlyArray<Uint8Array>) => Uint8Array;
@@ -2,19 +2,79 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
+ // Match the structured operation boundary so direct primitive facades cannot
6
+ // ask a provider to copy or allocate an attacker-controlled unbounded buffer.
7
+ export const MAX_CRYPTO_INPUT_LENGTH = 1_048_576;
8
+ export const ensureByteArray = (value) => {
9
+ if (!(value instanceof Uint8Array)) {
10
+ throw new ReallyMeCryptoError("invalid-input");
11
+ }
12
+ };
13
+ export const ensureByteArrayAtMost = (value, maximumLength) => {
14
+ ensureByteArray(value);
15
+ if (value.length > maximumLength) {
16
+ throw new ReallyMeCryptoError("invalid-input");
17
+ }
18
+ };
5
19
  export const ensureBytes = (value, expectedLength) => {
20
+ ensureByteArray(value);
6
21
  if (value.length !== expectedLength) {
7
22
  throw new ReallyMeCryptoError("invalid-input");
8
23
  }
9
24
  };
10
- export const readByteArrayProperty = (value, propertyName, expectedLength) => {
25
+ export const byteArraysOverlap = (left, right) => {
26
+ if (left.buffer !== right.buffer) {
27
+ return false;
28
+ }
29
+ const leftEnd = left.byteOffset + left.byteLength;
30
+ const rightEnd = right.byteOffset + right.byteLength;
31
+ return left.byteOffset < rightEnd && right.byteOffset < leftEnd;
32
+ };
33
+ export const ensureIndependentByteArray = (value, disallowedViews) => {
34
+ // A disjoint view into the same ArrayBuffer is still not independently
35
+ // owned: transferring or detaching the caller's buffer would invalidate the
36
+ // provider output too. Provider results must own separate backing storage.
37
+ if (disallowedViews.some((view) => value.buffer === view.buffer)) {
38
+ throw new ReallyMeCryptoError("provider-failure");
39
+ }
40
+ };
41
+ const readProviderByteArrayProperty = (value, propertyName) => {
11
42
  if (typeof value !== "object" || value === null) {
12
43
  throw new ReallyMeCryptoError("provider-failure");
13
44
  }
14
- const property = Reflect.get(value, propertyName);
45
+ let property;
46
+ try {
47
+ property = Reflect.get(value, propertyName);
48
+ }
49
+ catch (_error) {
50
+ throw new ReallyMeCryptoError("provider-failure");
51
+ }
15
52
  if (!(property instanceof Uint8Array)) {
16
53
  throw new ReallyMeCryptoError("provider-failure");
17
54
  }
18
- ensureBytes(property, expectedLength);
19
55
  return property;
20
56
  };
57
+ export const readIndependentByteArrayProperty = (value, propertyName, expectedLength, disallowedViews) => {
58
+ const property = readProviderByteArrayProperty(value, propertyName);
59
+ // Check ownership before cleanup so a malformed provider cannot make the
60
+ // validator erase a caller-owned input view.
61
+ ensureIndependentByteArray(property, disallowedViews);
62
+ if (property.length !== expectedLength) {
63
+ property.fill(0);
64
+ throw new ReallyMeCryptoError("provider-failure");
65
+ }
66
+ return property;
67
+ };
68
+ export const readIndependentProviderBytes = (value, expectedLength, disallowedViews) => {
69
+ if (!(value instanceof Uint8Array)) {
70
+ throw new ReallyMeCryptoError("provider-failure");
71
+ }
72
+ // Provider-owned secret outputs are cleared on malformed length, but only
73
+ // after proving the provider did not hand back a caller-owned buffer.
74
+ ensureIndependentByteArray(value, disallowedViews);
75
+ if (value.length !== expectedLength) {
76
+ value.fill(0);
77
+ throw new ReallyMeCryptoError("provider-failure");
78
+ }
79
+ return value;
80
+ };