-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathCrypto.ts
141 lines (116 loc) · 5.48 KB
/
Crypto.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/**
* @license
* Copyright 2022-2024 Matter.js Authors
* SPDX-License-Identifier: Apache-2.0
*/
import { Boot } from "#util/Boot.js";
import * as mod from "@noble/curves/abstract/modular";
import * as utils from "@noble/curves/abstract/utils";
import { p256 } from "@noble/curves/p256";
import { MatterError, NoProviderError } from "../MatterError.js";
import { Endian } from "../util/Bytes.js";
import { DataReader } from "../util/DataReader.js";
import { PrivateKey } from "./Key.js";
export const ec = {
p256,
...utils,
...mod,
};
export const CRYPTO_RANDOM_LENGTH = 32;
export const CRYPTO_ENCRYPT_ALGORITHM = "aes-128-ccm";
export const CRYPTO_HASH_ALGORITHM = "sha256";
export const CRYPTO_EC_CURVE = "prime256v1";
export const CRYPTO_EC_KEY_BYTES = 32;
export const CRYPTO_AUTH_TAG_LENGTH = 16;
export const CRYPTO_SYMMETRIC_KEY_LENGTH = 16;
export type CryptoDsaEncoding = "ieee-p1363" | "der";
export class CryptoVerifyError extends MatterError {}
export abstract class Crypto {
static get: () => Crypto;
abstract encrypt(key: Uint8Array, data: Uint8Array, nonce: Uint8Array, aad?: Uint8Array): Uint8Array;
static readonly encrypt = (key: Uint8Array, data: Uint8Array, nonce: Uint8Array, aad?: Uint8Array): Uint8Array =>
Crypto.get().encrypt(key, data, nonce, aad);
abstract decrypt(key: Uint8Array, data: Uint8Array, nonce: Uint8Array, aad?: Uint8Array): Uint8Array;
static readonly decrypt = (key: Uint8Array, data: Uint8Array, nonce: Uint8Array, aad?: Uint8Array): Uint8Array =>
Crypto.get().decrypt(key, data, nonce, aad);
abstract getRandomData(length: number): Uint8Array;
static readonly getRandomData = (length: number): Uint8Array => Crypto.get().getRandomData(length);
static readonly getRandom = (): Uint8Array => Crypto.get().getRandomData(CRYPTO_RANDOM_LENGTH);
static readonly getRandomUInt16 = (): number =>
new DataReader(Crypto.get().getRandomData(2), Endian.Little).readUInt16();
static readonly getRandomUInt32 = (): number =>
new DataReader(Crypto.get().getRandomData(4), Endian.Little).readUInt32();
static readonly getRandomBigUInt64 = (): bigint =>
new DataReader(Crypto.get().getRandomData(8), Endian.Little).readUInt64();
static readonly getRandomBigInt = (size: number, maxValue?: bigint): bigint => {
const { bytesToNumberBE } = ec;
if (maxValue === undefined) {
return bytesToNumberBE(Crypto.getRandomData(size));
}
while (true) {
const random = bytesToNumberBE(Crypto.getRandomData(size));
if (random < maxValue) return random;
}
};
abstract ecdhGeneratePublicKey(): { publicKey: Uint8Array; ecdh: any };
static readonly ecdhGeneratePublicKey = (): { publicKey: Uint8Array; ecdh: any } =>
Crypto.get().ecdhGeneratePublicKey();
abstract ecdhGeneratePublicKeyAndSecret(peerPublicKey: Uint8Array): {
publicKey: Uint8Array;
sharedSecret: Uint8Array;
};
static readonly ecdhGeneratePublicKeyAndSecret = (
peerPublicKey: Uint8Array,
): { publicKey: Uint8Array; sharedSecret: Uint8Array } =>
Crypto.get().ecdhGeneratePublicKeyAndSecret(peerPublicKey);
abstract ecdhGenerateSecret(peerPublicKey: Uint8Array, ecdh: any): Uint8Array;
static readonly ecdhGenerateSecret = (peerPublicKey: Uint8Array, ecdh: any): Uint8Array =>
Crypto.get().ecdhGenerateSecret(peerPublicKey, ecdh);
abstract hash(data: Uint8Array | Uint8Array[]): Uint8Array;
static readonly hash = (data: Uint8Array | Uint8Array[]): Uint8Array => Crypto.get().hash(data);
abstract pbkdf2(secret: Uint8Array, salt: Uint8Array, iteration: number, keyLength: number): Promise<Uint8Array>;
static readonly pbkdf2 = (
secret: Uint8Array,
salt: Uint8Array,
iteration: number,
keyLength: number,
): Promise<Uint8Array> => Crypto.get().pbkdf2(secret, salt, iteration, keyLength);
abstract hkdf(secret: Uint8Array, salt: Uint8Array, info: Uint8Array, length?: number): Promise<Uint8Array>;
static readonly hkdf = (
secret: Uint8Array,
salt: Uint8Array,
info: Uint8Array,
length?: number,
): Promise<Uint8Array> => Crypto.get().hkdf(secret, salt, info, length);
abstract hmac(key: Uint8Array, data: Uint8Array): Uint8Array;
static readonly hmac = (key: Uint8Array, data: Uint8Array): Uint8Array => Crypto.get().hmac(key, data);
abstract sign(privateKey: JsonWebKey, data: Uint8Array | Uint8Array[], dsaEncoding?: CryptoDsaEncoding): Uint8Array;
static readonly sign = (
privateKey: JsonWebKey,
data: Uint8Array | Uint8Array[],
dsaEncoding?: CryptoDsaEncoding,
): Uint8Array => Crypto.get().sign(privateKey, data, dsaEncoding);
abstract verify(
publicKey: JsonWebKey,
data: Uint8Array,
signature: Uint8Array,
dsaEncoding?: CryptoDsaEncoding,
): void;
static readonly verify = (
publicKey: JsonWebKey,
data: Uint8Array,
signature: Uint8Array,
dsaEncoding?: CryptoDsaEncoding,
): void => Crypto.get().verify(publicKey, data, signature, dsaEncoding);
abstract createKeyPair(): PrivateKey;
static readonly createKeyPair = (): PrivateKey => Crypto.get().createKeyPair();
}
Boot.init(() => {
Crypto.get = () => {
throw new NoProviderError("No provider configured");
};
// Hook for testing frameworks
if (typeof MatterHooks !== "undefined") {
MatterHooks.cryptoSetup?.(Crypto);
}
});