@matter/general 0.15.0 → 0.15.1-alpha.0-20250630-daa5888a0
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.
- package/dist/cjs/crypto/StandardCrypto.d.ts +5 -3
- package/dist/cjs/crypto/StandardCrypto.d.ts.map +1 -1
- package/dist/cjs/crypto/StandardCrypto.js +36 -24
- package/dist/cjs/crypto/StandardCrypto.js.map +1 -1
- package/dist/esm/crypto/StandardCrypto.d.ts +5 -3
- package/dist/esm/crypto/StandardCrypto.d.ts.map +1 -1
- package/dist/esm/crypto/StandardCrypto.js +36 -24
- package/dist/esm/crypto/StandardCrypto.js.map +1 -1
- package/package.json +2 -2
- package/src/crypto/StandardCrypto.ts +59 -44
|
@@ -7,16 +7,18 @@
|
|
|
7
7
|
import { Crypto, CryptoDsaEncoding } from "./Crypto.js";
|
|
8
8
|
import { PrivateKey, PublicKey } from "./Key.js";
|
|
9
9
|
/**
|
|
10
|
-
* A {@link Crypto} implementation
|
|
10
|
+
* A {@link Crypto} implementation that uses only JS standards.
|
|
11
11
|
*
|
|
12
12
|
* WARNING: This code is unaudited. Use a trusted native alternative where available.
|
|
13
13
|
*
|
|
14
14
|
* This module is mostly based on {@link crypto.subtle}. This should be a reliable native implementation. However,
|
|
15
|
-
* Web Crypto doesn't support AES-CCM required by Matter so
|
|
16
|
-
*
|
|
15
|
+
* Web Crypto doesn't support AES-CCM required by Matter so we use a JS implementation for that. See relevant warnings
|
|
16
|
+
* in the "aes" subdirectory.
|
|
17
17
|
*/
|
|
18
18
|
export declare class StandardCrypto extends Crypto {
|
|
19
|
+
#private;
|
|
19
20
|
implementationName: string;
|
|
21
|
+
constructor(subtle?: SubtleCrypto);
|
|
20
22
|
static provider(): StandardCrypto;
|
|
21
23
|
randomBytes(length: number): Uint8Array;
|
|
22
24
|
encrypt(key: Uint8Array, data: Uint8Array, nonce: Uint8Array, associatedData?: Uint8Array): Uint8Array<ArrayBufferLike>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StandardCrypto.d.ts","sourceRoot":"","sources":["../../../src/crypto/StandardCrypto.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"StandardCrypto.d.ts","sourceRoot":"","sources":["../../../src/crypto/StandardCrypto.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAAE,MAAM,EAA+B,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErF,OAAO,EAA2B,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAQ1E;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,MAAM;;IACtC,kBAAkB,SAAQ;gBAGd,MAAM,GAAE,YAA6B;IAYjD,MAAM,CAAC,QAAQ;IAIf,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU;IAMvC,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,UAAU;IAKzF,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,UAAU;IAKnF,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,EAAE;IAO/C,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAe1F,aAAa,CACf,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,MAAoC;IAgB1C,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU;IAK7C,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,EAAE,WAAW,CAAC,EAAE,iBAAiB;IA+B3F,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,iBAAiB;IA2BrG,aAAa;IA2Bb,gBAAgB,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS;CAyD7D"}
|
|
@@ -23,6 +23,7 @@ __export(StandardCrypto_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(StandardCrypto_exports);
|
|
24
24
|
var import_DerCodec = require("#codec/DerCodec.js");
|
|
25
25
|
var import_Environment = require("#environment/Environment.js");
|
|
26
|
+
var import_MatterError = require("#MatterError.js");
|
|
26
27
|
var import_Bytes = require("#util/Bytes.js");
|
|
27
28
|
var import_Ccm = require("./aes/Ccm.js");
|
|
28
29
|
var import_Crypto = require("./Crypto.js");
|
|
@@ -34,7 +35,6 @@ var import_Key = require("./Key.js");
|
|
|
34
35
|
* Portions copyright 2022-2023 Project CHIP Authors
|
|
35
36
|
* SPDX-License-Identifier: Apache-2.0
|
|
36
37
|
*/
|
|
37
|
-
const subtle = globalThis.crypto.subtle;
|
|
38
38
|
const SIGNATURE_ALGORITHM = {
|
|
39
39
|
name: "ECDSA",
|
|
40
40
|
namedCurve: "P-256",
|
|
@@ -42,6 +42,16 @@ const SIGNATURE_ALGORITHM = {
|
|
|
42
42
|
};
|
|
43
43
|
class StandardCrypto extends import_Crypto.Crypto {
|
|
44
44
|
implementationName = "JS";
|
|
45
|
+
#subtle;
|
|
46
|
+
constructor(subtle = crypto?.subtle) {
|
|
47
|
+
if (subtle === void 0) {
|
|
48
|
+
throw new import_MatterError.ImplementationError(
|
|
49
|
+
"You cannot instantiate StandardCrypto in this runtime because crypto.subtle is not present"
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
super();
|
|
53
|
+
this.#subtle = subtle;
|
|
54
|
+
}
|
|
45
55
|
static provider() {
|
|
46
56
|
return new StandardCrypto();
|
|
47
57
|
}
|
|
@@ -62,11 +72,11 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
62
72
|
if (Array.isArray(buffer)) {
|
|
63
73
|
buffer = import_Bytes.Bytes.concat(...buffer);
|
|
64
74
|
}
|
|
65
|
-
return new Uint8Array(await subtle.digest("SHA-256", buffer));
|
|
75
|
+
return new Uint8Array(await this.#subtle.digest("SHA-256", buffer));
|
|
66
76
|
}
|
|
67
77
|
async createPbkdf2Key(secret, salt, iteration, keyLength) {
|
|
68
|
-
const key = await importKey("raw", secret, "PBKDF2", false, ["deriveBits"]);
|
|
69
|
-
const bits = await subtle.deriveBits(
|
|
78
|
+
const key = await this.#importKey("raw", secret, "PBKDF2", false, ["deriveBits"]);
|
|
79
|
+
const bits = await this.#subtle.deriveBits(
|
|
70
80
|
{
|
|
71
81
|
name: "PBKDF2",
|
|
72
82
|
hash: "SHA-256",
|
|
@@ -79,8 +89,8 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
79
89
|
return new Uint8Array(bits);
|
|
80
90
|
}
|
|
81
91
|
async createHkdfKey(secret, salt, info, length = import_Crypto.CRYPTO_SYMMETRIC_KEY_LENGTH) {
|
|
82
|
-
const key = await importKey("raw", secret, "HKDF", false, ["deriveBits"]);
|
|
83
|
-
const bits = await subtle.deriveBits(
|
|
92
|
+
const key = await this.#importKey("raw", secret, "HKDF", false, ["deriveBits"]);
|
|
93
|
+
const bits = await this.#subtle.deriveBits(
|
|
84
94
|
{
|
|
85
95
|
name: "HKDF",
|
|
86
96
|
hash: "SHA-256",
|
|
@@ -93,8 +103,8 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
93
103
|
return new Uint8Array(bits);
|
|
94
104
|
}
|
|
95
105
|
async signHmac(secret, data) {
|
|
96
|
-
const key = await importKey("raw", secret, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
97
|
-
return new Uint8Array(await subtle.sign("HMAC", key, data));
|
|
106
|
+
const key = await this.#importKey("raw", secret, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
107
|
+
return new Uint8Array(await this.#subtle.sign("HMAC", key, data));
|
|
98
108
|
}
|
|
99
109
|
async signEcdsa(key, data, dsaEncoding) {
|
|
100
110
|
if (Array.isArray(data)) {
|
|
@@ -111,8 +121,8 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
111
121
|
// Required by some subtle implementations to sign
|
|
112
122
|
key_ops: ["sign"]
|
|
113
123
|
};
|
|
114
|
-
const subtleKey = await importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["sign"]);
|
|
115
|
-
const ieeeP1363 = await subtle.sign(SIGNATURE_ALGORITHM, subtleKey, data);
|
|
124
|
+
const subtleKey = await this.#importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["sign"]);
|
|
125
|
+
const ieeeP1363 = await this.#subtle.sign(SIGNATURE_ALGORITHM, subtleKey, data);
|
|
116
126
|
if (dsaEncoding !== "der") return new Uint8Array(ieeeP1363);
|
|
117
127
|
const bytesPerComponent = ieeeP1363.byteLength / 2;
|
|
118
128
|
return import_DerCodec.DerCodec.encode({
|
|
@@ -123,7 +133,7 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
123
133
|
async verifyEcdsa(key, data, signature, dsaEncoding) {
|
|
124
134
|
const { crv, kty, x, y } = key;
|
|
125
135
|
key = { crv, kty, x, y };
|
|
126
|
-
const subtleKey = await importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["verify"]);
|
|
136
|
+
const subtleKey = await this.#importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["verify"]);
|
|
127
137
|
if (dsaEncoding === "der") {
|
|
128
138
|
try {
|
|
129
139
|
const decoded = import_DerCodec.DerCodec.decode(signature);
|
|
@@ -135,13 +145,13 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
135
145
|
throw new import_CryptoError.CryptoVerifyError("Invalid DER signature", { cause });
|
|
136
146
|
}
|
|
137
147
|
}
|
|
138
|
-
const verified = await subtle.verify(SIGNATURE_ALGORITHM, subtleKey, signature, data);
|
|
148
|
+
const verified = await this.#subtle.verify(SIGNATURE_ALGORITHM, subtleKey, signature, data);
|
|
139
149
|
if (!verified) {
|
|
140
150
|
throw new import_CryptoError.CryptoVerifyError("Signature verification failed");
|
|
141
151
|
}
|
|
142
152
|
}
|
|
143
153
|
async createKeyPair() {
|
|
144
|
-
const subtleKey = await subtle.generateKey(
|
|
154
|
+
const subtleKey = await this.#subtle.generateKey(
|
|
145
155
|
{
|
|
146
156
|
// We must specify either ECDH or ECDSA to get an EC key but we may use the key for either (but not for
|
|
147
157
|
// both)
|
|
@@ -152,7 +162,7 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
152
162
|
// We must also specify usage but will drop this on export
|
|
153
163
|
["deriveKey"]
|
|
154
164
|
);
|
|
155
|
-
const key = await subtle.exportKey("jwk", subtleKey.privateKey);
|
|
165
|
+
const key = await this.#subtle.exportKey("jwk", subtleKey.privateKey);
|
|
156
166
|
return (0, import_Key.Key)({
|
|
157
167
|
kty: import_Key.KeyType.EC,
|
|
158
168
|
crv: import_Key.CurveType.p256,
|
|
@@ -162,7 +172,7 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
162
172
|
});
|
|
163
173
|
}
|
|
164
174
|
async generateDhSecret(key, peerKey) {
|
|
165
|
-
const subtleKey = await importKey(
|
|
175
|
+
const subtleKey = await this.#importKey(
|
|
166
176
|
"jwk",
|
|
167
177
|
key,
|
|
168
178
|
{
|
|
@@ -172,7 +182,7 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
172
182
|
false,
|
|
173
183
|
["deriveBits"]
|
|
174
184
|
);
|
|
175
|
-
const subtlePeerKey = await importKey(
|
|
185
|
+
const subtlePeerKey = await this.#importKey(
|
|
176
186
|
"jwk",
|
|
177
187
|
peerKey,
|
|
178
188
|
{
|
|
@@ -182,7 +192,7 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
182
192
|
false,
|
|
183
193
|
[]
|
|
184
194
|
);
|
|
185
|
-
const secret = await subtle.deriveBits(
|
|
195
|
+
const secret = await this.#subtle.deriveBits(
|
|
186
196
|
{
|
|
187
197
|
name: "ECDH",
|
|
188
198
|
public: subtlePeerKey
|
|
@@ -192,13 +202,15 @@ class StandardCrypto extends import_Crypto.Crypto {
|
|
|
192
202
|
);
|
|
193
203
|
return new Uint8Array(secret);
|
|
194
204
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
205
|
+
async #importKey(...params) {
|
|
206
|
+
try {
|
|
207
|
+
return await this.#subtle.importKey(...params);
|
|
208
|
+
} catch (cause) {
|
|
209
|
+
throw new import_CryptoError.KeyInputError("Invalid key", { cause });
|
|
210
|
+
}
|
|
201
211
|
}
|
|
202
212
|
}
|
|
203
|
-
|
|
213
|
+
if (crypto?.subtle !== void 0) {
|
|
214
|
+
import_Environment.Environment.default.set(import_Crypto.Crypto, new StandardCrypto(crypto.subtle));
|
|
215
|
+
}
|
|
204
216
|
//# sourceMappingURL=StandardCrypto.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/crypto/StandardCrypto.ts"],
|
|
4
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,sBAA+C;AAC/C,yBAA4B;AAC5B,mBAAsB;AACtB,iBAAoB;AACpB,oBAAuE;AACvE,yBAAiD;AACjD,iBAA+D;
|
|
4
|
+
"mappings": "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",
|
|
5
5
|
"names": []
|
|
6
6
|
}
|
|
@@ -7,16 +7,18 @@
|
|
|
7
7
|
import { Crypto, CryptoDsaEncoding } from "./Crypto.js";
|
|
8
8
|
import { PrivateKey, PublicKey } from "./Key.js";
|
|
9
9
|
/**
|
|
10
|
-
* A {@link Crypto} implementation
|
|
10
|
+
* A {@link Crypto} implementation that uses only JS standards.
|
|
11
11
|
*
|
|
12
12
|
* WARNING: This code is unaudited. Use a trusted native alternative where available.
|
|
13
13
|
*
|
|
14
14
|
* This module is mostly based on {@link crypto.subtle}. This should be a reliable native implementation. However,
|
|
15
|
-
* Web Crypto doesn't support AES-CCM required by Matter so
|
|
16
|
-
*
|
|
15
|
+
* Web Crypto doesn't support AES-CCM required by Matter so we use a JS implementation for that. See relevant warnings
|
|
16
|
+
* in the "aes" subdirectory.
|
|
17
17
|
*/
|
|
18
18
|
export declare class StandardCrypto extends Crypto {
|
|
19
|
+
#private;
|
|
19
20
|
implementationName: string;
|
|
21
|
+
constructor(subtle?: SubtleCrypto);
|
|
20
22
|
static provider(): StandardCrypto;
|
|
21
23
|
randomBytes(length: number): Uint8Array;
|
|
22
24
|
encrypt(key: Uint8Array, data: Uint8Array, nonce: Uint8Array, associatedData?: Uint8Array): Uint8Array<ArrayBufferLike>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StandardCrypto.d.ts","sourceRoot":"","sources":["../../../src/crypto/StandardCrypto.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"StandardCrypto.d.ts","sourceRoot":"","sources":["../../../src/crypto/StandardCrypto.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAAE,MAAM,EAA+B,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErF,OAAO,EAA2B,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAQ1E;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,MAAM;;IACtC,kBAAkB,SAAQ;gBAGd,MAAM,GAAE,YAA6B;IAYjD,MAAM,CAAC,QAAQ;IAIf,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU;IAMvC,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,UAAU;IAKzF,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,UAAU;IAKnF,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,EAAE;IAO/C,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAe1F,aAAa,CACf,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,UAAU,EAChB,MAAM,GAAE,MAAoC;IAgB1C,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU;IAK7C,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,EAAE,WAAW,CAAC,EAAE,iBAAiB;IA+B3F,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,iBAAiB;IA2BrG,aAAa;IA2Bb,gBAAgB,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS;CAyD7D"}
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { DerBigUint, DerCodec, DerError } from "#codec/DerCodec.js";
|
|
8
8
|
import { Environment } from "#environment/Environment.js";
|
|
9
|
+
import { ImplementationError } from "#MatterError.js";
|
|
9
10
|
import { Bytes } from "#util/Bytes.js";
|
|
10
11
|
import { Ccm } from "./aes/Ccm.js";
|
|
11
12
|
import { Crypto, CRYPTO_SYMMETRIC_KEY_LENGTH } from "./Crypto.js";
|
|
12
13
|
import { CryptoVerifyError, KeyInputError } from "./CryptoError.js";
|
|
13
14
|
import { CurveType, Key, KeyType } from "./Key.js";
|
|
14
|
-
const subtle = globalThis.crypto.subtle;
|
|
15
15
|
const SIGNATURE_ALGORITHM = {
|
|
16
16
|
name: "ECDSA",
|
|
17
17
|
namedCurve: "P-256",
|
|
@@ -19,6 +19,16 @@ const SIGNATURE_ALGORITHM = {
|
|
|
19
19
|
};
|
|
20
20
|
class StandardCrypto extends Crypto {
|
|
21
21
|
implementationName = "JS";
|
|
22
|
+
#subtle;
|
|
23
|
+
constructor(subtle = crypto?.subtle) {
|
|
24
|
+
if (subtle === void 0) {
|
|
25
|
+
throw new ImplementationError(
|
|
26
|
+
"You cannot instantiate StandardCrypto in this runtime because crypto.subtle is not present"
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
super();
|
|
30
|
+
this.#subtle = subtle;
|
|
31
|
+
}
|
|
22
32
|
static provider() {
|
|
23
33
|
return new StandardCrypto();
|
|
24
34
|
}
|
|
@@ -39,11 +49,11 @@ class StandardCrypto extends Crypto {
|
|
|
39
49
|
if (Array.isArray(buffer)) {
|
|
40
50
|
buffer = Bytes.concat(...buffer);
|
|
41
51
|
}
|
|
42
|
-
return new Uint8Array(await subtle.digest("SHA-256", buffer));
|
|
52
|
+
return new Uint8Array(await this.#subtle.digest("SHA-256", buffer));
|
|
43
53
|
}
|
|
44
54
|
async createPbkdf2Key(secret, salt, iteration, keyLength) {
|
|
45
|
-
const key = await importKey("raw", secret, "PBKDF2", false, ["deriveBits"]);
|
|
46
|
-
const bits = await subtle.deriveBits(
|
|
55
|
+
const key = await this.#importKey("raw", secret, "PBKDF2", false, ["deriveBits"]);
|
|
56
|
+
const bits = await this.#subtle.deriveBits(
|
|
47
57
|
{
|
|
48
58
|
name: "PBKDF2",
|
|
49
59
|
hash: "SHA-256",
|
|
@@ -56,8 +66,8 @@ class StandardCrypto extends Crypto {
|
|
|
56
66
|
return new Uint8Array(bits);
|
|
57
67
|
}
|
|
58
68
|
async createHkdfKey(secret, salt, info, length = CRYPTO_SYMMETRIC_KEY_LENGTH) {
|
|
59
|
-
const key = await importKey("raw", secret, "HKDF", false, ["deriveBits"]);
|
|
60
|
-
const bits = await subtle.deriveBits(
|
|
69
|
+
const key = await this.#importKey("raw", secret, "HKDF", false, ["deriveBits"]);
|
|
70
|
+
const bits = await this.#subtle.deriveBits(
|
|
61
71
|
{
|
|
62
72
|
name: "HKDF",
|
|
63
73
|
hash: "SHA-256",
|
|
@@ -70,8 +80,8 @@ class StandardCrypto extends Crypto {
|
|
|
70
80
|
return new Uint8Array(bits);
|
|
71
81
|
}
|
|
72
82
|
async signHmac(secret, data) {
|
|
73
|
-
const key = await importKey("raw", secret, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
74
|
-
return new Uint8Array(await subtle.sign("HMAC", key, data));
|
|
83
|
+
const key = await this.#importKey("raw", secret, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
84
|
+
return new Uint8Array(await this.#subtle.sign("HMAC", key, data));
|
|
75
85
|
}
|
|
76
86
|
async signEcdsa(key, data, dsaEncoding) {
|
|
77
87
|
if (Array.isArray(data)) {
|
|
@@ -88,8 +98,8 @@ class StandardCrypto extends Crypto {
|
|
|
88
98
|
// Required by some subtle implementations to sign
|
|
89
99
|
key_ops: ["sign"]
|
|
90
100
|
};
|
|
91
|
-
const subtleKey = await importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["sign"]);
|
|
92
|
-
const ieeeP1363 = await subtle.sign(SIGNATURE_ALGORITHM, subtleKey, data);
|
|
101
|
+
const subtleKey = await this.#importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["sign"]);
|
|
102
|
+
const ieeeP1363 = await this.#subtle.sign(SIGNATURE_ALGORITHM, subtleKey, data);
|
|
93
103
|
if (dsaEncoding !== "der") return new Uint8Array(ieeeP1363);
|
|
94
104
|
const bytesPerComponent = ieeeP1363.byteLength / 2;
|
|
95
105
|
return DerCodec.encode({
|
|
@@ -100,7 +110,7 @@ class StandardCrypto extends Crypto {
|
|
|
100
110
|
async verifyEcdsa(key, data, signature, dsaEncoding) {
|
|
101
111
|
const { crv, kty, x, y } = key;
|
|
102
112
|
key = { crv, kty, x, y };
|
|
103
|
-
const subtleKey = await importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["verify"]);
|
|
113
|
+
const subtleKey = await this.#importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["verify"]);
|
|
104
114
|
if (dsaEncoding === "der") {
|
|
105
115
|
try {
|
|
106
116
|
const decoded = DerCodec.decode(signature);
|
|
@@ -112,13 +122,13 @@ class StandardCrypto extends Crypto {
|
|
|
112
122
|
throw new CryptoVerifyError("Invalid DER signature", { cause });
|
|
113
123
|
}
|
|
114
124
|
}
|
|
115
|
-
const verified = await subtle.verify(SIGNATURE_ALGORITHM, subtleKey, signature, data);
|
|
125
|
+
const verified = await this.#subtle.verify(SIGNATURE_ALGORITHM, subtleKey, signature, data);
|
|
116
126
|
if (!verified) {
|
|
117
127
|
throw new CryptoVerifyError("Signature verification failed");
|
|
118
128
|
}
|
|
119
129
|
}
|
|
120
130
|
async createKeyPair() {
|
|
121
|
-
const subtleKey = await subtle.generateKey(
|
|
131
|
+
const subtleKey = await this.#subtle.generateKey(
|
|
122
132
|
{
|
|
123
133
|
// We must specify either ECDH or ECDSA to get an EC key but we may use the key for either (but not for
|
|
124
134
|
// both)
|
|
@@ -129,7 +139,7 @@ class StandardCrypto extends Crypto {
|
|
|
129
139
|
// We must also specify usage but will drop this on export
|
|
130
140
|
["deriveKey"]
|
|
131
141
|
);
|
|
132
|
-
const key = await subtle.exportKey("jwk", subtleKey.privateKey);
|
|
142
|
+
const key = await this.#subtle.exportKey("jwk", subtleKey.privateKey);
|
|
133
143
|
return Key({
|
|
134
144
|
kty: KeyType.EC,
|
|
135
145
|
crv: CurveType.p256,
|
|
@@ -139,7 +149,7 @@ class StandardCrypto extends Crypto {
|
|
|
139
149
|
});
|
|
140
150
|
}
|
|
141
151
|
async generateDhSecret(key, peerKey) {
|
|
142
|
-
const subtleKey = await importKey(
|
|
152
|
+
const subtleKey = await this.#importKey(
|
|
143
153
|
"jwk",
|
|
144
154
|
key,
|
|
145
155
|
{
|
|
@@ -149,7 +159,7 @@ class StandardCrypto extends Crypto {
|
|
|
149
159
|
false,
|
|
150
160
|
["deriveBits"]
|
|
151
161
|
);
|
|
152
|
-
const subtlePeerKey = await importKey(
|
|
162
|
+
const subtlePeerKey = await this.#importKey(
|
|
153
163
|
"jwk",
|
|
154
164
|
peerKey,
|
|
155
165
|
{
|
|
@@ -159,7 +169,7 @@ class StandardCrypto extends Crypto {
|
|
|
159
169
|
false,
|
|
160
170
|
[]
|
|
161
171
|
);
|
|
162
|
-
const secret = await subtle.deriveBits(
|
|
172
|
+
const secret = await this.#subtle.deriveBits(
|
|
163
173
|
{
|
|
164
174
|
name: "ECDH",
|
|
165
175
|
public: subtlePeerKey
|
|
@@ -169,15 +179,17 @@ class StandardCrypto extends Crypto {
|
|
|
169
179
|
);
|
|
170
180
|
return new Uint8Array(secret);
|
|
171
181
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
async #importKey(...params) {
|
|
183
|
+
try {
|
|
184
|
+
return await this.#subtle.importKey(...params);
|
|
185
|
+
} catch (cause) {
|
|
186
|
+
throw new KeyInputError("Invalid key", { cause });
|
|
187
|
+
}
|
|
178
188
|
}
|
|
179
189
|
}
|
|
180
|
-
|
|
190
|
+
if (crypto?.subtle !== void 0) {
|
|
191
|
+
Environment.default.set(Crypto, new StandardCrypto(crypto.subtle));
|
|
192
|
+
}
|
|
181
193
|
export {
|
|
182
194
|
StandardCrypto
|
|
183
195
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/crypto/StandardCrypto.ts"],
|
|
4
|
-
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,SAAS,YAAY,UAAU,gBAAgB;AAC/C,SAAS,mBAAmB;AAC5B,SAAS,aAAa;AACtB,SAAS,WAAW;AACpB,SAAS,QAAQ,mCAAsD;AACvE,SAAS,mBAAmB,qBAAqB;AACjD,SAAS,WAAW,KAAK,eAAsC;AAE/D,MAAM,
|
|
4
|
+
"mappings": "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",
|
|
5
5
|
"names": []
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matter/general",
|
|
3
|
-
"version": "0.15.0",
|
|
3
|
+
"version": "0.15.1-alpha.0-20250630-daa5888a0",
|
|
4
4
|
"description": "Non-Matter support for Matter.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"iot",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@noble/curves": "^1.9.2"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@matter/testing": "0.15.0"
|
|
39
|
+
"@matter/testing": "0.15.1-alpha.0-20250630-daa5888a0"
|
|
40
40
|
},
|
|
41
41
|
"files": [
|
|
42
42
|
"dist/**/*",
|
|
@@ -7,14 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
import { DerBigUint, DerCodec, DerError } from "#codec/DerCodec.js";
|
|
9
9
|
import { Environment } from "#environment/Environment.js";
|
|
10
|
+
import { ImplementationError } from "#MatterError.js";
|
|
10
11
|
import { Bytes } from "#util/Bytes.js";
|
|
11
12
|
import { Ccm } from "./aes/Ccm.js";
|
|
12
13
|
import { Crypto, CRYPTO_SYMMETRIC_KEY_LENGTH, CryptoDsaEncoding } from "./Crypto.js";
|
|
13
14
|
import { CryptoVerifyError, KeyInputError } from "./CryptoError.js";
|
|
14
15
|
import { CurveType, Key, KeyType, PrivateKey, PublicKey } from "./Key.js";
|
|
15
16
|
|
|
16
|
-
const subtle = globalThis.crypto.subtle;
|
|
17
|
-
|
|
18
17
|
const SIGNATURE_ALGORITHM = <EcdsaParams>{
|
|
19
18
|
name: "ECDSA",
|
|
20
19
|
namedCurve: "P-256",
|
|
@@ -22,16 +21,29 @@ const SIGNATURE_ALGORITHM = <EcdsaParams>{
|
|
|
22
21
|
};
|
|
23
22
|
|
|
24
23
|
/**
|
|
25
|
-
* A {@link Crypto} implementation
|
|
24
|
+
* A {@link Crypto} implementation that uses only JS standards.
|
|
26
25
|
*
|
|
27
26
|
* WARNING: This code is unaudited. Use a trusted native alternative where available.
|
|
28
27
|
*
|
|
29
28
|
* This module is mostly based on {@link crypto.subtle}. This should be a reliable native implementation. However,
|
|
30
|
-
* Web Crypto doesn't support AES-CCM required by Matter so
|
|
31
|
-
*
|
|
29
|
+
* Web Crypto doesn't support AES-CCM required by Matter so we use a JS implementation for that. See relevant warnings
|
|
30
|
+
* in the "aes" subdirectory.
|
|
32
31
|
*/
|
|
33
32
|
export class StandardCrypto extends Crypto {
|
|
34
33
|
implementationName = "JS";
|
|
34
|
+
#subtle: SubtleCrypto;
|
|
35
|
+
|
|
36
|
+
constructor(subtle: SubtleCrypto = crypto?.subtle) {
|
|
37
|
+
if (subtle === undefined) {
|
|
38
|
+
throw new ImplementationError(
|
|
39
|
+
"You cannot instantiate StandardCrypto in this runtime because crypto.subtle is not present",
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
super();
|
|
44
|
+
|
|
45
|
+
this.#subtle = subtle;
|
|
46
|
+
}
|
|
35
47
|
|
|
36
48
|
static provider() {
|
|
37
49
|
return new StandardCrypto();
|
|
@@ -57,12 +69,12 @@ export class StandardCrypto extends Crypto {
|
|
|
57
69
|
if (Array.isArray(buffer)) {
|
|
58
70
|
buffer = Bytes.concat(...buffer);
|
|
59
71
|
}
|
|
60
|
-
return new Uint8Array(await subtle.digest("SHA-256", buffer));
|
|
72
|
+
return new Uint8Array(await this.#subtle.digest("SHA-256", buffer));
|
|
61
73
|
}
|
|
62
74
|
|
|
63
75
|
async createPbkdf2Key(secret: Uint8Array, salt: Uint8Array, iteration: number, keyLength: number) {
|
|
64
|
-
const key = await importKey("raw", secret, "PBKDF2", false, ["deriveBits"]);
|
|
65
|
-
const bits = await subtle.deriveBits(
|
|
76
|
+
const key = await this.#importKey("raw", secret, "PBKDF2", false, ["deriveBits"]);
|
|
77
|
+
const bits = await this.#subtle.deriveBits(
|
|
66
78
|
{
|
|
67
79
|
name: "PBKDF2",
|
|
68
80
|
hash: "SHA-256",
|
|
@@ -81,8 +93,8 @@ export class StandardCrypto extends Crypto {
|
|
|
81
93
|
info: Uint8Array,
|
|
82
94
|
length: number = CRYPTO_SYMMETRIC_KEY_LENGTH,
|
|
83
95
|
) {
|
|
84
|
-
const key = await importKey("raw", secret, "HKDF", false, ["deriveBits"]);
|
|
85
|
-
const bits = await subtle.deriveBits(
|
|
96
|
+
const key = await this.#importKey("raw", secret, "HKDF", false, ["deriveBits"]);
|
|
97
|
+
const bits = await this.#subtle.deriveBits(
|
|
86
98
|
{
|
|
87
99
|
name: "HKDF",
|
|
88
100
|
hash: "SHA-256",
|
|
@@ -96,8 +108,8 @@ export class StandardCrypto extends Crypto {
|
|
|
96
108
|
}
|
|
97
109
|
|
|
98
110
|
async signHmac(secret: Uint8Array, data: Uint8Array) {
|
|
99
|
-
const key = await importKey("raw", secret, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
100
|
-
return new Uint8Array(await subtle.sign("HMAC", key, data));
|
|
111
|
+
const key = await this.#importKey("raw", secret, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
112
|
+
return new Uint8Array(await this.#subtle.sign("HMAC", key, data));
|
|
101
113
|
}
|
|
102
114
|
|
|
103
115
|
async signEcdsa(key: JsonWebKey, data: Uint8Array | Uint8Array[], dsaEncoding?: CryptoDsaEncoding) {
|
|
@@ -117,9 +129,9 @@ export class StandardCrypto extends Crypto {
|
|
|
117
129
|
key_ops: ["sign"],
|
|
118
130
|
};
|
|
119
131
|
|
|
120
|
-
const subtleKey = await importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["sign"]);
|
|
132
|
+
const subtleKey = await this.#importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["sign"]);
|
|
121
133
|
|
|
122
|
-
const ieeeP1363 = await subtle.sign(SIGNATURE_ALGORITHM, subtleKey, data);
|
|
134
|
+
const ieeeP1363 = await this.#subtle.sign(SIGNATURE_ALGORITHM, subtleKey, data);
|
|
123
135
|
|
|
124
136
|
if (dsaEncoding !== "der") return new Uint8Array(ieeeP1363);
|
|
125
137
|
|
|
@@ -134,7 +146,7 @@ export class StandardCrypto extends Crypto {
|
|
|
134
146
|
async verifyEcdsa(key: JsonWebKey, data: Uint8Array, signature: Uint8Array, dsaEncoding?: CryptoDsaEncoding) {
|
|
135
147
|
const { crv, kty, x, y } = key;
|
|
136
148
|
key = { crv, kty, x, y };
|
|
137
|
-
const subtleKey = await importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["verify"]);
|
|
149
|
+
const subtleKey = await this.#importKey("jwk", key, SIGNATURE_ALGORITHM, false, ["verify"]);
|
|
138
150
|
|
|
139
151
|
if (dsaEncoding === "der") {
|
|
140
152
|
try {
|
|
@@ -151,7 +163,7 @@ export class StandardCrypto extends Crypto {
|
|
|
151
163
|
}
|
|
152
164
|
}
|
|
153
165
|
|
|
154
|
-
const verified = await subtle.verify(SIGNATURE_ALGORITHM, subtleKey, signature, data);
|
|
166
|
+
const verified = await this.#subtle.verify(SIGNATURE_ALGORITHM, subtleKey, signature, data);
|
|
155
167
|
|
|
156
168
|
if (!verified) {
|
|
157
169
|
throw new CryptoVerifyError("Signature verification failed");
|
|
@@ -159,7 +171,7 @@ export class StandardCrypto extends Crypto {
|
|
|
159
171
|
}
|
|
160
172
|
|
|
161
173
|
async createKeyPair() {
|
|
162
|
-
const subtleKey = await subtle.generateKey(
|
|
174
|
+
const subtleKey = await this.#subtle.generateKey(
|
|
163
175
|
{
|
|
164
176
|
// We must specify either ECDH or ECDSA to get an EC key but we may use the key for either (but not for
|
|
165
177
|
// both)
|
|
@@ -173,7 +185,7 @@ export class StandardCrypto extends Crypto {
|
|
|
173
185
|
);
|
|
174
186
|
|
|
175
187
|
// Do not export as JWK because we do not want to inherit the algorithm and key_ops
|
|
176
|
-
const key = await subtle.exportKey("jwk", subtleKey.privateKey);
|
|
188
|
+
const key = await this.#subtle.exportKey("jwk", subtleKey.privateKey);
|
|
177
189
|
|
|
178
190
|
// Extract only private and public fields; we do not want key_ops
|
|
179
191
|
return Key({
|
|
@@ -186,7 +198,7 @@ export class StandardCrypto extends Crypto {
|
|
|
186
198
|
}
|
|
187
199
|
|
|
188
200
|
async generateDhSecret(key: PrivateKey, peerKey: PublicKey) {
|
|
189
|
-
const subtleKey = await importKey(
|
|
201
|
+
const subtleKey = await this.#importKey(
|
|
190
202
|
"jwk",
|
|
191
203
|
key,
|
|
192
204
|
{
|
|
@@ -197,7 +209,7 @@ export class StandardCrypto extends Crypto {
|
|
|
197
209
|
["deriveBits"],
|
|
198
210
|
);
|
|
199
211
|
|
|
200
|
-
const subtlePeerKey = await importKey(
|
|
212
|
+
const subtlePeerKey = await this.#importKey(
|
|
201
213
|
"jwk",
|
|
202
214
|
peerKey,
|
|
203
215
|
{
|
|
@@ -208,7 +220,7 @@ export class StandardCrypto extends Crypto {
|
|
|
208
220
|
[],
|
|
209
221
|
);
|
|
210
222
|
|
|
211
|
-
const secret = await subtle.deriveBits(
|
|
223
|
+
const secret = await this.#subtle.deriveBits(
|
|
212
224
|
{
|
|
213
225
|
name: "ECDH",
|
|
214
226
|
public: subtlePeerKey,
|
|
@@ -219,30 +231,33 @@ export class StandardCrypto extends Crypto {
|
|
|
219
231
|
|
|
220
232
|
return new Uint8Array(secret);
|
|
221
233
|
}
|
|
222
|
-
}
|
|
223
234
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
): Promise<CryptoKey>;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
): Promise<CryptoKey>;
|
|
238
|
-
|
|
239
|
-
async
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
235
|
+
#importKey(
|
|
236
|
+
format: "jwk",
|
|
237
|
+
keyData: JsonWebKey,
|
|
238
|
+
algorithm: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | AesKeyAlgorithm,
|
|
239
|
+
extractable: boolean,
|
|
240
|
+
keyUsages: ReadonlyArray<KeyUsage>,
|
|
241
|
+
): Promise<CryptoKey>;
|
|
242
|
+
#importKey(
|
|
243
|
+
format: Exclude<KeyFormat, "jwk">,
|
|
244
|
+
keyData: BufferSource,
|
|
245
|
+
algorithm: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | AesKeyAlgorithm,
|
|
246
|
+
extractable: boolean,
|
|
247
|
+
keyUsages: KeyUsage[],
|
|
248
|
+
): Promise<CryptoKey>;
|
|
249
|
+
|
|
250
|
+
async #importKey(...params: unknown[]) {
|
|
251
|
+
try {
|
|
252
|
+
return await this.#subtle.importKey(...(params as Parameters<SubtleCrypto["importKey"]>));
|
|
253
|
+
} catch (cause) {
|
|
254
|
+
throw new KeyInputError("Invalid key", { cause });
|
|
255
|
+
}
|
|
244
256
|
}
|
|
245
257
|
}
|
|
246
258
|
|
|
247
|
-
//
|
|
248
|
-
|
|
259
|
+
// If available, unconditionally add to Environment as it has not been exported yet so there can be no other
|
|
260
|
+
// implementation present
|
|
261
|
+
if (crypto?.subtle !== undefined) {
|
|
262
|
+
Environment.default.set(Crypto, new StandardCrypto(crypto.subtle));
|
|
263
|
+
}
|