@matter/general 0.16.0-alpha.0-20251111-11cc8c3bd → 0.16.0-alpha.0-20251112-dba1973d5

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 (62) hide show
  1. package/dist/cjs/codec/DerCodec.d.ts +6 -1
  2. package/dist/cjs/codec/DerCodec.d.ts.map +1 -1
  3. package/dist/cjs/codec/DerCodec.js +13 -2
  4. package/dist/cjs/codec/DerCodec.js.map +1 -1
  5. package/dist/cjs/crypto/Crypto.d.ts +3 -3
  6. package/dist/cjs/crypto/Crypto.d.ts.map +1 -1
  7. package/dist/cjs/crypto/Crypto.js.map +1 -1
  8. package/dist/cjs/crypto/CryptoError.d.ts +5 -0
  9. package/dist/cjs/crypto/CryptoError.d.ts.map +1 -1
  10. package/dist/cjs/crypto/CryptoError.js +4 -1
  11. package/dist/cjs/crypto/CryptoError.js.map +1 -1
  12. package/dist/cjs/crypto/EcdsaSignature.d.ts +43 -0
  13. package/dist/cjs/crypto/EcdsaSignature.d.ts.map +1 -0
  14. package/dist/cjs/crypto/EcdsaSignature.js +74 -0
  15. package/dist/cjs/crypto/EcdsaSignature.js.map +6 -0
  16. package/dist/cjs/crypto/NodeJsStyleCrypto.d.ts +4 -3
  17. package/dist/cjs/crypto/NodeJsStyleCrypto.d.ts.map +1 -1
  18. package/dist/cjs/crypto/NodeJsStyleCrypto.js +14 -11
  19. package/dist/cjs/crypto/NodeJsStyleCrypto.js.map +1 -1
  20. package/dist/cjs/crypto/StandardCrypto.d.ts +4 -3
  21. package/dist/cjs/crypto/StandardCrypto.d.ts.map +1 -1
  22. package/dist/cjs/crypto/StandardCrypto.js +5 -21
  23. package/dist/cjs/crypto/StandardCrypto.js.map +1 -1
  24. package/dist/cjs/crypto/index.d.ts +1 -0
  25. package/dist/cjs/crypto/index.d.ts.map +1 -1
  26. package/dist/cjs/crypto/index.js +1 -0
  27. package/dist/cjs/crypto/index.js.map +1 -1
  28. package/dist/esm/codec/DerCodec.d.ts +6 -1
  29. package/dist/esm/codec/DerCodec.d.ts.map +1 -1
  30. package/dist/esm/codec/DerCodec.js +13 -2
  31. package/dist/esm/codec/DerCodec.js.map +1 -1
  32. package/dist/esm/crypto/Crypto.d.ts +3 -3
  33. package/dist/esm/crypto/Crypto.d.ts.map +1 -1
  34. package/dist/esm/crypto/Crypto.js.map +1 -1
  35. package/dist/esm/crypto/CryptoError.d.ts +5 -0
  36. package/dist/esm/crypto/CryptoError.d.ts.map +1 -1
  37. package/dist/esm/crypto/CryptoError.js +4 -1
  38. package/dist/esm/crypto/CryptoError.js.map +1 -1
  39. package/dist/esm/crypto/EcdsaSignature.d.ts +43 -0
  40. package/dist/esm/crypto/EcdsaSignature.d.ts.map +1 -0
  41. package/dist/esm/crypto/EcdsaSignature.js +54 -0
  42. package/dist/esm/crypto/EcdsaSignature.js.map +6 -0
  43. package/dist/esm/crypto/NodeJsStyleCrypto.d.ts +4 -3
  44. package/dist/esm/crypto/NodeJsStyleCrypto.d.ts.map +1 -1
  45. package/dist/esm/crypto/NodeJsStyleCrypto.js +14 -11
  46. package/dist/esm/crypto/NodeJsStyleCrypto.js.map +1 -1
  47. package/dist/esm/crypto/StandardCrypto.d.ts +4 -3
  48. package/dist/esm/crypto/StandardCrypto.d.ts.map +1 -1
  49. package/dist/esm/crypto/StandardCrypto.js +5 -21
  50. package/dist/esm/crypto/StandardCrypto.js.map +1 -1
  51. package/dist/esm/crypto/index.d.ts +1 -0
  52. package/dist/esm/crypto/index.d.ts.map +1 -1
  53. package/dist/esm/crypto/index.js +1 -0
  54. package/dist/esm/crypto/index.js.map +1 -1
  55. package/package.json +2 -2
  56. package/src/codec/DerCodec.ts +19 -3
  57. package/src/crypto/Crypto.ts +3 -12
  58. package/src/crypto/CryptoError.ts +5 -0
  59. package/src/crypto/EcdsaSignature.ts +83 -0
  60. package/src/crypto/NodeJsStyleCrypto.ts +14 -12
  61. package/src/crypto/StandardCrypto.ts +6 -28
  62. package/src/crypto/index.ts +1 -0
