@reallyme/crypto 0.1.8 → 0.2.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.
- package/LICENSE +201 -0
- package/README.md +43 -3
- package/dist/aead.d.ts +4 -0
- package/dist/aead.js +32 -15
- package/dist/aesKw.d.ts +3 -0
- package/dist/aesKw.js +10 -0
- package/dist/argon2id.d.ts +2 -0
- package/dist/argon2id.js +6 -0
- package/dist/cryptoFacade.d.ts +36 -0
- package/dist/cryptoFacade.js +71 -23
- package/dist/errors.d.ts +1 -1
- package/dist/hpke.d.ts +4 -0
- package/dist/hpke.js +20 -0
- package/dist/index.d.ts +5 -6
- package/dist/index.js +4 -4
- package/dist/jwaConcatKdf.js +8 -4
- package/dist/jwk.js +67 -72
- package/dist/memory.d.ts +8 -0
- package/dist/memory.js +13 -0
- package/dist/mlDsa.d.ts +5 -0
- package/dist/mlDsa.js +23 -0
- package/dist/mlKem.d.ts +6 -0
- package/dist/mlKem.js +29 -0
- package/dist/p256Ecdh.js +5 -1
- package/dist/p384Ecdh.js +5 -1
- package/dist/p521Ecdh.js +5 -1
- package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.d.ts +1392 -72
- package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.js +490 -17
- package/dist/proto.d.ts +113 -5
- package/dist/proto.js +706 -3
- package/dist/rsa.d.ts +2 -0
- package/dist/rsa.js +18 -15
- package/dist/slhDsa.d.ts +5 -0
- package/dist/slhDsa.js +21 -0
- package/dist/validateBytes.d.ts +1 -0
- package/dist/validateBytes.js +6 -0
- package/dist/wasm/reallyme_crypto_wasm.js +1 -246
- package/dist/wasm/reallyme_crypto_wasm_bg.wasm +0 -0
- package/dist/wasmModuleTypes.d.ts +2 -11
- package/dist/wasmProvider.d.ts +1 -16
- package/dist/wasmProvider.js +10 -25
- package/dist/xWing.d.ts +6 -0
- package/dist/xWing.js +34 -2
- package/package.json +7 -2
- package/dist/codecs.d.ts +0 -35
- package/dist/codecs.js +0 -216
- package/dist/proto/generated/reallyme/codec/v1/codec_pb.d.ts +0 -253
- package/dist/proto/generated/reallyme/codec/v1/codec_pb.js +0 -160
package/dist/cryptoFacade.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { ReallyMeAead } from "./aead.js";
|
|
5
5
|
import { ReallyMeAesKw } from "./aesKw.js";
|
|
6
|
-
import { ReallyMeArgon2id } from "./argon2id.js";
|
|
6
|
+
import { ARGON2ID_DERIVED_KEY_LENGTH, ReallyMeArgon2id } from "./argon2id.js";
|
|
7
7
|
import { ReallyMeBip340Schnorr } from "./bip340Schnorr.js";
|
|
8
8
|
import { ReallyMeDigest } from "./digest.js";
|
|
9
9
|
import { ReallyMeEd25519 } from "./ed25519.js";
|
|
@@ -24,6 +24,7 @@ import { ReallyMePbkdf2 } from "./pbkdf2.js";
|
|
|
24
24
|
import { ReallyMeRsa } from "./rsa.js";
|
|
25
25
|
import { ReallyMeSecp256k1 } from "./secp256k1.js";
|
|
26
26
|
import { ReallyMeSlhDsa } from "./slhDsa.js";
|
|
27
|
+
import { requireReallyMeWasmProvider } from "./wasmProvider.js";
|
|
27
28
|
import { ReallyMeX25519 } from "./x25519.js";
|
|
28
29
|
import { ReallyMeXWing } from "./xWing.js";
|
|
29
30
|
const SECP256K1_ECDSA = "ECDSA-secp256k1-SHA256";
|
|
@@ -37,7 +38,7 @@ const ED25519 = "Ed25519";
|
|
|
37
38
|
* callers that want direct provider access; this facade gives consumers a
|
|
38
39
|
* stable typed route that fails closed for not-yet-exposed algorithms.
|
|
39
40
|
*/
|
|
40
|
-
|
|
41
|
+
const createReallyMeCryptoFacade = (resolveWasmProvider) => ({
|
|
41
42
|
hash(algorithm, bytes) {
|
|
42
43
|
switch (algorithm) {
|
|
43
44
|
case "SHA2-256":
|
|
@@ -66,7 +67,7 @@ export const ReallyMeCrypto = {
|
|
|
66
67
|
case "AES-256-GCM-SIV":
|
|
67
68
|
case "ChaCha20-Poly1305":
|
|
68
69
|
case "XChaCha20-Poly1305":
|
|
69
|
-
return ReallyMeAead.
|
|
70
|
+
return ReallyMeAead.sealWithProvider(resolveWasmProvider(), algorithm, key, nonce, aad, plaintext);
|
|
70
71
|
default:
|
|
71
72
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
72
73
|
}
|
|
@@ -79,7 +80,7 @@ export const ReallyMeCrypto = {
|
|
|
79
80
|
case "AES-256-GCM-SIV":
|
|
80
81
|
case "ChaCha20-Poly1305":
|
|
81
82
|
case "XChaCha20-Poly1305":
|
|
82
|
-
return ReallyMeAead.
|
|
83
|
+
return ReallyMeAead.openWithProvider(resolveWasmProvider(), algorithm, key, nonce, aad, ciphertextWithTag);
|
|
83
84
|
default:
|
|
84
85
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
85
86
|
}
|
|
@@ -104,10 +105,21 @@ export const ReallyMeCrypto = {
|
|
|
104
105
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
105
106
|
}
|
|
106
107
|
},
|
|
108
|
+
deriveArgon2id(kdfVersion, secret, salt) {
|
|
109
|
+
return ReallyMeArgon2id.deriveKeyWithProvider(resolveWasmProvider(), kdfVersion, secret, salt);
|
|
110
|
+
},
|
|
107
111
|
deriveKey(algorithm, password, salt, iterations, outputLength) {
|
|
108
112
|
switch (algorithm) {
|
|
109
113
|
case "Argon2id":
|
|
110
|
-
|
|
114
|
+
if (outputLength !== ARGON2ID_DERIVED_KEY_LENGTH) {
|
|
115
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
116
|
+
}
|
|
117
|
+
// Argon2id is governed by fixed ReallyMe profile versions, not by
|
|
118
|
+
// caller-selected iteration counts. This legacy generic KDF shape
|
|
119
|
+
// preserves the existing facade contract; new code should call
|
|
120
|
+
// deriveArgon2id(kdfVersion, secret, salt) so the profile selector is
|
|
121
|
+
// explicit at the API boundary.
|
|
122
|
+
return ReallyMeArgon2id.deriveKeyWithProvider(resolveWasmProvider(), iterations, password, salt);
|
|
111
123
|
case "PBKDF2-HMAC-SHA-256":
|
|
112
124
|
return ReallyMePbkdf2.deriveHmacSha256(password, salt, iterations, outputLength);
|
|
113
125
|
case "PBKDF2-HMAC-SHA-512":
|
|
@@ -147,7 +159,7 @@ export const ReallyMeCrypto = {
|
|
|
147
159
|
wrapKey(algorithm, wrappingKey, keyToWrap) {
|
|
148
160
|
switch (algorithm) {
|
|
149
161
|
case "AES-256-KW":
|
|
150
|
-
return ReallyMeAesKw.
|
|
162
|
+
return ReallyMeAesKw.wrapKeyWithProvider(resolveWasmProvider(), wrappingKey, keyToWrap);
|
|
151
163
|
default:
|
|
152
164
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
153
165
|
}
|
|
@@ -155,7 +167,7 @@ export const ReallyMeCrypto = {
|
|
|
155
167
|
unwrapKey(algorithm, wrappingKey, wrappedKey) {
|
|
156
168
|
switch (algorithm) {
|
|
157
169
|
case "AES-256-KW":
|
|
158
|
-
return ReallyMeAesKw.
|
|
170
|
+
return ReallyMeAesKw.unwrapKeyWithProvider(resolveWasmProvider(), wrappingKey, wrappedKey);
|
|
159
171
|
default:
|
|
160
172
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
161
173
|
}
|
|
@@ -178,9 +190,9 @@ export const ReallyMeCrypto = {
|
|
|
178
190
|
case "ML-DSA-44":
|
|
179
191
|
case "ML-DSA-65":
|
|
180
192
|
case "ML-DSA-87":
|
|
181
|
-
return ReallyMeMlDsa.
|
|
193
|
+
return ReallyMeMlDsa.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
|
|
182
194
|
case "SLH-DSA-SHA2-128s":
|
|
183
|
-
return ReallyMeSlhDsa.
|
|
195
|
+
return ReallyMeSlhDsa.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
|
|
184
196
|
default:
|
|
185
197
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
186
198
|
}
|
|
@@ -206,7 +218,7 @@ export const ReallyMeCrypto = {
|
|
|
206
218
|
case "ML-DSA-44":
|
|
207
219
|
case "ML-DSA-65":
|
|
208
220
|
case "ML-DSA-87":
|
|
209
|
-
return ReallyMeMlDsa.
|
|
221
|
+
return ReallyMeMlDsa.deriveKeyPairWithProvider(resolveWasmProvider(), algorithm, secretKey);
|
|
210
222
|
case "SLH-DSA-SHA2-128s":
|
|
211
223
|
// SLH-DSA deterministic derivation uses three FIPS seed components,
|
|
212
224
|
// so it deliberately does not fit this single-secret import shape.
|
|
@@ -231,9 +243,9 @@ export const ReallyMeCrypto = {
|
|
|
231
243
|
case "ML-DSA-44":
|
|
232
244
|
case "ML-DSA-65":
|
|
233
245
|
case "ML-DSA-87":
|
|
234
|
-
return ReallyMeMlDsa.
|
|
246
|
+
return ReallyMeMlDsa.signWithProvider(resolveWasmProvider(), algorithm, message, secretKey);
|
|
235
247
|
case "SLH-DSA-SHA2-128s":
|
|
236
|
-
return ReallyMeSlhDsa.
|
|
248
|
+
return ReallyMeSlhDsa.signWithProvider(resolveWasmProvider(), algorithm, message, secretKey);
|
|
237
249
|
default:
|
|
238
250
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
239
251
|
}
|
|
@@ -265,17 +277,30 @@ export const ReallyMeCrypto = {
|
|
|
265
277
|
case "ML-DSA-44":
|
|
266
278
|
case "ML-DSA-65":
|
|
267
279
|
case "ML-DSA-87":
|
|
268
|
-
ReallyMeMlDsa.
|
|
280
|
+
ReallyMeMlDsa.verifyWithProvider(resolveWasmProvider(), algorithm, signature, message, publicKey);
|
|
269
281
|
return;
|
|
270
282
|
case "SLH-DSA-SHA2-128s":
|
|
271
|
-
ReallyMeSlhDsa.
|
|
283
|
+
ReallyMeSlhDsa.verifyWithProvider(resolveWasmProvider(), algorithm, signature, message, publicKey);
|
|
272
284
|
return;
|
|
273
285
|
default:
|
|
274
286
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
275
287
|
}
|
|
276
288
|
},
|
|
277
289
|
verifyRsa(algorithm, signature, message, publicKeyDer, publicKeyEncoding) {
|
|
278
|
-
|
|
290
|
+
switch (algorithm) {
|
|
291
|
+
case "RSA-PKCS1v15-SHA1":
|
|
292
|
+
case "RSA-PKCS1v15-SHA256":
|
|
293
|
+
case "RSA-PKCS1v15-SHA384":
|
|
294
|
+
case "RSA-PKCS1v15-SHA512":
|
|
295
|
+
case "RSA-PSS-SHA1-MGF1-SHA1":
|
|
296
|
+
case "RSA-PSS-SHA256-MGF1-SHA256":
|
|
297
|
+
case "RSA-PSS-SHA384-MGF1-SHA384":
|
|
298
|
+
case "RSA-PSS-SHA512-MGF1-SHA512":
|
|
299
|
+
ReallyMeRsa.verifyWithProvider(resolveWasmProvider(), algorithm, signature, message, publicKeyDer, publicKeyEncoding);
|
|
300
|
+
return;
|
|
301
|
+
default:
|
|
302
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
303
|
+
}
|
|
279
304
|
},
|
|
280
305
|
deriveSharedSecret(algorithm, publicKey, secretKey) {
|
|
281
306
|
switch (algorithm) {
|
|
@@ -309,11 +334,24 @@ export const ReallyMeCrypto = {
|
|
|
309
334
|
switch (algorithm) {
|
|
310
335
|
case "X-Wing-768":
|
|
311
336
|
case "X-Wing-1024":
|
|
312
|
-
return ReallyMeXWing.
|
|
337
|
+
return ReallyMeXWing.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
|
|
313
338
|
case "ML-KEM-512":
|
|
314
339
|
case "ML-KEM-768":
|
|
315
340
|
case "ML-KEM-1024":
|
|
316
|
-
return ReallyMeMlKem.
|
|
341
|
+
return ReallyMeMlKem.generateKeyPairWithProvider(resolveWasmProvider(), algorithm);
|
|
342
|
+
default:
|
|
343
|
+
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
deriveKemKeyPair(algorithm, secretKey) {
|
|
347
|
+
switch (algorithm) {
|
|
348
|
+
case "X-Wing-768":
|
|
349
|
+
case "X-Wing-1024":
|
|
350
|
+
return ReallyMeXWing.deriveKeyPairWithProvider(resolveWasmProvider(), algorithm, secretKey);
|
|
351
|
+
case "ML-KEM-512":
|
|
352
|
+
case "ML-KEM-768":
|
|
353
|
+
case "ML-KEM-1024":
|
|
354
|
+
return ReallyMeMlKem.deriveKeyPairWithProvider(resolveWasmProvider(), algorithm, secretKey);
|
|
317
355
|
default:
|
|
318
356
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
319
357
|
}
|
|
@@ -322,11 +360,11 @@ export const ReallyMeCrypto = {
|
|
|
322
360
|
switch (algorithm) {
|
|
323
361
|
case "X-Wing-768":
|
|
324
362
|
case "X-Wing-1024":
|
|
325
|
-
return ReallyMeXWing.
|
|
363
|
+
return ReallyMeXWing.encapsulateWithProvider(resolveWasmProvider(), algorithm, publicKey);
|
|
326
364
|
case "ML-KEM-512":
|
|
327
365
|
case "ML-KEM-768":
|
|
328
366
|
case "ML-KEM-1024":
|
|
329
|
-
return ReallyMeMlKem.
|
|
367
|
+
return ReallyMeMlKem.encapsulateWithProvider(resolveWasmProvider(), algorithm, publicKey);
|
|
330
368
|
default:
|
|
331
369
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
332
370
|
}
|
|
@@ -335,11 +373,11 @@ export const ReallyMeCrypto = {
|
|
|
335
373
|
switch (algorithm) {
|
|
336
374
|
case "X-Wing-768":
|
|
337
375
|
case "X-Wing-1024":
|
|
338
|
-
return ReallyMeXWing.
|
|
376
|
+
return ReallyMeXWing.decapsulateWithProvider(resolveWasmProvider(), algorithm, ciphertext, secretKey);
|
|
339
377
|
case "ML-KEM-512":
|
|
340
378
|
case "ML-KEM-768":
|
|
341
379
|
case "ML-KEM-1024":
|
|
342
|
-
return ReallyMeMlKem.
|
|
380
|
+
return ReallyMeMlKem.decapsulateWithProvider(resolveWasmProvider(), algorithm, ciphertext, secretKey);
|
|
343
381
|
default:
|
|
344
382
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
345
383
|
}
|
|
@@ -348,7 +386,7 @@ export const ReallyMeCrypto = {
|
|
|
348
386
|
switch (suite) {
|
|
349
387
|
case "DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM":
|
|
350
388
|
case "DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305":
|
|
351
|
-
return ReallyMeHpke.
|
|
389
|
+
return ReallyMeHpke.sealBaseWithProvider(resolveWasmProvider(), suite, recipientPublicKey, info, aad, plaintext);
|
|
352
390
|
default:
|
|
353
391
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
354
392
|
}
|
|
@@ -357,9 +395,19 @@ export const ReallyMeCrypto = {
|
|
|
357
395
|
switch (suite) {
|
|
358
396
|
case "DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM":
|
|
359
397
|
case "DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305":
|
|
360
|
-
return ReallyMeHpke.
|
|
398
|
+
return ReallyMeHpke.openBaseWithProvider(resolveWasmProvider(), suite, recipientSecretKey, encapsulatedKey, info, aad, ciphertext);
|
|
361
399
|
default:
|
|
362
400
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
363
401
|
}
|
|
364
402
|
},
|
|
403
|
+
});
|
|
404
|
+
export const createReallyMeCrypto = (providers = {}) => {
|
|
405
|
+
const configuredProvider = providers.wasmProvider;
|
|
406
|
+
return createReallyMeCryptoFacade(() => {
|
|
407
|
+
if (configuredProvider === undefined) {
|
|
408
|
+
throw new ReallyMeCryptoError("provider-failure");
|
|
409
|
+
}
|
|
410
|
+
return configuredProvider;
|
|
411
|
+
});
|
|
365
412
|
};
|
|
413
|
+
export const ReallyMeCrypto = createReallyMeCryptoFacade(requireReallyMeWasmProvider);
|
package/dist/errors.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* user-provided bytes so callers can log them without leaking key material
|
|
4
4
|
* or PII.
|
|
5
5
|
*/
|
|
6
|
-
export type ReallyMeCryptoErrorCode = "invalid-input" | "invalid-signature" | "provider-failure" | "unsupported-algorithm";
|
|
6
|
+
export type ReallyMeCryptoErrorCode = "invalid-input" | "invalid-signature" | "authentication-failed" | "provider-failure" | "unsupported-algorithm";
|
|
7
7
|
export declare class ReallyMeCryptoError extends Error {
|
|
8
8
|
readonly code: ReallyMeCryptoErrorCode;
|
|
9
9
|
constructor(code: ReallyMeCryptoErrorCode);
|
package/dist/hpke.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ReallyMeHpkeSuite } from "./algorithms.js";
|
|
2
|
+
import type { ReallyMeWasmProvider } from "./wasmProvider.js";
|
|
2
3
|
export declare const HPKE_P256_PRIVATE_KEY_LENGTH = 32;
|
|
3
4
|
export declare const HPKE_P256_PUBLIC_KEY_LENGTH = 65;
|
|
4
5
|
export declare const HPKE_X25519_PRIVATE_KEY_LENGTH = 32;
|
|
@@ -10,6 +11,9 @@ export type ReallyMeHpkeSealedMessage = Readonly<{
|
|
|
10
11
|
}>;
|
|
11
12
|
export declare const ReallyMeHpke: {
|
|
12
13
|
readonly sealBase: (suite: ReallyMeHpkeSuite, recipientPublicKey: Uint8Array, info: Uint8Array, aad: Uint8Array, plaintext: Uint8Array) => ReallyMeHpkeSealedMessage;
|
|
14
|
+
readonly sealBaseWithProvider: (provider: ReallyMeWasmProvider, suite: ReallyMeHpkeSuite, recipientPublicKey: Uint8Array, info: Uint8Array, aad: Uint8Array, plaintext: Uint8Array) => ReallyMeHpkeSealedMessage;
|
|
13
15
|
readonly openBase: (suite: ReallyMeHpkeSuite, recipientSecretKey: Uint8Array, encapsulatedKey: Uint8Array, info: Uint8Array, aad: Uint8Array, ciphertext: Uint8Array) => Uint8Array;
|
|
16
|
+
readonly openBaseWithProvider: (provider: ReallyMeWasmProvider, suite: ReallyMeHpkeSuite, recipientSecretKey: Uint8Array, encapsulatedKey: Uint8Array, info: Uint8Array, aad: Uint8Array, ciphertext: Uint8Array) => Uint8Array;
|
|
14
17
|
};
|
|
15
18
|
export declare const sealHpkeBaseDeterministicallyForTest: (suite: ReallyMeHpkeSuite, recipientPublicKey: Uint8Array, encapsulationRandomness: Uint8Array, info: Uint8Array, aad: Uint8Array, plaintext: Uint8Array) => ReallyMeHpkeSealedMessage;
|
|
19
|
+
export declare const sealHpkeBaseDeterministicallyWithProviderForTest: (provider: ReallyMeWasmProvider, suite: ReallyMeHpkeSuite, recipientPublicKey: Uint8Array, encapsulationRandomness: Uint8Array, info: Uint8Array, aad: Uint8Array, plaintext: Uint8Array) => ReallyMeHpkeSealedMessage;
|
package/dist/hpke.js
CHANGED
|
@@ -41,6 +41,11 @@ export const ReallyMeHpke = {
|
|
|
41
41
|
ensureBytes(recipientPublicKey, config.publicKeyLength);
|
|
42
42
|
return readSealedMessage(requireReallyMeWasmProvider().hpkeSealBase(config.id, recipientPublicKey, info, aad, plaintext), config, plaintext.length);
|
|
43
43
|
},
|
|
44
|
+
sealBaseWithProvider(provider, suite, recipientPublicKey, info, aad, plaintext) {
|
|
45
|
+
const config = hpkeSuite(suite);
|
|
46
|
+
ensureBytes(recipientPublicKey, config.publicKeyLength);
|
|
47
|
+
return readSealedMessage(provider.hpkeSealBase(config.id, recipientPublicKey, info, aad, plaintext), config, plaintext.length);
|
|
48
|
+
},
|
|
44
49
|
openBase(suite, recipientSecretKey, encapsulatedKey, info, aad, ciphertext) {
|
|
45
50
|
const config = hpkeSuite(suite);
|
|
46
51
|
ensureBytes(recipientSecretKey, config.privateKeyLength);
|
|
@@ -50,6 +55,15 @@ export const ReallyMeHpke = {
|
|
|
50
55
|
}
|
|
51
56
|
return requirePlaintext(requireReallyMeWasmProvider().hpkeOpenBase(config.id, recipientSecretKey, encapsulatedKey, info, aad, ciphertext));
|
|
52
57
|
},
|
|
58
|
+
openBaseWithProvider(provider, suite, recipientSecretKey, encapsulatedKey, info, aad, ciphertext) {
|
|
59
|
+
const config = hpkeSuite(suite);
|
|
60
|
+
ensureBytes(recipientSecretKey, config.privateKeyLength);
|
|
61
|
+
ensureBytes(encapsulatedKey, config.publicKeyLength);
|
|
62
|
+
if (ciphertext.length < HPKE_AEAD_TAG_LENGTH) {
|
|
63
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
64
|
+
}
|
|
65
|
+
return requirePlaintext(provider.hpkeOpenBase(config.id, recipientSecretKey, encapsulatedKey, info, aad, ciphertext));
|
|
66
|
+
},
|
|
53
67
|
};
|
|
54
68
|
export const sealHpkeBaseDeterministicallyForTest = (suite, recipientPublicKey, encapsulationRandomness, info, aad, plaintext) => {
|
|
55
69
|
const config = hpkeSuite(suite);
|
|
@@ -57,3 +71,9 @@ export const sealHpkeBaseDeterministicallyForTest = (suite, recipientPublicKey,
|
|
|
57
71
|
ensureBytes(encapsulationRandomness, config.privateKeyLength);
|
|
58
72
|
return readSealedMessage(requireReallyMeWasmProvider().hpkeSealBaseDerand(config.id, recipientPublicKey, encapsulationRandomness, info, aad, plaintext), config, plaintext.length);
|
|
59
73
|
};
|
|
74
|
+
export const sealHpkeBaseDeterministicallyWithProviderForTest = (provider, suite, recipientPublicKey, encapsulationRandomness, info, aad, plaintext) => {
|
|
75
|
+
const config = hpkeSuite(suite);
|
|
76
|
+
ensureBytes(recipientPublicKey, config.publicKeyLength);
|
|
77
|
+
ensureBytes(encapsulationRandomness, config.privateKeyLength);
|
|
78
|
+
return readSealedMessage(provider.hpkeSealBaseDerand(config.id, recipientPublicKey, encapsulationRandomness, info, aad, plaintext), config, plaintext.length);
|
|
79
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -2,14 +2,12 @@ export { ReallyMeCryptoError } from "./errors.js";
|
|
|
2
2
|
export type { ReallyMeCryptoErrorCode } from "./errors.js";
|
|
3
3
|
export { REALLYME_AEAD_ALGORITHMS, REALLYME_HASH_ALGORITHMS, REALLYME_HPKE_SUITES, REALLYME_KDF_ALGORITHMS, REALLYME_KEM_ALGORITHMS, REALLYME_KEY_AGREEMENT_ALGORITHMS, REALLYME_KEY_WRAP_ALGORITHMS, REALLYME_MAC_ALGORITHMS, REALLYME_SIGNATURE_ALGORITHMS, } from "./algorithms.js";
|
|
4
4
|
export type { ReallyMeAeadAlgorithm, ReallyMeHashAlgorithm, ReallyMeHpkeSuite, ReallyMeKdfAlgorithm, ReallyMeKemAlgorithm, ReallyMeKeyAgreementAlgorithm, ReallyMeKeyWrapAlgorithm, ReallyMeMacAlgorithm, ReallyMeSignatureAlgorithm, } from "./algorithms.js";
|
|
5
|
-
export { AEAD_KEY_LENGTH, AEAD_NONCE_LENGTH, AEAD_TAG_LENGTH, AES_128_GCM_KEY_LENGTH, AES_192_GCM_KEY_LENGTH, AES_256_GCM_KEY_LENGTH, ReallyMeAead, XCHACHA20_POLY1305_NONCE_LENGTH, } from "./aead.js";
|
|
5
|
+
export { AEAD_KEY_LENGTH, AEAD_NONCE_LENGTH, AEAD_TAG_LENGTH, AES_128_GCM_KEY_LENGTH, AES_192_GCM_KEY_LENGTH, AES_256_GCM_KEY_LENGTH, CHACHA20_POLY1305_KEY_LENGTH, ReallyMeAead, XCHACHA20_POLY1305_NONCE_LENGTH, } from "./aead.js";
|
|
6
6
|
export { AES_256_KW_KEK_LENGTH, AES_KW_BLOCK_LENGTH, AES_KW_INTEGRITY_CHECK_LENGTH, AES_KW_MAX_KEY_DATA_LENGTH, AES_KW_MIN_KEY_DATA_LENGTH, AES_KW_MIN_WRAPPED_KEY_LENGTH, ReallyMeAesKw, } from "./aesKw.js";
|
|
7
7
|
export { ARGON2ID_DERIVED_KEY_LENGTH, ARGON2ID_SALT_MAX_LENGTH, ARGON2ID_SALT_MIN_LENGTH, ARGON2ID_V1, ARGON2ID_V2, ReallyMeArgon2id, } from "./argon2id.js";
|
|
8
8
|
export { BIP340_SCHNORR_AUX_RAND_LENGTH, BIP340_SCHNORR_MESSAGE_LENGTH, BIP340_SCHNORR_PUBLIC_KEY_LENGTH, BIP340_SCHNORR_SECRET_KEY_LENGTH, BIP340_SCHNORR_SIGNATURE_LENGTH, ReallyMeBip340Schnorr, } from "./bip340Schnorr.js";
|
|
9
9
|
export { HPKE_AEAD_TAG_LENGTH, HPKE_P256_PRIVATE_KEY_LENGTH, HPKE_P256_PUBLIC_KEY_LENGTH, HPKE_X25519_PRIVATE_KEY_LENGTH, HPKE_X25519_PUBLIC_KEY_LENGTH, ReallyMeHpke, } from "./hpke.js";
|
|
10
10
|
export type { ReallyMeHpkeSealedMessage as ReallyMeHpkeProviderSealedMessage } from "./hpke.js";
|
|
11
|
-
export { ReallyMeCodecs } from "./codecs.js";
|
|
12
|
-
export type { ReallyMeDagCborCidVerification, ReallyMeKeyMaterialKind, ReallyMeMulticodecMetadata, ReallyMeMulticodecTag, ReallyMeParsedMultikey, } from "./codecs.js";
|
|
13
11
|
export { ReallyMeJwk } from "./jwk.js";
|
|
14
12
|
export type { ReallyMeAkpJwk, ReallyMeEcJwk, ReallyMeJwk as ReallyMeJsonWebKey, ReallyMeJwkAlgorithm, ReallyMeJwkKey, ReallyMeJwks, ReallyMeJwksKeySet, ReallyMeOkpJwk, } from "./jwk.js";
|
|
15
13
|
export { ML_KEM_1024_CIPHERTEXT_LENGTH, ML_KEM_1024_PUBLIC_KEY_LENGTH, ML_KEM_512_CIPHERTEXT_LENGTH, ML_KEM_512_PUBLIC_KEY_LENGTH, ML_KEM_768_CIPHERTEXT_LENGTH, ML_KEM_768_PUBLIC_KEY_LENGTH, ML_KEM_ENCAPSULATION_RANDOMNESS_LENGTH, ML_KEM_SECRET_KEY_LENGTH, ML_KEM_SHARED_SECRET_LENGTH, ReallyMeMlKem, } from "./mlKem.js";
|
|
@@ -20,12 +18,13 @@ export { ReallyMeSlhDsa, SLH_DSA_SHA2_128S_KEYGEN_SEED_LENGTH, SLH_DSA_SHA2_128S
|
|
|
20
18
|
export type { ReallyMeSlhDsaKeyPair } from "./slhDsa.js";
|
|
21
19
|
export { compiledProviders, REALLYME_CRYPTO_PROVIDERS } from "./providerCatalog.js";
|
|
22
20
|
export type { ReallyMeCryptoProvider } from "./providerCatalog.js";
|
|
23
|
-
export { ReallyMeCrypto } from "./cryptoFacade.js";
|
|
24
|
-
export type { ReallyMeHpkeSealedMessage, ReallyMeKeyAgreementKeyPair, ReallyMeKemEncapsulation, ReallyMeKemKeyPair, ReallyMeSignatureKeyPair, } from "./cryptoFacade.js";
|
|
21
|
+
export { createReallyMeCrypto, ReallyMeCrypto } from "./cryptoFacade.js";
|
|
22
|
+
export type { ReallyMeCryptoFacade, ReallyMeCryptoProviders, ReallyMeHpkeSealedMessage, ReallyMeKeyAgreementKeyPair, ReallyMeKemEncapsulation, ReallyMeKemKeyPair, ReallyMeSignatureKeyPair, } from "./cryptoFacade.js";
|
|
25
23
|
export { ReallyMeDigest } from "./digest.js";
|
|
26
24
|
export { ED25519_PUBLIC_KEY_LENGTH, ED25519_SECRET_KEY_LENGTH, ED25519_SIGNATURE_LENGTH, ReallyMeEd25519, } from "./ed25519.js";
|
|
27
25
|
export { HKDF_MAX_INPUT_LENGTH, HKDF_MAX_OUTPUT_LENGTH, HKDF_MIN_INPUT_KEY_MATERIAL_LENGTH, HKDF_MIN_OUTPUT_LENGTH, ReallyMeHkdf, } from "./hkdf.js";
|
|
28
26
|
export { JWA_CONCAT_KDF_MAX_INFO_LENGTH, JWA_CONCAT_KDF_MAX_OUTPUT_LENGTH, JWA_CONCAT_KDF_MAX_SHARED_SECRET_LENGTH, JWA_CONCAT_KDF_MIN_OUTPUT_LENGTH, JWA_CONCAT_KDF_SHA256_DIGEST_LENGTH, ReallyMeJwaConcatKdf, } from "./jwaConcatKdf.js";
|
|
27
|
+
export { bestEffortClear } from "./memory.js";
|
|
29
28
|
export { HMAC_MAX_KEY_LENGTH, HMAC_SHA256_TAG_LENGTH, HMAC_SHA512_TAG_LENGTH, ReallyMeHmac, } from "./hmac.js";
|
|
30
29
|
export { P256_ECDH_COMPRESSED_PUBLIC_KEY_LENGTH, P256_ECDH_SECRET_KEY_LENGTH, P256_ECDH_SHARED_SECRET_LENGTH, ReallyMeP256Ecdh, } from "./p256Ecdh.js";
|
|
31
30
|
export { P256_ECDSA_COMPACT_SIGNATURE_LENGTH, P256_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH, P256_ECDSA_DER_SIGNATURE_MAX_LENGTH, P256_ECDSA_SECRET_KEY_LENGTH, ReallyMeP256Ecdsa, } from "./p256Ecdsa.js";
|
|
@@ -38,7 +37,7 @@ export { ReallyMeSecp256k1, SECP256K1_COMPRESSED_PUBLIC_KEY_LENGTH, SECP256K1_SE
|
|
|
38
37
|
export { ReallyMeRsa, RSA_PUBLIC_KEY_DER_MAX_LENGTH, RSA_SIGNATURE_MAX_LENGTH, } from "./rsa.js";
|
|
39
38
|
export type { ReallyMeRsaPublicKeyDerEncoding } from "./rsa.js";
|
|
40
39
|
export { ReallyMeX25519, X25519_PUBLIC_KEY_LENGTH, X25519_SECRET_KEY_LENGTH, X25519_SHARED_SECRET_LENGTH, } from "./x25519.js";
|
|
41
|
-
export { installReallyMeWasmProvider } from "./wasmProvider.js";
|
|
40
|
+
export { createReallyMeWasmProvider, installReallyMeWasmProvider } from "./wasmProvider.js";
|
|
42
41
|
export type { ReallyMeWasmProvider } from "./wasmProvider.js";
|
|
43
42
|
export { ReallyMeXWing, X_WING_1024_CIPHERTEXT_LENGTH, X_WING_1024_PUBLIC_KEY_LENGTH, X_WING_768_CIPHERTEXT_LENGTH, X_WING_768_PUBLIC_KEY_LENGTH, X_WING_ENCAPSULATION_SEED_LENGTH, X_WING_SECRET_KEY_LENGTH, X_WING_SHARED_SECRET_LENGTH, } from "./xWing.js";
|
|
44
43
|
export type { ReallyMeXWingEncapsulation, ReallyMeXWingKeyPair } from "./xWing.js";
|
package/dist/index.js
CHANGED
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
export { ReallyMeCryptoError } from "./errors.js";
|
|
5
5
|
export { REALLYME_AEAD_ALGORITHMS, REALLYME_HASH_ALGORITHMS, REALLYME_HPKE_SUITES, REALLYME_KDF_ALGORITHMS, REALLYME_KEM_ALGORITHMS, REALLYME_KEY_AGREEMENT_ALGORITHMS, REALLYME_KEY_WRAP_ALGORITHMS, REALLYME_MAC_ALGORITHMS, REALLYME_SIGNATURE_ALGORITHMS, } from "./algorithms.js";
|
|
6
|
-
export { AEAD_KEY_LENGTH, AEAD_NONCE_LENGTH, AEAD_TAG_LENGTH, AES_128_GCM_KEY_LENGTH, AES_192_GCM_KEY_LENGTH, AES_256_GCM_KEY_LENGTH, ReallyMeAead, XCHACHA20_POLY1305_NONCE_LENGTH, } from "./aead.js";
|
|
6
|
+
export { AEAD_KEY_LENGTH, AEAD_NONCE_LENGTH, AEAD_TAG_LENGTH, AES_128_GCM_KEY_LENGTH, AES_192_GCM_KEY_LENGTH, AES_256_GCM_KEY_LENGTH, CHACHA20_POLY1305_KEY_LENGTH, ReallyMeAead, XCHACHA20_POLY1305_NONCE_LENGTH, } from "./aead.js";
|
|
7
7
|
export { AES_256_KW_KEK_LENGTH, AES_KW_BLOCK_LENGTH, AES_KW_INTEGRITY_CHECK_LENGTH, AES_KW_MAX_KEY_DATA_LENGTH, AES_KW_MIN_KEY_DATA_LENGTH, AES_KW_MIN_WRAPPED_KEY_LENGTH, ReallyMeAesKw, } from "./aesKw.js";
|
|
8
8
|
export { ARGON2ID_DERIVED_KEY_LENGTH, ARGON2ID_SALT_MAX_LENGTH, ARGON2ID_SALT_MIN_LENGTH, ARGON2ID_V1, ARGON2ID_V2, ReallyMeArgon2id, } from "./argon2id.js";
|
|
9
9
|
export { BIP340_SCHNORR_AUX_RAND_LENGTH, BIP340_SCHNORR_MESSAGE_LENGTH, BIP340_SCHNORR_PUBLIC_KEY_LENGTH, BIP340_SCHNORR_SECRET_KEY_LENGTH, BIP340_SCHNORR_SIGNATURE_LENGTH, ReallyMeBip340Schnorr, } from "./bip340Schnorr.js";
|
|
10
10
|
export { HPKE_AEAD_TAG_LENGTH, HPKE_P256_PRIVATE_KEY_LENGTH, HPKE_P256_PUBLIC_KEY_LENGTH, HPKE_X25519_PRIVATE_KEY_LENGTH, HPKE_X25519_PUBLIC_KEY_LENGTH, ReallyMeHpke, } from "./hpke.js";
|
|
11
|
-
export { ReallyMeCodecs } from "./codecs.js";
|
|
12
11
|
export { ReallyMeJwk } from "./jwk.js";
|
|
13
12
|
export { ML_KEM_1024_CIPHERTEXT_LENGTH, ML_KEM_1024_PUBLIC_KEY_LENGTH, ML_KEM_512_CIPHERTEXT_LENGTH, ML_KEM_512_PUBLIC_KEY_LENGTH, ML_KEM_768_CIPHERTEXT_LENGTH, ML_KEM_768_PUBLIC_KEY_LENGTH, ML_KEM_ENCAPSULATION_RANDOMNESS_LENGTH, ML_KEM_SECRET_KEY_LENGTH, ML_KEM_SHARED_SECRET_LENGTH, ReallyMeMlKem, } from "./mlKem.js";
|
|
14
13
|
export { ML_DSA_44_PUBLIC_KEY_LENGTH, ML_DSA_44_SIGNATURE_LENGTH, ML_DSA_65_PUBLIC_KEY_LENGTH, ML_DSA_65_SIGNATURE_LENGTH, ML_DSA_87_PUBLIC_KEY_LENGTH, ML_DSA_87_SIGNATURE_LENGTH, ML_DSA_SECRET_KEY_LENGTH, ReallyMeMlDsa, } from "./mlDsa.js";
|
|
15
14
|
export { ReallyMeSlhDsa, SLH_DSA_SHA2_128S_KEYGEN_SEED_LENGTH, SLH_DSA_SHA2_128S_PUBLIC_KEY_LENGTH, SLH_DSA_SHA2_128S_SECRET_KEY_LENGTH, SLH_DSA_SHA2_128S_SIGNATURE_LENGTH, } from "./slhDsa.js";
|
|
16
15
|
export { compiledProviders, REALLYME_CRYPTO_PROVIDERS } from "./providerCatalog.js";
|
|
17
|
-
export { ReallyMeCrypto } from "./cryptoFacade.js";
|
|
16
|
+
export { createReallyMeCrypto, ReallyMeCrypto } from "./cryptoFacade.js";
|
|
18
17
|
export { ReallyMeDigest } from "./digest.js";
|
|
19
18
|
export { ED25519_PUBLIC_KEY_LENGTH, ED25519_SECRET_KEY_LENGTH, ED25519_SIGNATURE_LENGTH, ReallyMeEd25519, } from "./ed25519.js";
|
|
20
19
|
export { HKDF_MAX_INPUT_LENGTH, HKDF_MAX_OUTPUT_LENGTH, HKDF_MIN_INPUT_KEY_MATERIAL_LENGTH, HKDF_MIN_OUTPUT_LENGTH, ReallyMeHkdf, } from "./hkdf.js";
|
|
21
20
|
export { JWA_CONCAT_KDF_MAX_INFO_LENGTH, JWA_CONCAT_KDF_MAX_OUTPUT_LENGTH, JWA_CONCAT_KDF_MAX_SHARED_SECRET_LENGTH, JWA_CONCAT_KDF_MIN_OUTPUT_LENGTH, JWA_CONCAT_KDF_SHA256_DIGEST_LENGTH, ReallyMeJwaConcatKdf, } from "./jwaConcatKdf.js";
|
|
21
|
+
export { bestEffortClear } from "./memory.js";
|
|
22
22
|
export { HMAC_MAX_KEY_LENGTH, HMAC_SHA256_TAG_LENGTH, HMAC_SHA512_TAG_LENGTH, ReallyMeHmac, } from "./hmac.js";
|
|
23
23
|
export { P256_ECDH_COMPRESSED_PUBLIC_KEY_LENGTH, P256_ECDH_SECRET_KEY_LENGTH, P256_ECDH_SHARED_SECRET_LENGTH, ReallyMeP256Ecdh, } from "./p256Ecdh.js";
|
|
24
24
|
export { P256_ECDSA_COMPACT_SIGNATURE_LENGTH, P256_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH, P256_ECDSA_DER_SIGNATURE_MAX_LENGTH, P256_ECDSA_SECRET_KEY_LENGTH, ReallyMeP256Ecdsa, } from "./p256Ecdsa.js";
|
|
@@ -30,5 +30,5 @@ export { PBKDF2_MAX_INPUT_LENGTH, PBKDF2_MAX_OUTPUT_LENGTH, PBKDF2_MIN_INPUT_LEN
|
|
|
30
30
|
export { ReallyMeSecp256k1, SECP256K1_COMPRESSED_PUBLIC_KEY_LENGTH, SECP256K1_SECRET_KEY_LENGTH, SECP256K1_SIGNATURE_LENGTH, } from "./secp256k1.js";
|
|
31
31
|
export { ReallyMeRsa, RSA_PUBLIC_KEY_DER_MAX_LENGTH, RSA_SIGNATURE_MAX_LENGTH, } from "./rsa.js";
|
|
32
32
|
export { ReallyMeX25519, X25519_PUBLIC_KEY_LENGTH, X25519_SECRET_KEY_LENGTH, X25519_SHARED_SECRET_LENGTH, } from "./x25519.js";
|
|
33
|
-
export { installReallyMeWasmProvider } from "./wasmProvider.js";
|
|
33
|
+
export { createReallyMeWasmProvider, installReallyMeWasmProvider } from "./wasmProvider.js";
|
|
34
34
|
export { ReallyMeXWing, X_WING_1024_CIPHERTEXT_LENGTH, X_WING_1024_PUBLIC_KEY_LENGTH, X_WING_768_CIPHERTEXT_LENGTH, X_WING_768_PUBLIC_KEY_LENGTH, X_WING_ENCAPSULATION_SEED_LENGTH, X_WING_SECRET_KEY_LENGTH, X_WING_SHARED_SECRET_LENGTH, } from "./xWing.js";
|
package/dist/jwaConcatKdf.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
5
5
|
import { ReallyMeCryptoError } from "./errors.js";
|
|
6
|
+
import { bestEffortClear } from "./memory.js";
|
|
6
7
|
export const JWA_CONCAT_KDF_SHA256_DIGEST_LENGTH = 32;
|
|
7
8
|
export const JWA_CONCAT_KDF_MAX_SHARED_SECRET_LENGTH = 4096;
|
|
8
9
|
export const JWA_CONCAT_KDF_MAX_INFO_LENGTH = 4096;
|
|
@@ -17,13 +18,16 @@ export const ReallyMeJwaConcatKdf = {
|
|
|
17
18
|
const derived = new Uint8Array(reps * JWA_CONCAT_KDF_SHA256_DIGEST_LENGTH);
|
|
18
19
|
for (let counter = 1; counter <= reps; counter += 1) {
|
|
19
20
|
const counterBytes = uint32be(counter);
|
|
20
|
-
const
|
|
21
|
+
const hashInput = concatBytes(counterBytes, sharedSecret, otherInfo);
|
|
22
|
+
const digest = sha256(hashInput);
|
|
21
23
|
derived.set(digest, (counter - 1) * JWA_CONCAT_KDF_SHA256_DIGEST_LENGTH);
|
|
22
|
-
|
|
24
|
+
bestEffortClear(digest);
|
|
25
|
+
bestEffortClear(hashInput);
|
|
26
|
+
bestEffortClear(counterBytes);
|
|
23
27
|
}
|
|
24
28
|
const output = derived.slice(0, outputLength);
|
|
25
|
-
derived
|
|
26
|
-
otherInfo
|
|
29
|
+
bestEffortClear(derived);
|
|
30
|
+
bestEffortClear(otherInfo);
|
|
27
31
|
return output;
|
|
28
32
|
},
|
|
29
33
|
};
|
package/dist/jwk.js
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { p256 } from "@noble/curves/nist.js";
|
|
5
5
|
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
6
|
+
import { base64urlDecode as codecBase64urlDecodeValue, base64urlEncode as codecBase64urlEncodeValue, canonicalizeJson as codecCanonicalizeJson, ReallyMeCodecError, } from "@reallyme/codec";
|
|
6
7
|
import { ReallyMeCryptoError } from "./errors.js";
|
|
7
|
-
const BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
8
|
-
const DECODE_TABLE = new Map([...BASE64URL_ALPHABET].map((char, index) => [char, index]));
|
|
9
8
|
const jwkSpec = (algorithm) => {
|
|
10
9
|
switch (algorithm) {
|
|
11
10
|
case "Ed25519":
|
|
@@ -41,63 +40,6 @@ const ensureLength = (bytes, expectedLength) => {
|
|
|
41
40
|
throw new ReallyMeCryptoError("invalid-input");
|
|
42
41
|
}
|
|
43
42
|
};
|
|
44
|
-
const byteAt = (bytes, index) => {
|
|
45
|
-
const value = bytes[index];
|
|
46
|
-
if (value === undefined) {
|
|
47
|
-
throw new ReallyMeCryptoError("invalid-input");
|
|
48
|
-
}
|
|
49
|
-
return value;
|
|
50
|
-
};
|
|
51
|
-
const base64urlEncode = (bytes) => {
|
|
52
|
-
let encoded = "";
|
|
53
|
-
let index = 0;
|
|
54
|
-
while (index < bytes.length) {
|
|
55
|
-
const first = byteAt(bytes, index);
|
|
56
|
-
const second = index + 1 < bytes.length ? byteAt(bytes, index + 1) : 0;
|
|
57
|
-
const third = index + 2 < bytes.length ? byteAt(bytes, index + 2) : 0;
|
|
58
|
-
const triple = (first << 16) | (second << 8) | third;
|
|
59
|
-
encoded += BASE64URL_ALPHABET[(triple >> 18) & 0x3f];
|
|
60
|
-
encoded += BASE64URL_ALPHABET[(triple >> 12) & 0x3f];
|
|
61
|
-
if (index + 1 < bytes.length) {
|
|
62
|
-
encoded += BASE64URL_ALPHABET[(triple >> 6) & 0x3f];
|
|
63
|
-
}
|
|
64
|
-
if (index + 2 < bytes.length) {
|
|
65
|
-
encoded += BASE64URL_ALPHABET[triple & 0x3f];
|
|
66
|
-
}
|
|
67
|
-
index += 3;
|
|
68
|
-
}
|
|
69
|
-
return encoded;
|
|
70
|
-
};
|
|
71
|
-
const decodeChar = (char) => {
|
|
72
|
-
const value = DECODE_TABLE.get(char);
|
|
73
|
-
if (value === undefined) {
|
|
74
|
-
throw new ReallyMeCryptoError("invalid-input");
|
|
75
|
-
}
|
|
76
|
-
return value;
|
|
77
|
-
};
|
|
78
|
-
const base64urlDecode = (encoded) => {
|
|
79
|
-
if (encoded.length % 4 === 1) {
|
|
80
|
-
throw new ReallyMeCryptoError("invalid-input");
|
|
81
|
-
}
|
|
82
|
-
const outputLength = Math.floor((encoded.length * 6) / 8);
|
|
83
|
-
const output = new Uint8Array(outputLength);
|
|
84
|
-
let buffer = 0;
|
|
85
|
-
let bits = 0;
|
|
86
|
-
let offset = 0;
|
|
87
|
-
for (const char of encoded) {
|
|
88
|
-
buffer = (buffer << 6) | decodeChar(char);
|
|
89
|
-
bits += 6;
|
|
90
|
-
if (bits >= 8) {
|
|
91
|
-
bits -= 8;
|
|
92
|
-
output[offset] = (buffer >> bits) & 0xff;
|
|
93
|
-
offset += 1;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (offset !== output.length) {
|
|
97
|
-
throw new ReallyMeCryptoError("invalid-input");
|
|
98
|
-
}
|
|
99
|
-
return output;
|
|
100
|
-
};
|
|
101
43
|
const readString = (value, name) => {
|
|
102
44
|
if (typeof value !== "object" || value === null) {
|
|
103
45
|
throw new ReallyMeCryptoError("invalid-input");
|
|
@@ -108,6 +50,29 @@ const readString = (value, name) => {
|
|
|
108
50
|
}
|
|
109
51
|
return property;
|
|
110
52
|
};
|
|
53
|
+
const privateJwkMemberNames = [
|
|
54
|
+
"d",
|
|
55
|
+
"p",
|
|
56
|
+
"q",
|
|
57
|
+
"dp",
|
|
58
|
+
"dq",
|
|
59
|
+
"qi",
|
|
60
|
+
"oth",
|
|
61
|
+
"k",
|
|
62
|
+
"priv",
|
|
63
|
+
"privateKey",
|
|
64
|
+
"secretKey",
|
|
65
|
+
];
|
|
66
|
+
const rejectPrivateKeyMaterial = (value) => {
|
|
67
|
+
if (typeof value !== "object" || value === null) {
|
|
68
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
69
|
+
}
|
|
70
|
+
for (const name of privateJwkMemberNames) {
|
|
71
|
+
if (Reflect.has(value, name)) {
|
|
72
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
111
76
|
const optionalStringMatches = (value, name, expected) => {
|
|
112
77
|
if (typeof value !== "object" || value === null) {
|
|
113
78
|
throw new ReallyMeCryptoError("invalid-input");
|
|
@@ -172,14 +137,43 @@ const compressEc = (algorithm, x, y) => {
|
|
|
172
137
|
throw new ReallyMeCryptoError("invalid-input");
|
|
173
138
|
}
|
|
174
139
|
};
|
|
140
|
+
const mapCodecError = (error) => {
|
|
141
|
+
if (error instanceof ReallyMeCodecError && error.code === "provider-failure") {
|
|
142
|
+
return new ReallyMeCryptoError("provider-failure");
|
|
143
|
+
}
|
|
144
|
+
return new ReallyMeCryptoError("invalid-input");
|
|
145
|
+
};
|
|
146
|
+
const codecBase64urlEncode = (bytes) => {
|
|
147
|
+
try {
|
|
148
|
+
return codecBase64urlEncodeValue(bytes);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
throw mapCodecError(error);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const codecBase64urlDecode = (encoded) => {
|
|
155
|
+
try {
|
|
156
|
+
return codecBase64urlDecodeValue(encoded);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
throw mapCodecError(error);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const codecBase64urlDecodeCanonical = (encoded) => {
|
|
163
|
+
const bytes = codecBase64urlDecode(encoded);
|
|
164
|
+
if (codecBase64urlEncode(bytes) !== encoded) {
|
|
165
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
166
|
+
}
|
|
167
|
+
return bytes;
|
|
168
|
+
};
|
|
175
169
|
const toJcs = (jwk) => {
|
|
176
|
-
|
|
177
|
-
|
|
170
|
+
const key = ReallyMeJwk.fromJwk(jwk);
|
|
171
|
+
try {
|
|
172
|
+
return codecCanonicalizeJson(key.jwk);
|
|
178
173
|
}
|
|
179
|
-
|
|
180
|
-
|
|
174
|
+
catch (error) {
|
|
175
|
+
throw mapCodecError(error);
|
|
181
176
|
}
|
|
182
|
-
return `{"alg":${JSON.stringify(jwk.alg)},"crv":${JSON.stringify(jwk.crv)},"kty":"OKP","use":${JSON.stringify(jwk.use)},"x":${JSON.stringify(jwk.x)}}`;
|
|
183
177
|
};
|
|
184
178
|
export const ReallyMeJwk = {
|
|
185
179
|
toJwk(algorithm, publicKey) {
|
|
@@ -193,15 +187,15 @@ export const ReallyMeJwk = {
|
|
|
193
187
|
crv: ecAlgorithm,
|
|
194
188
|
kty: "EC",
|
|
195
189
|
use: "sig",
|
|
196
|
-
x:
|
|
197
|
-
y:
|
|
190
|
+
x: codecBase64urlEncode(uncompressed.slice(1, 33)),
|
|
191
|
+
y: codecBase64urlEncode(uncompressed.slice(33, 65)),
|
|
198
192
|
};
|
|
199
193
|
}
|
|
200
194
|
if (spec.kty === "AKP") {
|
|
201
195
|
return {
|
|
202
196
|
alg: spec.alg,
|
|
203
197
|
kty: "AKP",
|
|
204
|
-
pub:
|
|
198
|
+
pub: codecBase64urlEncode(publicKey),
|
|
205
199
|
use: spec.use,
|
|
206
200
|
};
|
|
207
201
|
}
|
|
@@ -214,10 +208,11 @@ export const ReallyMeJwk = {
|
|
|
214
208
|
crv,
|
|
215
209
|
kty: "OKP",
|
|
216
210
|
use: spec.use,
|
|
217
|
-
x:
|
|
211
|
+
x: codecBase64urlEncode(publicKey),
|
|
218
212
|
};
|
|
219
213
|
},
|
|
220
214
|
fromJwk(value) {
|
|
215
|
+
rejectPrivateKeyMaterial(value);
|
|
221
216
|
const kty = readString(value, "kty");
|
|
222
217
|
const spec = kty === "AKP"
|
|
223
218
|
? specFromAlgorithm(readString(value, "alg"))
|
|
@@ -229,8 +224,8 @@ export const ReallyMeJwk = {
|
|
|
229
224
|
optionalStringMatches(value, "use", spec.use);
|
|
230
225
|
if (spec.kty === "EC") {
|
|
231
226
|
const ecAlgorithm = spec.crv === "P-256" ? "P-256" : "secp256k1";
|
|
232
|
-
const x =
|
|
233
|
-
const y =
|
|
227
|
+
const x = codecBase64urlDecodeCanonical(readString(value, "x"));
|
|
228
|
+
const y = codecBase64urlDecodeCanonical(readString(value, "y"));
|
|
234
229
|
const publicKey = compressEc(ecAlgorithm, x, y);
|
|
235
230
|
ensureLength(publicKey, spec.publicKeyLength);
|
|
236
231
|
const jwk = ReallyMeJwk.toJwk(ecAlgorithm, publicKey);
|
|
@@ -241,14 +236,14 @@ export const ReallyMeJwk = {
|
|
|
241
236
|
if (crv !== "Ed25519" && crv !== "X25519") {
|
|
242
237
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
243
238
|
}
|
|
244
|
-
const publicKey =
|
|
239
|
+
const publicKey = codecBase64urlDecodeCanonical(readString(value, "x"));
|
|
245
240
|
ensureLength(publicKey, spec.publicKeyLength);
|
|
246
241
|
const jwk = ReallyMeJwk.toJwk(crv, publicKey);
|
|
247
242
|
return { algorithm: crv, publicKey, jwk };
|
|
248
243
|
}
|
|
249
244
|
const algorithm = readString(value, "alg");
|
|
250
245
|
const akpSpec = specFromAlgorithm(algorithm);
|
|
251
|
-
const publicKey =
|
|
246
|
+
const publicKey = codecBase64urlDecodeCanonical(readString(value, "pub"));
|
|
252
247
|
ensureLength(publicKey, akpSpec.publicKeyLength);
|
|
253
248
|
switch (algorithm) {
|
|
254
249
|
case "ML-DSA-44":
|
package/dist/memory.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Best-effort cleanup for caller-owned managed-runtime byte arrays.
|
|
3
|
+
*
|
|
4
|
+
* This overwrites the supplied `Uint8Array` view in place. It does not and
|
|
5
|
+
* cannot clear copies already made by JavaScript engines, WebAssembly
|
|
6
|
+
* marshalling, snapshots, browser developer tools, or native providers.
|
|
7
|
+
*/
|
|
8
|
+
export declare const bestEffortClear: (bytes: Uint8Array) => void;
|
package/dist/memory.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
/**
|
|
5
|
+
* Best-effort cleanup for caller-owned managed-runtime byte arrays.
|
|
6
|
+
*
|
|
7
|
+
* This overwrites the supplied `Uint8Array` view in place. It does not and
|
|
8
|
+
* cannot clear copies already made by JavaScript engines, WebAssembly
|
|
9
|
+
* marshalling, snapshots, browser developer tools, or native providers.
|
|
10
|
+
*/
|
|
11
|
+
export const bestEffortClear = (bytes) => {
|
|
12
|
+
bytes.fill(0);
|
|
13
|
+
};
|