@reallyme/crypto 0.3.9 → 0.3.11
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/README.md +10 -11
- package/dist/aead.js +1 -1
- package/dist/aesKw.js +1 -1
- package/dist/algorithms.js +1 -1
- package/dist/argon2id.js +1 -1
- package/dist/bip340Schnorr.js +1 -1
- package/dist/cryptoFacade.d.ts +60 -81
- package/dist/cryptoFacade.js +12 -408
- package/dist/cryptoFacadeAsymmetric.d.ts +20 -0
- package/dist/cryptoFacadeAsymmetric.js +252 -0
- package/dist/cryptoFacadeSymmetric.d.ts +27 -0
- package/dist/cryptoFacadeSymmetric.js +166 -0
- package/dist/digest.js +1 -1
- package/dist/ed25519.d.ts +2 -0
- package/dist/ed25519.js +45 -4
- package/dist/encodeEcdsaDer.js +1 -1
- package/dist/errors.js +1 -1
- package/dist/hkdf.js +1 -1
- package/dist/hmac.d.ts +3 -3
- package/dist/hmac.js +8 -5
- package/dist/hpke.d.ts +1 -1
- package/dist/hpke.js +4 -2
- package/dist/index.js +1 -1
- package/dist/jwaConcatKdf.js +1 -1
- package/dist/jwk.js +46 -11
- package/dist/kmac.js +1 -1
- package/dist/memory.js +1 -1
- package/dist/mlDsa.js +1 -1
- package/dist/mlKem.js +1 -1
- package/dist/operationResponse.js +1 -1
- package/dist/p256Ecdh.js +1 -1
- package/dist/p256Ecdsa.js +1 -1
- package/dist/p384Ecdh.js +1 -1
- package/dist/p384Ecdsa.js +1 -1
- package/dist/p521Ecdh.js +1 -1
- package/dist/p521Ecdsa.js +1 -1
- package/dist/pbkdf2.js +12 -4
- package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.js +1 -1
- package/dist/proto.d.ts +8 -117
- package/dist/proto.js +6 -1085
- package/dist/protoAlgorithms.d.ts +21 -0
- package/dist/protoAlgorithms.js +323 -0
- package/dist/protoErrors.d.ts +27 -0
- package/dist/protoErrors.js +275 -0
- package/dist/protoIdentifiers.d.ts +14 -0
- package/dist/protoIdentifiers.js +112 -0
- package/dist/protoJwk.d.ts +10 -0
- package/dist/protoJwk.js +204 -0
- package/dist/protoValues.d.ts +63 -0
- package/dist/protoValues.js +228 -0
- package/dist/providerCatalog.js +1 -1
- package/dist/rsa.js +1 -1
- package/dist/secp256k1.js +1 -1
- package/dist/slhDsa.js +1 -1
- package/dist/validateBytes.js +1 -1
- package/dist/verifyBundledWasmModule.d.ts +63 -0
- package/dist/verifyBundledWasmModule.js +80 -0
- package/dist/wasm/reallyme_crypto_wasm.d.ts +383 -0
- package/dist/wasm/reallyme_crypto_wasm.js +8 -8
- package/dist/wasm/reallyme_crypto_wasm_bg.wasm +0 -0
- package/dist/wasmModuleTypes.js +1 -1
- package/dist/wasmProvider.d.ts +5 -0
- package/dist/wasmProvider.js +61 -3
- package/dist/x25519.js +1 -1
- package/dist/xWing.js +1 -1
- package/package.json +6 -5
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 ReallyMe LLC
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
4
|
+
import { ReallyMeBip340Schnorr } from "./bip340Schnorr.js";
|
|
5
|
+
import { ReallyMeEd25519 } from "./ed25519.js";
|
|
6
|
+
import { ReallyMeCryptoError } from "./errors.js";
|
|
7
|
+
import { ReallyMeHpke } from "./hpke.js";
|
|
8
|
+
import { ReallyMeMlDsa } from "./mlDsa.js";
|
|
9
|
+
import { ReallyMeMlKem } from "./mlKem.js";
|
|
10
|
+
import { ReallyMeP256Ecdh } from "./p256Ecdh.js";
|
|
11
|
+
import { ReallyMeP256Ecdsa } from "./p256Ecdsa.js";
|
|
12
|
+
import { ReallyMeP384Ecdh } from "./p384Ecdh.js";
|
|
13
|
+
import { ReallyMeP384Ecdsa } from "./p384Ecdsa.js";
|
|
14
|
+
import { ReallyMeP521Ecdh } from "./p521Ecdh.js";
|
|
15
|
+
import { ReallyMeP521Ecdsa } from "./p521Ecdsa.js";
|
|
16
|
+
import { ReallyMeRsa } from "./rsa.js";
|
|
17
|
+
import { ReallyMeSecp256k1 } from "./secp256k1.js";
|
|
18
|
+
import { ReallyMeSlhDsa } from "./slhDsa.js";
|
|
19
|
+
import { ReallyMeX25519 } from "./x25519.js";
|
|
20
|
+
import { ReallyMeXWing } from "./xWing.js";
|
|
21
|
+
const SECP256K1_ECDSA = "ECDSA-secp256k1-SHA256";
|
|
22
|
+
const P256_ECDSA = "ECDSA-P256-SHA256";
|
|
23
|
+
const P384_ECDSA = "ECDSA-P384-SHA384";
|
|
24
|
+
const P521_ECDSA = "ECDSA-P521-SHA512";
|
|
25
|
+
const BIP340_SCHNORR = "BIP340-Schnorr-secp256k1-SHA256";
|
|
26
|
+
const ED25519 = "Ed25519";
|
|
27
|
+
export const createReallyMeAsymmetricFacade = (resolveWasmProvider) => ({
|
|
28
|
+
generateKeyPair(algorithm) {
|
|
29
|
+
if (algorithm === ED25519) {
|
|
30
|
+
return ReallyMeEd25519.generateKeyPair();
|
|
31
|
+
}
|
|
32
|
+
switch (algorithm) {
|
|
33
|
+
case P256_ECDSA:
|
|
34
|
+
return ReallyMeP256Ecdsa.generateKeyPair();
|
|
35
|
+
case P384_ECDSA:
|
|
36
|
+
return ReallyMeP384Ecdsa.generateKeyPair();
|
|
37
|
+
case P521_ECDSA:
|
|
38
|
+
return ReallyMeP521Ecdsa.generateKeyPair();
|
|
39
|
+
case SECP256K1_ECDSA:
|
|
40
|
+
return ReallyMeSecp256k1.generateKeyPair();
|
|
41
|
+
case BIP340_SCHNORR:
|
|
42
|
+
return ReallyMeBip340Schnorr.generateKeyPair();
|
|
43
|
+
case "ML-DSA-44":
|
|
44
|
+
case "ML-DSA-65":
|
|
45
|
+
case "ML-DSA-87":
|
|
46
|
+
return ReallyMeMlDsa.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
|
|
47
|
+
case "SLH-DSA-SHA2-128s":
|
|
48
|
+
return ReallyMeSlhDsa.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
|
|
49
|
+
default:
|
|
50
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
deriveKeyPair(algorithm, secretKey) {
|
|
54
|
+
// Import an existing secret and reconstruct its public key. Do not use
|
|
55
|
+
// this as key generation from passwords or other low-entropy input; use
|
|
56
|
+
// generateKeyPair for new keys, or a protocol-approved KDF before import.
|
|
57
|
+
if (algorithm === ED25519) {
|
|
58
|
+
return ReallyMeEd25519.deriveKeyPair(secretKey);
|
|
59
|
+
}
|
|
60
|
+
switch (algorithm) {
|
|
61
|
+
case P256_ECDSA:
|
|
62
|
+
return ReallyMeP256Ecdsa.deriveKeyPair(secretKey);
|
|
63
|
+
case P384_ECDSA:
|
|
64
|
+
return ReallyMeP384Ecdsa.deriveKeyPair(secretKey);
|
|
65
|
+
case P521_ECDSA:
|
|
66
|
+
return ReallyMeP521Ecdsa.deriveKeyPair(secretKey);
|
|
67
|
+
case SECP256K1_ECDSA:
|
|
68
|
+
return ReallyMeSecp256k1.deriveKeyPair(secretKey);
|
|
69
|
+
case BIP340_SCHNORR:
|
|
70
|
+
return ReallyMeBip340Schnorr.deriveKeyPair(secretKey);
|
|
71
|
+
case "ML-DSA-44":
|
|
72
|
+
case "ML-DSA-65":
|
|
73
|
+
case "ML-DSA-87":
|
|
74
|
+
return ReallyMeMlDsa.deriveKeyPairWithProvider(resolveWasmProvider(), algorithm, secretKey);
|
|
75
|
+
case "SLH-DSA-SHA2-128s":
|
|
76
|
+
// SLH-DSA deterministic derivation uses three FIPS seed components,
|
|
77
|
+
// so it deliberately does not fit this single-secret import shape.
|
|
78
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
79
|
+
default:
|
|
80
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
sign(algorithm, message, secretKey) {
|
|
84
|
+
if (algorithm === ED25519) {
|
|
85
|
+
return ReallyMeEd25519.sign(message, secretKey);
|
|
86
|
+
}
|
|
87
|
+
switch (algorithm) {
|
|
88
|
+
case P256_ECDSA:
|
|
89
|
+
return ReallyMeP256Ecdsa.sign(message, secretKey);
|
|
90
|
+
case P384_ECDSA:
|
|
91
|
+
return ReallyMeP384Ecdsa.sign(message, secretKey);
|
|
92
|
+
case P521_ECDSA:
|
|
93
|
+
return ReallyMeP521Ecdsa.sign(message, secretKey);
|
|
94
|
+
case SECP256K1_ECDSA:
|
|
95
|
+
return ReallyMeSecp256k1.sign(message, secretKey);
|
|
96
|
+
case "ML-DSA-44":
|
|
97
|
+
case "ML-DSA-65":
|
|
98
|
+
case "ML-DSA-87":
|
|
99
|
+
return ReallyMeMlDsa.signWithProvider(resolveWasmProvider(), algorithm, message, secretKey);
|
|
100
|
+
case "SLH-DSA-SHA2-128s":
|
|
101
|
+
return ReallyMeSlhDsa.signWithProvider(resolveWasmProvider(), algorithm, message, secretKey);
|
|
102
|
+
default:
|
|
103
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
signBip340Schnorr(message32, secretKey, auxRand32) {
|
|
107
|
+
return ReallyMeBip340Schnorr.sign(message32, secretKey, auxRand32);
|
|
108
|
+
},
|
|
109
|
+
verify(algorithm, signature, message, publicKey) {
|
|
110
|
+
if (algorithm === ED25519) {
|
|
111
|
+
ReallyMeEd25519.verify(signature, message, publicKey);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
switch (algorithm) {
|
|
115
|
+
case P256_ECDSA:
|
|
116
|
+
ReallyMeP256Ecdsa.verify(signature, message, publicKey);
|
|
117
|
+
return;
|
|
118
|
+
case P384_ECDSA:
|
|
119
|
+
ReallyMeP384Ecdsa.verify(signature, message, publicKey);
|
|
120
|
+
return;
|
|
121
|
+
case P521_ECDSA:
|
|
122
|
+
ReallyMeP521Ecdsa.verify(signature, message, publicKey);
|
|
123
|
+
return;
|
|
124
|
+
case SECP256K1_ECDSA:
|
|
125
|
+
ReallyMeSecp256k1.verify(signature, message, publicKey);
|
|
126
|
+
return;
|
|
127
|
+
case BIP340_SCHNORR:
|
|
128
|
+
ReallyMeBip340Schnorr.verify(signature, message, publicKey);
|
|
129
|
+
return;
|
|
130
|
+
case "ML-DSA-44":
|
|
131
|
+
case "ML-DSA-65":
|
|
132
|
+
case "ML-DSA-87":
|
|
133
|
+
ReallyMeMlDsa.verifyWithProvider(resolveWasmProvider(), algorithm, signature, message, publicKey);
|
|
134
|
+
return;
|
|
135
|
+
case "SLH-DSA-SHA2-128s":
|
|
136
|
+
ReallyMeSlhDsa.verifyWithProvider(resolveWasmProvider(), algorithm, signature, message, publicKey);
|
|
137
|
+
return;
|
|
138
|
+
default:
|
|
139
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
verifyRsa(algorithm, signature, message, publicKeyDer, publicKeyEncoding) {
|
|
143
|
+
switch (algorithm) {
|
|
144
|
+
case "RSA-PKCS1v15-SHA1":
|
|
145
|
+
case "RSA-PKCS1v15-SHA256":
|
|
146
|
+
case "RSA-PKCS1v15-SHA384":
|
|
147
|
+
case "RSA-PKCS1v15-SHA512":
|
|
148
|
+
case "RSA-PSS-SHA1-MGF1-SHA1":
|
|
149
|
+
case "RSA-PSS-SHA256-MGF1-SHA256":
|
|
150
|
+
case "RSA-PSS-SHA384-MGF1-SHA384":
|
|
151
|
+
case "RSA-PSS-SHA512-MGF1-SHA512":
|
|
152
|
+
ReallyMeRsa.verifyWithProvider(resolveWasmProvider(), algorithm, signature, message, publicKeyDer, publicKeyEncoding);
|
|
153
|
+
return;
|
|
154
|
+
default:
|
|
155
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
deriveSharedSecret(algorithm, publicKey, secretKey) {
|
|
159
|
+
switch (algorithm) {
|
|
160
|
+
case "X25519":
|
|
161
|
+
return ReallyMeX25519.deriveSharedSecret(publicKey, secretKey);
|
|
162
|
+
case "P-256-ECDH":
|
|
163
|
+
return ReallyMeP256Ecdh.deriveSharedSecret(publicKey, secretKey);
|
|
164
|
+
case "P-384-ECDH":
|
|
165
|
+
return ReallyMeP384Ecdh.deriveSharedSecret(publicKey, secretKey);
|
|
166
|
+
case "P-521-ECDH":
|
|
167
|
+
return ReallyMeP521Ecdh.deriveSharedSecret(publicKey, secretKey);
|
|
168
|
+
default:
|
|
169
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
deriveKeyAgreementKeyPair(algorithm, secretKey) {
|
|
173
|
+
switch (algorithm) {
|
|
174
|
+
case "X25519":
|
|
175
|
+
return ReallyMeX25519.deriveKeyPair(secretKey);
|
|
176
|
+
case "P-256-ECDH":
|
|
177
|
+
return ReallyMeP256Ecdh.deriveKeyPair(secretKey);
|
|
178
|
+
case "P-384-ECDH":
|
|
179
|
+
return ReallyMeP384Ecdh.deriveKeyPair(secretKey);
|
|
180
|
+
case "P-521-ECDH":
|
|
181
|
+
return ReallyMeP521Ecdh.deriveKeyPair(secretKey);
|
|
182
|
+
default:
|
|
183
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
generateKemKeyPair(algorithm) {
|
|
187
|
+
switch (algorithm) {
|
|
188
|
+
case "X-Wing-768":
|
|
189
|
+
return ReallyMeXWing.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
|
|
190
|
+
case "ML-KEM-512":
|
|
191
|
+
case "ML-KEM-768":
|
|
192
|
+
case "ML-KEM-1024":
|
|
193
|
+
return ReallyMeMlKem.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
|
|
194
|
+
default:
|
|
195
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
deriveKemKeyPair(algorithm, secretKey) {
|
|
199
|
+
switch (algorithm) {
|
|
200
|
+
case "X-Wing-768":
|
|
201
|
+
return ReallyMeXWing.deriveKeyPairWithProvider(resolveWasmProvider(), algorithm, secretKey);
|
|
202
|
+
case "ML-KEM-512":
|
|
203
|
+
case "ML-KEM-768":
|
|
204
|
+
case "ML-KEM-1024":
|
|
205
|
+
return ReallyMeMlKem.deriveKeyPairWithProvider(resolveWasmProvider(), algorithm, secretKey);
|
|
206
|
+
default:
|
|
207
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
encapsulate(algorithm, publicKey) {
|
|
211
|
+
switch (algorithm) {
|
|
212
|
+
case "X-Wing-768":
|
|
213
|
+
return ReallyMeXWing.encapsulateWithProvider(resolveWasmProvider(), algorithm, publicKey);
|
|
214
|
+
case "ML-KEM-512":
|
|
215
|
+
case "ML-KEM-768":
|
|
216
|
+
case "ML-KEM-1024":
|
|
217
|
+
return ReallyMeMlKem.encapsulateWithProvider(resolveWasmProvider(), algorithm, publicKey);
|
|
218
|
+
default:
|
|
219
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
decapsulate(algorithm, ciphertext, secretKey) {
|
|
223
|
+
switch (algorithm) {
|
|
224
|
+
case "X-Wing-768":
|
|
225
|
+
return ReallyMeXWing.decapsulateWithProvider(resolveWasmProvider(), algorithm, ciphertext, secretKey);
|
|
226
|
+
case "ML-KEM-512":
|
|
227
|
+
case "ML-KEM-768":
|
|
228
|
+
case "ML-KEM-1024":
|
|
229
|
+
return ReallyMeMlKem.decapsulateWithProvider(resolveWasmProvider(), algorithm, ciphertext, secretKey);
|
|
230
|
+
default:
|
|
231
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
sealHpke(suite, recipientPublicKey, info, aad, plaintext) {
|
|
235
|
+
switch (suite) {
|
|
236
|
+
case "DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM":
|
|
237
|
+
case "DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305":
|
|
238
|
+
return ReallyMeHpke.sealBaseWithProvider(resolveWasmProvider(), suite, recipientPublicKey, info, aad, plaintext);
|
|
239
|
+
default:
|
|
240
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
openHpke(suite, recipientSecretKey, encapsulatedKey, info, aad, ciphertext) {
|
|
244
|
+
switch (suite) {
|
|
245
|
+
case "DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM":
|
|
246
|
+
case "DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305":
|
|
247
|
+
return ReallyMeHpke.openBaseWithProvider(resolveWasmProvider(), suite, recipientSecretKey, encapsulatedKey, info, aad, ciphertext);
|
|
248
|
+
default:
|
|
249
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ReallyMeAeadAlgorithm, ReallyMeHashAlgorithm, ReallyMeHkdfAlgorithm, ReallyMeJwaConcatKdfAlgorithm, ReallyMeKeyWrapAlgorithm, ReallyMeKmacKdfAlgorithm, ReallyMeMacAlgorithm, ReallyMePbkdf2Algorithm } from "./algorithms.js";
|
|
2
|
+
import type { ReallyMeWasmProvider } from "./wasmProvider.js";
|
|
3
|
+
export declare const createReallyMeSymmetricFacade: (resolveWasmProvider: () => ReallyMeWasmProvider) => {
|
|
4
|
+
/**
|
|
5
|
+
* Executes a generated binary request and returns a binary
|
|
6
|
+
* `CryptoOperationResponse`.
|
|
7
|
+
*/
|
|
8
|
+
processOperationResponse(request: Uint8Array): Uint8Array;
|
|
9
|
+
/**
|
|
10
|
+
* Executes a permitted non-secret generated ProtoJSON request and returns
|
|
11
|
+
* the same binary `CryptoOperationResponse`. Secret-bearing selectors fail
|
|
12
|
+
* before JSON value deserialization.
|
|
13
|
+
*/
|
|
14
|
+
processOperationResponseJson(requestJson: Uint8Array): Uint8Array;
|
|
15
|
+
hash(algorithm: ReallyMeHashAlgorithm, bytes: Uint8Array): Uint8Array;
|
|
16
|
+
seal(algorithm: ReallyMeAeadAlgorithm, key: Uint8Array, nonce: Uint8Array, aad: Uint8Array, plaintext: Uint8Array): Uint8Array;
|
|
17
|
+
open(algorithm: ReallyMeAeadAlgorithm, key: Uint8Array, nonce: Uint8Array, aad: Uint8Array, ciphertextWithTag: Uint8Array): Uint8Array;
|
|
18
|
+
authenticate(algorithm: ReallyMeMacAlgorithm, key: Uint8Array, message: Uint8Array): Uint8Array;
|
|
19
|
+
verifyMac(algorithm: ReallyMeMacAlgorithm, tag: Uint8Array, key: Uint8Array, message: Uint8Array): void;
|
|
20
|
+
deriveArgon2id(kdfVersion: number, secret: Uint8Array, salt: Uint8Array): Uint8Array;
|
|
21
|
+
deriveKey(algorithm: ReallyMePbkdf2Algorithm, password: Uint8Array, salt: Uint8Array, iterations: number, outputLength: number): Uint8Array;
|
|
22
|
+
deriveHkdf(algorithm: ReallyMeHkdfAlgorithm, inputKeyMaterial: Uint8Array, salt: Uint8Array, info: Uint8Array, outputLength: number): Uint8Array;
|
|
23
|
+
deriveJwaConcatKdfSha256(algorithm: ReallyMeJwaConcatKdfAlgorithm, sharedSecret: Uint8Array, algorithmId: Uint8Array, partyUInfo: Uint8Array, partyVInfo: Uint8Array, outputLength: number): Uint8Array;
|
|
24
|
+
deriveKmac256(algorithm: ReallyMeKmacKdfAlgorithm, key: Uint8Array, context: Uint8Array, customization: Uint8Array, outputLength: number): Uint8Array;
|
|
25
|
+
wrapKey(algorithm: ReallyMeKeyWrapAlgorithm, wrappingKey: Uint8Array, keyToWrap: Uint8Array): Uint8Array;
|
|
26
|
+
unwrapKey(algorithm: ReallyMeKeyWrapAlgorithm, wrappingKey: Uint8Array, wrappedKey: Uint8Array): Uint8Array;
|
|
27
|
+
};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 ReallyMe LLC
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
4
|
+
import { ReallyMeAead } from "./aead.js";
|
|
5
|
+
import { ReallyMeAesKw } from "./aesKw.js";
|
|
6
|
+
import { ReallyMeArgon2id } from "./argon2id.js";
|
|
7
|
+
import { ReallyMeDigest } from "./digest.js";
|
|
8
|
+
import { ReallyMeCryptoError } from "./errors.js";
|
|
9
|
+
import { ReallyMeHkdf } from "./hkdf.js";
|
|
10
|
+
import { ReallyMeHmac } from "./hmac.js";
|
|
11
|
+
import { ReallyMeJwaConcatKdf } from "./jwaConcatKdf.js";
|
|
12
|
+
import { ReallyMeKmac } from "./kmac.js";
|
|
13
|
+
import { processOperationResponseJsonWithProvider, processOperationResponseWithProvider, } from "./operationResponse.js";
|
|
14
|
+
import { ReallyMePbkdf2 } from "./pbkdf2.js";
|
|
15
|
+
import { ensureByteArray } from "./validateBytes.js";
|
|
16
|
+
export const createReallyMeSymmetricFacade = (resolveWasmProvider) => ({
|
|
17
|
+
/**
|
|
18
|
+
* Executes a generated binary request and returns a binary
|
|
19
|
+
* `CryptoOperationResponse`.
|
|
20
|
+
*/
|
|
21
|
+
processOperationResponse(request) {
|
|
22
|
+
ensureByteArray(request);
|
|
23
|
+
return processOperationResponseWithProvider(resolveWasmProvider(), request);
|
|
24
|
+
},
|
|
25
|
+
/**
|
|
26
|
+
* Executes a permitted non-secret generated ProtoJSON request and returns
|
|
27
|
+
* the same binary `CryptoOperationResponse`. Secret-bearing selectors fail
|
|
28
|
+
* before JSON value deserialization.
|
|
29
|
+
*/
|
|
30
|
+
processOperationResponseJson(requestJson) {
|
|
31
|
+
ensureByteArray(requestJson);
|
|
32
|
+
return processOperationResponseJsonWithProvider(resolveWasmProvider(), requestJson);
|
|
33
|
+
},
|
|
34
|
+
hash(algorithm, bytes) {
|
|
35
|
+
switch (algorithm) {
|
|
36
|
+
case "SHA2-256":
|
|
37
|
+
return ReallyMeDigest.sha256(bytes);
|
|
38
|
+
case "SHA2-384":
|
|
39
|
+
return ReallyMeDigest.sha384(bytes);
|
|
40
|
+
case "SHA2-512":
|
|
41
|
+
return ReallyMeDigest.sha512(bytes);
|
|
42
|
+
case "SHA3-224":
|
|
43
|
+
return ReallyMeDigest.sha3_224(bytes);
|
|
44
|
+
case "SHA3-256":
|
|
45
|
+
return ReallyMeDigest.sha3_256(bytes);
|
|
46
|
+
case "SHA3-384":
|
|
47
|
+
return ReallyMeDigest.sha3_384(bytes);
|
|
48
|
+
case "SHA3-512":
|
|
49
|
+
return ReallyMeDigest.sha3_512(bytes);
|
|
50
|
+
default:
|
|
51
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
seal(algorithm, key, nonce, aad, plaintext) {
|
|
55
|
+
switch (algorithm) {
|
|
56
|
+
case "AES-128-GCM":
|
|
57
|
+
case "AES-192-GCM":
|
|
58
|
+
case "AES-256-GCM":
|
|
59
|
+
case "AES-256-GCM-SIV":
|
|
60
|
+
case "ChaCha20-Poly1305":
|
|
61
|
+
case "XChaCha20-Poly1305":
|
|
62
|
+
return ReallyMeAead.sealWithProvider(resolveWasmProvider(), algorithm, key, nonce, aad, plaintext);
|
|
63
|
+
default:
|
|
64
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
open(algorithm, key, nonce, aad, ciphertextWithTag) {
|
|
68
|
+
switch (algorithm) {
|
|
69
|
+
case "AES-128-GCM":
|
|
70
|
+
case "AES-192-GCM":
|
|
71
|
+
case "AES-256-GCM":
|
|
72
|
+
case "AES-256-GCM-SIV":
|
|
73
|
+
case "ChaCha20-Poly1305":
|
|
74
|
+
case "XChaCha20-Poly1305":
|
|
75
|
+
return ReallyMeAead.openWithProvider(resolveWasmProvider(), algorithm, key, nonce, aad, ciphertextWithTag);
|
|
76
|
+
default:
|
|
77
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
authenticate(algorithm, key, message) {
|
|
81
|
+
switch (algorithm) {
|
|
82
|
+
case "HMAC-SHA-256":
|
|
83
|
+
return ReallyMeHmac.authenticateSha256(key, message);
|
|
84
|
+
case "HMAC-SHA-384":
|
|
85
|
+
return ReallyMeHmac.authenticateSha384(key, message);
|
|
86
|
+
case "HMAC-SHA-512":
|
|
87
|
+
return ReallyMeHmac.authenticateSha512(key, message);
|
|
88
|
+
default:
|
|
89
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
verifyMac(algorithm, tag, key, message) {
|
|
93
|
+
switch (algorithm) {
|
|
94
|
+
case "HMAC-SHA-256":
|
|
95
|
+
ReallyMeHmac.verifySha256(tag, key, message);
|
|
96
|
+
return;
|
|
97
|
+
case "HMAC-SHA-384":
|
|
98
|
+
ReallyMeHmac.verifySha384(tag, key, message);
|
|
99
|
+
return;
|
|
100
|
+
case "HMAC-SHA-512":
|
|
101
|
+
ReallyMeHmac.verifySha512(tag, key, message);
|
|
102
|
+
return;
|
|
103
|
+
default:
|
|
104
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
deriveArgon2id(kdfVersion, secret, salt) {
|
|
108
|
+
return ReallyMeArgon2id.deriveKeyWithProvider(resolveWasmProvider(), kdfVersion, secret, salt);
|
|
109
|
+
},
|
|
110
|
+
deriveKey(algorithm, password, salt, iterations, outputLength) {
|
|
111
|
+
switch (algorithm) {
|
|
112
|
+
case "PBKDF2-HMAC-SHA-256":
|
|
113
|
+
return ReallyMePbkdf2.deriveHmacSha256(password, salt, iterations, outputLength);
|
|
114
|
+
case "PBKDF2-HMAC-SHA-512":
|
|
115
|
+
return ReallyMePbkdf2.deriveHmacSha512(password, salt, iterations, outputLength);
|
|
116
|
+
default:
|
|
117
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
deriveHkdf(algorithm, inputKeyMaterial, salt, info, outputLength) {
|
|
121
|
+
switch (algorithm) {
|
|
122
|
+
case "HKDF-SHA256":
|
|
123
|
+
return ReallyMeHkdf.deriveSha256(inputKeyMaterial, salt, info, outputLength);
|
|
124
|
+
case "HKDF-SHA384":
|
|
125
|
+
return ReallyMeHkdf.deriveSha384(inputKeyMaterial, salt, info, outputLength);
|
|
126
|
+
default:
|
|
127
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
deriveJwaConcatKdfSha256(algorithm, sharedSecret, algorithmId, partyUInfo, partyVInfo, outputLength) {
|
|
131
|
+
switch (algorithm) {
|
|
132
|
+
case "JWA-CONCAT-KDF-SHA256":
|
|
133
|
+
return ReallyMeJwaConcatKdf.deriveSha256(sharedSecret, algorithmId, partyUInfo, partyVInfo, outputLength);
|
|
134
|
+
default:
|
|
135
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
deriveKmac256(algorithm, key, context, customization, outputLength) {
|
|
139
|
+
switch (algorithm) {
|
|
140
|
+
case "KMAC256":
|
|
141
|
+
return ReallyMeKmac.deriveKmac256WithProvider(resolveWasmProvider(), key, context, customization, outputLength);
|
|
142
|
+
default:
|
|
143
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
wrapKey(algorithm, wrappingKey, keyToWrap) {
|
|
147
|
+
switch (algorithm) {
|
|
148
|
+
case "AES-128-KW":
|
|
149
|
+
case "AES-192-KW":
|
|
150
|
+
case "AES-256-KW":
|
|
151
|
+
return ReallyMeAesKw.wrapKeyWithProvider(algorithm, resolveWasmProvider(), wrappingKey, keyToWrap);
|
|
152
|
+
default:
|
|
153
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
unwrapKey(algorithm, wrappingKey, wrappedKey) {
|
|
157
|
+
switch (algorithm) {
|
|
158
|
+
case "AES-128-KW":
|
|
159
|
+
case "AES-192-KW":
|
|
160
|
+
case "AES-256-KW":
|
|
161
|
+
return ReallyMeAesKw.unwrapKeyWithProvider(algorithm, resolveWasmProvider(), wrappingKey, wrappedKey);
|
|
162
|
+
default:
|
|
163
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
});
|
package/dist/digest.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText:
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 ReallyMe LLC
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
4
4
|
import { sha256 as nobleSha256, sha384 as nobleSha384, sha512 as nobleSha512 } from "@noble/hashes/sha2.js";
|
package/dist/ed25519.d.ts
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
export declare const ED25519_SECRET_KEY_LENGTH = 32;
|
|
11
11
|
export declare const ED25519_PUBLIC_KEY_LENGTH = 32;
|
|
12
12
|
export declare const ED25519_SIGNATURE_LENGTH = 64;
|
|
13
|
+
/** Require one canonical prime-subgroup encoding for an Ed25519 identity. */
|
|
14
|
+
export declare const validateEd25519PublicKeyIdentity: (publicKey: Uint8Array) => void;
|
|
13
15
|
export declare const ReallyMeEd25519: {
|
|
14
16
|
/** Generates a random Ed25519 keypair: 32-byte public key, 32-byte seed. */
|
|
15
17
|
readonly generateKeyPair: () => {
|
package/dist/ed25519.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText:
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 ReallyMe LLC
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
4
4
|
import { ed25519 } from "@noble/curves/ed25519.js";
|
|
5
|
+
import { bytesToNumberLE, concatBytes } from "@noble/curves/utils.js";
|
|
6
|
+
import { sha512 } from "@noble/hashes/sha2.js";
|
|
5
7
|
import { ReallyMeCryptoError } from "./errors.js";
|
|
6
8
|
import { ensureByteArray } from "./validateBytes.js";
|
|
7
9
|
/**
|
|
@@ -16,6 +18,25 @@ import { ensureByteArray } from "./validateBytes.js";
|
|
|
16
18
|
export const ED25519_SECRET_KEY_LENGTH = 32;
|
|
17
19
|
export const ED25519_PUBLIC_KEY_LENGTH = 32;
|
|
18
20
|
export const ED25519_SIGNATURE_LENGTH = 64;
|
|
21
|
+
/** Require one canonical prime-subgroup encoding for an Ed25519 identity. */
|
|
22
|
+
export const validateEd25519PublicKeyIdentity = (publicKey) => {
|
|
23
|
+
ensureByteArray(publicKey);
|
|
24
|
+
if (publicKey.length !== ED25519_PUBLIC_KEY_LENGTH) {
|
|
25
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const point = ed25519.Point.fromBytes(publicKey, false);
|
|
29
|
+
const canonical = point.toBytes();
|
|
30
|
+
if (!point.isTorsionFree() ||
|
|
31
|
+
point.isSmallOrder() ||
|
|
32
|
+
canonical.some((byte, index) => byte !== publicKey[index])) {
|
|
33
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
38
|
+
}
|
|
39
|
+
};
|
|
19
40
|
export const ReallyMeEd25519 = {
|
|
20
41
|
/** Generates a random Ed25519 keypair: 32-byte public key, 32-byte seed. */
|
|
21
42
|
generateKeyPair() {
|
|
@@ -78,13 +99,33 @@ export const ReallyMeEd25519 = {
|
|
|
78
99
|
publicKey.length !== ED25519_PUBLIC_KEY_LENGTH) {
|
|
79
100
|
throw new ReallyMeCryptoError("invalid-input");
|
|
80
101
|
}
|
|
102
|
+
let point;
|
|
81
103
|
try {
|
|
82
|
-
ed25519.Point.fromBytes(publicKey, false);
|
|
104
|
+
point = ed25519.Point.fromBytes(publicKey, false);
|
|
83
105
|
}
|
|
84
106
|
catch {
|
|
85
|
-
throw new ReallyMeCryptoError("invalid-
|
|
107
|
+
throw new ReallyMeCryptoError("invalid-signature");
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const rBytes = signature.subarray(0, ED25519_PUBLIC_KEY_LENGTH);
|
|
111
|
+
const rPoint = ed25519.Point.fromBytes(rBytes, false);
|
|
112
|
+
const scalar = bytesToNumberLE(signature.subarray(ED25519_PUBLIC_KEY_LENGTH));
|
|
113
|
+
const order = ed25519.Point.Fn.ORDER;
|
|
114
|
+
if (scalar >= order ||
|
|
115
|
+
!point.isTorsionFree() ||
|
|
116
|
+
!rPoint.isTorsionFree() ||
|
|
117
|
+
point.isSmallOrder() ||
|
|
118
|
+
rPoint.isSmallOrder()) {
|
|
119
|
+
throw new ReallyMeCryptoError("invalid-signature");
|
|
120
|
+
}
|
|
121
|
+
// Noble's ordinary verify uses a cofactored equation. Rust's verify_strict
|
|
122
|
+
// compares the full Edwards equation, including any torsion component.
|
|
123
|
+
const challenge = bytesToNumberLE(sha512(concatBytes(rBytes, publicKey, message))) % order;
|
|
124
|
+
if (!ed25519.Point.BASE.multiplyUnsafe(scalar).equals(rPoint.add(point.multiplyUnsafe(challenge)))) {
|
|
125
|
+
throw new ReallyMeCryptoError("invalid-signature");
|
|
126
|
+
}
|
|
86
127
|
}
|
|
87
|
-
|
|
128
|
+
catch {
|
|
88
129
|
throw new ReallyMeCryptoError("invalid-signature");
|
|
89
130
|
}
|
|
90
131
|
},
|
package/dist/encodeEcdsaDer.js
CHANGED
package/dist/errors.js
CHANGED
package/dist/hkdf.js
CHANGED
package/dist/hmac.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export declare const ReallyMeHmac: {
|
|
|
6
6
|
readonly authenticateSha256: (key: Uint8Array, message: Uint8Array) => Uint8Array;
|
|
7
7
|
readonly authenticateSha384: (key: Uint8Array, message: Uint8Array) => Uint8Array;
|
|
8
8
|
readonly authenticateSha512: (key: Uint8Array, message: Uint8Array) => Uint8Array;
|
|
9
|
-
readonly verifySha256: (tag: Uint8Array, key: Uint8Array, message: Uint8Array) =>
|
|
10
|
-
readonly verifySha384: (tag: Uint8Array, key: Uint8Array, message: Uint8Array) =>
|
|
11
|
-
readonly verifySha512: (tag: Uint8Array, key: Uint8Array, message: Uint8Array) =>
|
|
9
|
+
readonly verifySha256: (tag: Uint8Array, key: Uint8Array, message: Uint8Array) => void;
|
|
10
|
+
readonly verifySha384: (tag: Uint8Array, key: Uint8Array, message: Uint8Array) => void;
|
|
11
|
+
readonly verifySha512: (tag: Uint8Array, key: Uint8Array, message: Uint8Array) => void;
|
|
12
12
|
};
|
package/dist/hmac.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText:
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 ReallyMe LLC
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
4
4
|
import { hmac } from "@noble/hashes/hmac.js";
|
|
@@ -30,21 +30,21 @@ export const ReallyMeHmac = {
|
|
|
30
30
|
if (tag.length !== HMAC_SHA256_TAG_LENGTH) {
|
|
31
31
|
throw new ReallyMeCryptoError("invalid-input");
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
verifyAndClearExpectedTag(tag, ReallyMeHmac.authenticateSha256(key, message));
|
|
34
34
|
},
|
|
35
35
|
verifySha384(tag, key, message) {
|
|
36
36
|
ensureByteArray(tag);
|
|
37
37
|
if (tag.length !== HMAC_SHA384_TAG_LENGTH) {
|
|
38
38
|
throw new ReallyMeCryptoError("invalid-input");
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
verifyAndClearExpectedTag(tag, ReallyMeHmac.authenticateSha384(key, message));
|
|
41
41
|
},
|
|
42
42
|
verifySha512(tag, key, message) {
|
|
43
43
|
ensureByteArray(tag);
|
|
44
44
|
if (tag.length !== HMAC_SHA512_TAG_LENGTH) {
|
|
45
45
|
throw new ReallyMeCryptoError("invalid-input");
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
verifyAndClearExpectedTag(tag, ReallyMeHmac.authenticateSha512(key, message));
|
|
48
48
|
},
|
|
49
49
|
};
|
|
50
50
|
function validateKey(key) {
|
|
@@ -70,7 +70,10 @@ function constantTimeEquals(left, right) {
|
|
|
70
70
|
}
|
|
71
71
|
function verifyAndClearExpectedTag(tag, expectedTag) {
|
|
72
72
|
try {
|
|
73
|
-
|
|
73
|
+
if (!constantTimeEquals(tag, expectedTag)) {
|
|
74
|
+
// Verification must fail even when a caller ignores the return value.
|
|
75
|
+
throw new ReallyMeCryptoError("authentication-failed");
|
|
76
|
+
}
|
|
74
77
|
}
|
|
75
78
|
finally {
|
|
76
79
|
// Noble returns a new typed array. Clear it immediately so verification
|
package/dist/hpke.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare const HPKE_P256_PUBLIC_KEY_LENGTH = 65;
|
|
|
5
5
|
export declare const HPKE_X25519_PRIVATE_KEY_LENGTH = 32;
|
|
6
6
|
export declare const HPKE_X25519_PUBLIC_KEY_LENGTH = 32;
|
|
7
7
|
export declare const HPKE_AEAD_TAG_LENGTH = 16;
|
|
8
|
-
export declare const HPKE_INFO_MAX_LENGTH =
|
|
8
|
+
export declare const HPKE_INFO_MAX_LENGTH = 1048576;
|
|
9
9
|
export type ReallyMeHpkeSealedMessage = Readonly<{
|
|
10
10
|
encapsulatedKey: Uint8Array;
|
|
11
11
|
ciphertext: Uint8Array;
|
package/dist/hpke.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText:
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 ReallyMe LLC
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
4
4
|
import { ReallyMeCryptoError } from "./errors.js";
|
|
@@ -9,7 +9,9 @@ export const HPKE_P256_PUBLIC_KEY_LENGTH = 65;
|
|
|
9
9
|
export const HPKE_X25519_PRIVATE_KEY_LENGTH = 32;
|
|
10
10
|
export const HPKE_X25519_PUBLIC_KEY_LENGTH = 32;
|
|
11
11
|
export const HPKE_AEAD_TAG_LENGTH = 16;
|
|
12
|
-
|
|
12
|
+
// HKDF-based HPKE suites accept info beyond a u16 length; the package-wide
|
|
13
|
+
// input limit is the resource boundary for this public parameter.
|
|
14
|
+
export const HPKE_INFO_MAX_LENGTH = MAX_CRYPTO_INPUT_LENGTH;
|
|
13
15
|
const hpkeSuite = (suite) => {
|
|
14
16
|
switch (suite) {
|
|
15
17
|
case "DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM":
|
package/dist/index.js
CHANGED
package/dist/jwaConcatKdf.js
CHANGED