@@ -13,6 +13,7 @@ import * as mod from "@noble/curves/abstract/modular.js";
13
13
  import { p256 } from "@noble/curves/nist.js";
14
14
  import * as utils from "@noble/curves/utils.js";
15
15
  import { Entropy } from "../util/Entropy.js";
16
+ import { EcdsaSignature } from "./EcdsaSignature.js";
16
17
  import type { PrivateKey, PublicKey } from "./Key.js";
17
18
 
18
19
  export const ec = {
@@ -27,7 +28,6 @@ export const CRYPTO_EC_CURVE = "prime256v1";
27
28
  export const CRYPTO_EC_KEY_BYTES = 32;
28
29
  export const CRYPTO_AUTH_TAG_LENGTH = 16;
29
30
  export const CRYPTO_SYMMETRIC_KEY_LENGTH = 16;
30
- export type CryptoDsaEncoding = "ieee-p1363" | "der";
31
31
 
32
32
  const logger = Logger.get("Crypto");
33
33
 
@@ -83,21 +83,12 @@ export abstract class Crypto extends Entropy {
83
83
  /**
84
84
  * Create an ECDSA signature.
85
85
  */
86
- abstract signEcdsa(
87
- privateKey: JsonWebKey,
88
- data: Bytes | Bytes[],
89
- dsaEncoding?: CryptoDsaEncoding,
90
- ): MaybePromise<Bytes>;
86
+ abstract signEcdsa(privateKey: JsonWebKey, data: Bytes | Bytes[]): MaybePromise<EcdsaSignature>;
91
87
 
92
88
  /**
93
89
  * Authenticate an ECDSA signature.
94
90
  */
95
- abstract verifyEcdsa(
96
- publicKey: JsonWebKey,
97
- data: Bytes,
98
- signature: Bytes,
99
- dsaEncoding?: CryptoDsaEncoding,
100
- ): MaybePromise<void>;
91
+ abstract verifyEcdsa(publicKey: JsonWebKey, data: Bytes, signature: EcdsaSignature): MaybePromise<void>;
101
92
 
102
93
  /**
103
94
  * Create a general-purpose EC key.
@@ -30,3 +30,8 @@ export class CryptoDecryptError extends CryptoError {}
30
30
  * Thrown when cryptographic key parameters are invalid.
31
31
  */
32
32
  export class KeyInputError extends CryptoInputError {}
33
+
34
+ /**
35
+ * Thrown when verification fails because of an invalid signature format.
36
+ */
37
+ export class SignatureEncodingError extends CryptoVerifyError {}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022-2025 Matter.js Authors
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { DerCodec, DerError, DerRawUint } from "#codec/DerCodec.js";
8
+ import { Bytes } from "#util/Bytes.js";
9
+ import { SignatureEncodingError } from "./CryptoError.js";
10
+
11
+ /**
12
+ * An ECDSA signature.
13
+ *
14
+ * Input and output may be IEEE-P1363 or DER encoded. Matter helpfully mixes and matches so we validate input to ensure
15
+ * the correct encoding is specified. Extraction to bytes must explicitly use {@link bytes} or {@link der} to specify
16
+ * the desired format.
17
+ *
18
+ * Currently we only support 256-bit curves.
19
+ */
20
+ export class EcdsaSignature {
21
+ #bytes: Bytes;
22
+
23
+ constructor(bytes: Bytes, encoding = "ieee-p1363") {
24
+ if (encoding === "der") {
25
+ try {
26
+ const decoded = DerCodec.decode(bytes);
27
+
28
+ const r = DerCodec.decodeBigUint(decoded?._elements?.[0], 32);
29
+ const s = DerCodec.decodeBigUint(decoded?._elements?.[1], 32);
30
+
31
+ this.#bytes = Bytes.concat(r, s);
32
+ } catch (cause) {
33
+ DerError.accept(cause);
34
+
35
+ throw new SignatureEncodingError("Could not decode DER signature", { cause });
36
+ }
37
+ } else {
38
+ // Change this if/when we support more curves
39
+ if (bytes.byteLength !== 64) {
40
+ throw new SignatureEncodingError("Invalid IEEE P1364 signature length");
41
+ }
42
+ this.#bytes = bytes;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Access signature in IEEE P1363 format.
48
+ */
49
+ get bytes() {
50
+ return this.#bytes;
51
+ }
52
+
53
+ /**
54
+ * Access signature in DER format.
55
+ */
56
+ get der() {
57
+ const bytes = Bytes.of(this.#bytes);
58
+ const bytesPerComponent = bytes.length / 2;
59
+
60
+ return DerCodec.encode({
61
+ r: DerRawUint(bytes.slice(0, bytesPerComponent)),
62
+ s: DerRawUint(bytes.slice(bytesPerComponent)),
63
+ });
64
+ }
65
+ }
66
+
67
+ export namespace EcdsaSignature {
68
+ /**
69
+ * IEEE P1363 encoding.
70
+ *
71
+ * This is a simple concatenation of the raw R and S elements
72
+ */
73
+ export const IEEE_P1363 = "ieee-p1363";
74
+
75
+ /**
76
+ * DER encoding.
77
+ *
78
+ * This encodes R and S elements in a sequence of separate integers.
79
+ */
80
+ export const DER = "der";
81
+
82
+ export type Encoding = typeof IEEE_P1363 | typeof DER;
83
+ }
@@ -17,9 +17,9 @@ import {
17
17
  CRYPTO_ENCRYPT_ALGORITHM,
18
18
  CRYPTO_HASH_ALGORITHM,
19
19
  CRYPTO_SYMMETRIC_KEY_LENGTH,
20
- CryptoDsaEncoding,
21
20
  } from "./Crypto.js";
22
21
  import { CryptoDecryptError, CryptoVerifyError } from "./CryptoError.js";
22
+ import { EcdsaSignature } from "./EcdsaSignature.js";
23
23
  import { PrivateKey, PublicKey } from "./Key.js";
24
24
 
25
25
  // Note that this is a type-only import, not a runtime dependency.
@@ -179,24 +179,26 @@ export class NodeJsStyleCrypto extends Crypto {
179
179
  return Bytes.of(hmac.digest());
180
180
  }
181
181
 
182
- signEcdsa(privateKey: JsonWebKey, data: Bytes | Bytes[], dsaEncoding: CryptoDsaEncoding = "ieee-p1363"): Bytes {
182
+ signEcdsa(privateKey: JsonWebKey, data: Bytes | Bytes[]) {
183
183
  const signer = this.#crypto.createSign(CRYPTO_HASH_ALGORITHM);
184
184
  if (Array.isArray(data)) {
185
185
  data.forEach(chunk => signer.update(Bytes.of(chunk)));
186
186
  } else {
187
187
  signer.update(Bytes.of(data));
188
188
  }
189
- return Bytes.of(
190
- signer.sign({
191
- key: privateKey as any,
192
- format: "jwk",
193
- type: "pkcs8",
194
- dsaEncoding,
195
- }),
189
+ return new EcdsaSignature(
190
+ Bytes.of(
191
+ signer.sign({
192
+ key: privateKey as any,
193
+ format: "jwk",
194
+ type: "pkcs8",
195
+ dsaEncoding: "ieee-p1363",
196
+ }),
197
+ ),
196
198
  );
197
199
  }
198
200
 
199
- verifyEcdsa(publicKey: JsonWebKey, data: Bytes, signature: Bytes, dsaEncoding: CryptoDsaEncoding = "ieee-p1363") {
201
+ verifyEcdsa(publicKey: JsonWebKey, data: Bytes, signature: EcdsaSignature) {
200
202
  const verifier = this.#crypto.createVerify(CRYPTO_HASH_ALGORITHM);
201
203
  verifier.update(Bytes.of(data));
202
204
  const success = verifier.verify(
@@ -204,9 +206,9 @@ export class NodeJsStyleCrypto extends Crypto {
204
206
  key: publicKey as any,
205
207
  format: "jwk",
206
208
  type: "spki",
207
- dsaEncoding,
209
+ dsaEncoding: "ieee-p1363",
208
210
  },
209
- Bytes.of(signature),
211
+ Bytes.of(signature.bytes),
210
212
  );
211
213
  if (!success) throw new CryptoVerifyError("Signature verification failed");
212
214
  }
@@ -5,7 +5,6 @@
5
5
  * SPDX-License-Identifier: Apache-2.0
6
6
  */
7
7
 
8
- import { DerBigUint, DerCodec, DerError } from "#codec/DerCodec.js";
9
8
  import { Environment } from "#environment/Environment.js";
10
9
  import { ImplementationError, NotImplementedError } from "#MatterError.js";
11
10
  import { Bytes } from "#util/Bytes.js";
@@ -13,8 +12,9 @@ import { Entropy } from "#util/Entropy.js";
13
12
  import { MaybePromise } from "#util/Promises.js";
14
13
  import { describeList } from "#util/String.js";
15
14
  import { Ccm } from "./aes/Ccm.js";
16
- import { Crypto, CRYPTO_SYMMETRIC_KEY_LENGTH, CryptoDsaEncoding } from "./Crypto.js";
15
+ import { Crypto, CRYPTO_SYMMETRIC_KEY_LENGTH } from "./Crypto.js";
17
16
  import { CryptoVerifyError, KeyInputError } from "./CryptoError.js";
17
+ import { EcdsaSignature } from "./EcdsaSignature.js";
18
18
  import { CurveType, Key, KeyType, PrivateKey, PublicKey } from "./Key.js";
19
19
  import { WebCrypto } from "./WebCrypto.js";
20
20
 
@@ -146,7 +146,7 @@ export class StandardCrypto extends Crypto {
146
146
  );
147
147
  }
148
148
 
149
- async signEcdsa(key: JsonWebKey, data: Bytes | Bytes[], dsaEncoding?: CryptoDsaEncoding) {
149
+ async signEcdsa(key: JsonWebKey, data: Bytes | Bytes[]) {
150
150
  if (Array.isArray(data)) {
151
151
  data = Bytes.concat(...data);
152
152
  }
@@ -167,40 +167,18 @@ export class StandardCrypto extends Crypto {
167
167
 
168
168
  const ieeeP1363 = Bytes.of(await this.#subtle.sign(SIGNATURE_ALGORITHM, subtleKey, Bytes.exclusive(data)));
169
169
 
170
- if (dsaEncoding !== "der") return ieeeP1363;
171
-
172
- const bytesPerComponent = ieeeP1363.byteLength / 2;
173
-
174
- return DerCodec.encode({
175
- r: DerBigUint(ieeeP1363.slice(0, bytesPerComponent)),
176
- s: DerBigUint(ieeeP1363.slice(bytesPerComponent)),
177
- });
170
+ return new EcdsaSignature(ieeeP1363);
178
171
  }
179
172
 
180
- async verifyEcdsa(key: JsonWebKey, data: Bytes, signature: Bytes, dsaEncoding?: CryptoDsaEncoding) {
173
+ async verifyEcdsa(key: JsonWebKey, data: Bytes, signature: EcdsaSignature) {
181
174
  const { crv, kty, x, y } = key;
182
175
  key = { crv, kty, x, y };
183
176
  const subtleKey = await this.importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["verify"]);
184
177
 
185
- if (dsaEncoding === "der") {
186
- try {
187
- const decoded = DerCodec.decode(signature);
188
-
189
- const r = DerCodec.decodeBigUint(decoded?._elements?.[0], 32);
190
- const s = DerCodec.decodeBigUint(decoded?._elements?.[1], 32);
191
-
192
- signature = Bytes.concat(r, s);
193
- } catch (cause) {
194
- DerError.accept(cause);
195
-
196
- throw new CryptoVerifyError("Invalid DER signature", { cause });
197
- }
198
- }
199
-
200
178
  const verified = await this.#subtle.verify(
201
179
  SIGNATURE_ALGORITHM,
202
180
  subtleKey,
203
- Bytes.exclusive(signature),
181
+ Bytes.exclusive(signature.bytes),
204
182
  Bytes.exclusive(data),
205
183
  );
206
184
 
@@ -7,6 +7,7 @@
7
7
  export * from "./Crypto.js";
8
8
  export * from "./CryptoConstants.js";
9
9
  export * from "./CryptoError.js";
10
+ export * from "./EcdsaSignature.js";
10
11
  export * from "./Key.js";
11
12
  export * from "./MockCrypto.js";
12
13
  export * from "./NodeJsStyleCrypto.js";