leviathan-crypto 2.0.1 → 3.0.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/CLAUDE.md +88 -281
- package/LICENSE +4 -0
- package/README.md +275 -87
- package/dist/aes/aes-cbc.d.ts +40 -0
- package/dist/aes/aes-cbc.js +158 -0
- package/dist/aes/aes-ctr.d.ts +50 -0
- package/dist/aes/aes-ctr.js +141 -0
- package/dist/aes/aes-gcm-siv.d.ts +67 -0
- package/dist/aes/aes-gcm-siv.js +217 -0
- package/dist/aes/aes-gcm.d.ts +61 -0
- package/dist/aes/aes-gcm.js +226 -0
- package/dist/aes/cipher-suite.d.ts +21 -0
- package/dist/aes/cipher-suite.js +179 -0
- package/dist/aes/embedded.d.ts +1 -0
- package/dist/aes/embedded.js +26 -0
- package/dist/aes/generator.d.ts +14 -0
- package/dist/aes/generator.js +103 -0
- package/dist/aes/index.d.ts +58 -0
- package/dist/aes/index.js +125 -0
- package/dist/aes/ops.d.ts +60 -0
- package/dist/aes/ops.js +164 -0
- package/dist/aes/pool-worker.d.ts +1 -0
- package/dist/aes/pool-worker.js +92 -0
- package/dist/aes/types.d.ts +1 -0
- package/dist/aes/types.js +23 -0
- package/dist/aes.wasm +0 -0
- package/dist/blake3/embedded.d.ts +1 -0
- package/dist/blake3/embedded.js +26 -0
- package/dist/blake3/index.d.ts +143 -0
- package/dist/blake3/index.js +620 -0
- package/dist/blake3/types.d.ts +102 -0
- package/dist/blake3/types.js +31 -0
- package/dist/blake3/validate.d.ts +29 -0
- package/dist/blake3/validate.js +80 -0
- package/dist/blake3.wasm +0 -0
- package/dist/chacha20/cipher-suite.d.ts +10 -0
- package/dist/chacha20/cipher-suite.js +98 -13
- package/dist/chacha20/generator.d.ts +12 -0
- package/dist/chacha20/generator.js +91 -0
- package/dist/chacha20/index.d.ts +100 -3
- package/dist/chacha20/index.js +169 -35
- package/dist/chacha20/ops.d.ts +57 -6
- package/dist/chacha20/ops.js +107 -27
- package/dist/chacha20/pool-worker.js +14 -0
- package/dist/chacha20/types.d.ts +1 -32
- package/dist/cte-wasm.d.ts +1 -0
- package/dist/cte-wasm.js +3 -0
- package/dist/cte.wasm +0 -0
- package/dist/curve25519.wasm +0 -0
- package/dist/ecdsa/der.d.ts +23 -0
- package/dist/ecdsa/der.js +192 -0
- package/dist/ecdsa/ecprivatekey-der.d.ts +32 -0
- package/dist/ecdsa/ecprivatekey-der.js +230 -0
- package/dist/ecdsa/embedded.d.ts +1 -0
- package/dist/ecdsa/embedded.js +25 -0
- package/dist/ecdsa/index.d.ts +124 -0
- package/dist/ecdsa/index.js +366 -0
- package/dist/ecdsa/types.d.ts +31 -0
- package/dist/ecdsa/types.js +28 -0
- package/dist/ecdsa/validate.d.ts +18 -0
- package/dist/ecdsa/validate.js +92 -0
- package/dist/ed25519/embedded.d.ts +1 -0
- package/dist/ed25519/embedded.js +31 -0
- package/dist/ed25519/index.d.ts +70 -0
- package/dist/ed25519/index.js +308 -0
- package/dist/ed25519/types.d.ts +27 -0
- package/dist/ed25519/types.js +27 -0
- package/dist/ed25519/validate.d.ts +7 -0
- package/dist/ed25519/validate.js +77 -0
- package/dist/embedded/aes-pool-worker.d.ts +1 -0
- package/dist/embedded/aes-pool-worker.js +5 -0
- package/dist/embedded/aes.d.ts +1 -0
- package/dist/embedded/aes.js +3 -0
- package/dist/embedded/blake3.d.ts +1 -0
- package/dist/embedded/blake3.js +3 -0
- package/dist/embedded/chacha20-pool-worker.d.ts +1 -0
- package/dist/embedded/chacha20-pool-worker.js +5 -0
- package/dist/embedded/chacha20.d.ts +1 -1
- package/dist/embedded/chacha20.js +2 -2
- package/dist/embedded/curve25519.d.ts +1 -0
- package/dist/embedded/curve25519.js +3 -0
- package/dist/embedded/mldsa.d.ts +1 -0
- package/dist/embedded/mldsa.js +3 -0
- package/dist/embedded/mlkem.d.ts +1 -0
- package/dist/embedded/mlkem.js +3 -0
- package/dist/embedded/p256.d.ts +1 -0
- package/dist/embedded/p256.js +3 -0
- package/dist/embedded/serpent-pool-worker.d.ts +1 -0
- package/dist/embedded/serpent-pool-worker.js +5 -0
- package/dist/embedded/serpent.d.ts +1 -1
- package/dist/embedded/serpent.js +2 -2
- package/dist/embedded/sha2.d.ts +1 -1
- package/dist/embedded/sha2.js +2 -2
- package/dist/embedded/sha3.d.ts +1 -1
- package/dist/embedded/sha3.js +2 -2
- package/dist/embedded/slhdsa.d.ts +1 -0
- package/dist/embedded/slhdsa.js +3 -0
- package/dist/errors.d.ts +92 -1
- package/dist/errors.js +111 -1
- package/dist/fortuna.d.ts +18 -12
- package/dist/fortuna.js +166 -99
- package/dist/index.d.ts +42 -11
- package/dist/index.js +65 -20
- package/dist/init.d.ts +1 -3
- package/dist/init.js +73 -7
- package/dist/keccak/embedded.js +1 -1
- package/dist/keccak/index.d.ts +2 -0
- package/dist/keccak/index.js +4 -2
- package/dist/loader.d.ts +1 -19
- package/dist/loader.js +26 -32
- package/dist/merkle/blake3-tree.d.ts +35 -0
- package/dist/merkle/blake3-tree.js +187 -0
- package/dist/merkle/checkpoint.d.ts +58 -0
- package/dist/merkle/checkpoint.js +217 -0
- package/dist/merkle/index.d.ts +19 -0
- package/dist/merkle/index.js +37 -0
- package/dist/merkle/merkle-log.d.ts +130 -0
- package/dist/merkle/merkle-log.js +207 -0
- package/dist/merkle/merkle-verifier.d.ts +126 -0
- package/dist/merkle/merkle-verifier.js +296 -0
- package/dist/merkle/proof.d.ts +70 -0
- package/dist/merkle/proof.js +300 -0
- package/dist/merkle/sha256-tree.d.ts +33 -0
- package/dist/merkle/sha256-tree.js +145 -0
- package/dist/merkle/signed-log.d.ts +156 -0
- package/dist/merkle/signed-log.js +356 -0
- package/dist/merkle/signed-note.d.ts +309 -0
- package/dist/merkle/signed-note.js +648 -0
- package/dist/merkle/sth.d.ts +31 -0
- package/dist/merkle/sth.js +31 -0
- package/dist/merkle/storage.d.ts +40 -0
- package/dist/merkle/storage.js +71 -0
- package/dist/merkle/tree.d.ts +68 -0
- package/dist/merkle/tree.js +94 -0
- package/dist/mldsa/embedded.d.ts +1 -0
- package/dist/{kyber → mldsa}/embedded.js +5 -5
- package/dist/mldsa/expand.d.ts +53 -0
- package/dist/mldsa/expand.js +188 -0
- package/dist/mldsa/format.d.ts +16 -0
- package/dist/mldsa/format.js +68 -0
- package/dist/mldsa/hashvariant.d.ts +32 -0
- package/dist/mldsa/hashvariant.js +248 -0
- package/dist/mldsa/index.d.ts +142 -0
- package/dist/mldsa/index.js +463 -0
- package/dist/mldsa/keygen.d.ts +16 -0
- package/dist/mldsa/keygen.js +232 -0
- package/dist/mldsa/params.d.ts +21 -0
- package/dist/mldsa/params.js +55 -0
- package/dist/mldsa/sha3-helpers.d.ts +30 -0
- package/dist/mldsa/sha3-helpers.js +124 -0
- package/dist/mldsa/sign.d.ts +36 -0
- package/dist/mldsa/sign.js +380 -0
- package/dist/mldsa/types.d.ts +91 -0
- package/dist/mldsa/types.js +25 -0
- package/dist/mldsa/validate.d.ts +55 -0
- package/dist/mldsa/validate.js +125 -0
- package/dist/mldsa/verify.d.ts +29 -0
- package/dist/mldsa/verify.js +269 -0
- package/dist/mldsa.wasm +0 -0
- package/dist/mlkem/embedded.d.ts +1 -0
- package/dist/mlkem/embedded.js +27 -0
- package/dist/mlkem/indcpa.d.ts +49 -0
- package/dist/{kyber → mlkem}/indcpa.js +48 -48
- package/dist/mlkem/index.d.ts +37 -0
- package/dist/{kyber → mlkem}/index.js +41 -31
- package/dist/mlkem/kem.d.ts +21 -0
- package/dist/{kyber → mlkem}/kem.js +48 -13
- package/dist/{kyber → mlkem}/params.d.ts +4 -4
- package/dist/{kyber → mlkem}/params.js +2 -2
- package/dist/mlkem/suite.d.ts +12 -0
- package/dist/{kyber → mlkem}/suite.js +17 -12
- package/dist/{kyber → mlkem}/types.d.ts +4 -3
- package/dist/{kyber → mlkem}/types.js +1 -1
- package/dist/mlkem/validate.d.ts +23 -0
- package/dist/{kyber → mlkem}/validate.js +24 -20
- package/dist/{kyber.wasm → mlkem.wasm} +0 -0
- package/dist/p256.wasm +0 -0
- package/dist/ratchet/index.d.ts +8 -0
- package/dist/ratchet/index.js +38 -0
- package/dist/ratchet/kdf-chain.d.ts +13 -0
- package/dist/ratchet/kdf-chain.js +85 -0
- package/dist/ratchet/ratchet-keypair.d.ts +9 -0
- package/dist/ratchet/ratchet-keypair.js +61 -0
- package/dist/ratchet/root-kdf.d.ts +4 -0
- package/dist/ratchet/root-kdf.js +124 -0
- package/dist/ratchet/skipped-key-store.d.ts +14 -0
- package/dist/ratchet/skipped-key-store.js +154 -0
- package/dist/ratchet/types.d.ts +36 -0
- package/dist/ratchet/types.js +26 -0
- package/dist/serpent/cipher-suite.d.ts +10 -0
- package/dist/serpent/cipher-suite.js +144 -56
- package/dist/serpent/generator.d.ts +12 -0
- package/dist/serpent/generator.js +97 -0
- package/dist/serpent/index.d.ts +62 -1
- package/dist/serpent/index.js +97 -21
- package/dist/serpent/pool-worker.js +28 -102
- package/dist/serpent/serpent-cbc.d.ts +16 -6
- package/dist/serpent/serpent-cbc.js +58 -37
- package/dist/serpent/shared-ops.d.ts +63 -0
- package/dist/serpent/shared-ops.js +178 -0
- package/dist/serpent/types.d.ts +1 -5
- package/dist/serpent.wasm +0 -0
- package/dist/sha2/hash.d.ts +2 -0
- package/dist/sha2/hash.js +53 -0
- package/dist/sha2/hkdf.js +5 -5
- package/dist/sha2/index.d.ts +22 -1
- package/dist/sha2/index.js +80 -11
- package/dist/sha2/types.d.ts +41 -2
- package/dist/sha2.wasm +0 -0
- package/dist/sha3/hash.d.ts +2 -0
- package/dist/sha3/hash.js +53 -0
- package/dist/sha3/index.d.ts +87 -3
- package/dist/sha3/index.js +317 -19
- package/dist/sha3/kmac.d.ts +121 -0
- package/dist/sha3/kmac.js +800 -0
- package/dist/sha3.wasm +0 -0
- package/dist/shared/pkcs7.d.ts +22 -0
- package/dist/shared/pkcs7.js +84 -0
- package/dist/sign/ctx.d.ts +41 -0
- package/dist/sign/ctx.js +102 -0
- package/dist/sign/envelope.d.ts +45 -0
- package/dist/sign/envelope.js +152 -0
- package/dist/sign/hasher.d.ts +9 -0
- package/dist/sign/hasher.js +132 -0
- package/dist/sign/index.d.ts +11 -0
- package/dist/sign/index.js +34 -0
- package/dist/sign/sign-stream.d.ts +25 -0
- package/dist/sign/sign-stream.js +112 -0
- package/dist/sign/suites/ecdsa-p256.d.ts +2 -0
- package/dist/sign/suites/ecdsa-p256.js +120 -0
- package/dist/sign/suites/ed25519.d.ts +3 -0
- package/dist/sign/suites/ed25519.js +165 -0
- package/dist/sign/suites/hybrid-classical.d.ts +23 -0
- package/dist/sign/suites/hybrid-classical.js +526 -0
- package/dist/sign/suites/hybrid-pq.d.ts +4 -0
- package/dist/sign/suites/hybrid-pq.js +234 -0
- package/dist/sign/suites/mldsa.d.ts +7 -0
- package/dist/sign/suites/mldsa.js +161 -0
- package/dist/sign/suites/slhdsa.d.ts +7 -0
- package/dist/sign/suites/slhdsa.js +176 -0
- package/dist/sign/types.d.ts +106 -0
- package/dist/sign/types.js +28 -0
- package/dist/sign/verify-stream.d.ts +30 -0
- package/dist/sign/verify-stream.js +227 -0
- package/dist/slhdsa/embedded.d.ts +1 -0
- package/dist/slhdsa/embedded.js +26 -0
- package/dist/slhdsa/index.d.ts +149 -0
- package/dist/slhdsa/index.js +493 -0
- package/dist/slhdsa/params.d.ts +26 -0
- package/dist/slhdsa/params.js +70 -0
- package/dist/slhdsa/prehash.d.ts +68 -0
- package/dist/slhdsa/prehash.js +307 -0
- package/dist/slhdsa/sign.d.ts +39 -0
- package/dist/slhdsa/sign.js +116 -0
- package/dist/slhdsa/types.d.ts +129 -0
- package/dist/slhdsa/types.js +27 -0
- package/dist/slhdsa/validate.d.ts +60 -0
- package/dist/slhdsa/validate.js +127 -0
- package/dist/slhdsa/verify.d.ts +32 -0
- package/dist/slhdsa/verify.js +107 -0
- package/dist/slhdsa.wasm +0 -0
- package/dist/stream/header.js +8 -8
- package/dist/stream/index.d.ts +1 -0
- package/dist/stream/index.js +1 -0
- package/dist/stream/open-stream.js +65 -22
- package/dist/stream/seal-stream-pool.d.ts +2 -0
- package/dist/stream/seal-stream-pool.js +100 -33
- package/dist/stream/seal-stream.d.ts +1 -1
- package/dist/stream/seal-stream.js +48 -19
- package/dist/stream/seal.js +6 -6
- package/dist/stream/types.d.ts +3 -1
- package/dist/stream/types.js +1 -1
- package/dist/types.d.ts +22 -1
- package/dist/types.js +1 -1
- package/dist/utils.d.ts +9 -10
- package/dist/utils.js +84 -59
- package/dist/wasm-source.d.ts +9 -8
- package/dist/wasm-source.js +1 -1
- package/dist/x25519/embedded.d.ts +1 -0
- package/dist/x25519/embedded.js +31 -0
- package/dist/x25519/index.d.ts +43 -0
- package/dist/x25519/index.js +159 -0
- package/dist/x25519/types.d.ts +25 -0
- package/dist/x25519/types.js +27 -0
- package/dist/x25519/validate.d.ts +2 -0
- package/dist/x25519/validate.js +39 -0
- package/package.json +123 -64
- package/SECURITY.md +0 -276
- package/dist/ct-wasm.d.ts +0 -1
- package/dist/ct-wasm.js +0 -3
- package/dist/ct.wasm +0 -0
- package/dist/docs/aead.md +0 -323
- package/dist/docs/architecture.md +0 -932
- package/dist/docs/argon2id.md +0 -302
- package/dist/docs/chacha20.md +0 -674
- package/dist/docs/exports.md +0 -241
- package/dist/docs/fortuna.md +0 -313
- package/dist/docs/init.md +0 -302
- package/dist/docs/loader.md +0 -161
- package/dist/docs/serpent.md +0 -519
- package/dist/docs/sha2.md +0 -613
- package/dist/docs/sha3.md +0 -546
- package/dist/docs/types.md +0 -276
- package/dist/docs/utils.md +0 -367
- package/dist/embedded/kyber.d.ts +0 -1
- package/dist/embedded/kyber.js +0 -3
- package/dist/kyber/embedded.d.ts +0 -1
- package/dist/kyber/indcpa.d.ts +0 -49
- package/dist/kyber/index.d.ts +0 -38
- package/dist/kyber/kem.d.ts +0 -21
- package/dist/kyber/suite.d.ts +0 -13
- package/dist/kyber/validate.d.ts +0 -19
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { WasmSource } from '../wasm-source.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load and initialise the AES WASM module from `source`.
|
|
4
|
+
* Must be called before constructing any AES class.
|
|
5
|
+
* @param source WASM binary, gzip+base64 string, URL, ArrayBuffer, Uint8Array,
|
|
6
|
+
* pre-compiled WebAssembly.Module, Response, or Promise<Response>
|
|
7
|
+
*/
|
|
8
|
+
export declare function aesInit(source: WasmSource): Promise<void>;
|
|
9
|
+
export type { WasmSource };
|
|
10
|
+
export { isInitialized } from '../init.js';
|
|
11
|
+
/**
|
|
12
|
+
* Low-level AES block cipher, raw ECB encrypt + decrypt.
|
|
13
|
+
*
|
|
14
|
+
* AES-128/192/256 supported. `loadKey` accepts 16, 24, or 32 byte keys;
|
|
15
|
+
* Nr (10, 12, or 14) is derived and persisted in WASM memory between
|
|
16
|
+
* `loadKey` and the cipher calls.
|
|
17
|
+
*
|
|
18
|
+
* Decrypt uses the FIPS 197 §5.3.5 Equivalent Inverse Cipher: the round
|
|
19
|
+
* loop mirrors encrypt, and round keys 1..Nr-1 are pre-transformed by
|
|
20
|
+
* InvMixColumns inside `loadKey`.
|
|
21
|
+
*
|
|
22
|
+
* Atomic (stateless): each method call is independent. Does not hold
|
|
23
|
+
* exclusive module access. Call `dispose()` after use to wipe WASM key
|
|
24
|
+
* material.
|
|
25
|
+
*/
|
|
26
|
+
export declare class AES {
|
|
27
|
+
private readonly x;
|
|
28
|
+
constructor();
|
|
29
|
+
/**
|
|
30
|
+
* Expand `key` into the WASM key schedule (forward + EqInvCipher
|
|
31
|
+
* inverse round keys). Must be called before `encryptBlock` or
|
|
32
|
+
* `decryptBlock`.
|
|
33
|
+
* @param key 16, 24, or 32 bytes (AES-128 / 192 / 256)
|
|
34
|
+
*/
|
|
35
|
+
loadKey(key: Uint8Array): void;
|
|
36
|
+
/**
|
|
37
|
+
* Encrypt one 128-bit block with the previously loaded key schedule.
|
|
38
|
+
* FIPS 197 §5.1 Algorithm 1, Nr ∈ {10, 12, 14}.
|
|
39
|
+
* @param plaintext 16-byte plaintext block
|
|
40
|
+
* @returns 16-byte ciphertext block
|
|
41
|
+
*/
|
|
42
|
+
encryptBlock(plaintext: Uint8Array): Uint8Array;
|
|
43
|
+
/**
|
|
44
|
+
* Decrypt one 128-bit block with the previously loaded key schedule.
|
|
45
|
+
* FIPS 197 §5.3.5 Equivalent Inverse Cipher, Nr ∈ {10, 12, 14}.
|
|
46
|
+
* @param ciphertext 16-byte ciphertext block
|
|
47
|
+
* @returns 16-byte plaintext block
|
|
48
|
+
*/
|
|
49
|
+
decryptBlock(ciphertext: Uint8Array): Uint8Array;
|
|
50
|
+
/** Wipe WASM key material and intermediate buffers. */
|
|
51
|
+
dispose(): void;
|
|
52
|
+
}
|
|
53
|
+
export { AESCbc } from './aes-cbc.js';
|
|
54
|
+
export { AESCtr } from './aes-ctr.js';
|
|
55
|
+
export { AESGCM } from './aes-gcm.js';
|
|
56
|
+
export { AESGCMSIV } from './aes-gcm-siv.js';
|
|
57
|
+
export { AESGenerator } from './generator.js';
|
|
58
|
+
export { AESGCMSIVCipher } from './cipher-suite.js';
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// ▄▄▄▄▄▄▄▄▄▄
|
|
2
|
+
// ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
|
|
3
|
+
// ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
|
|
4
|
+
// ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
|
|
5
|
+
// ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
|
|
6
|
+
// ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
|
|
7
|
+
// ███████▌ ▀██▀ ███
|
|
8
|
+
// ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
|
|
9
|
+
// ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
|
|
10
|
+
// ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
|
|
11
|
+
// ▀████▄ ▄██▄
|
|
12
|
+
// ▐████ ▐███ Author: xero (https://x-e.ro)
|
|
13
|
+
// ▄▄██████████ ▐███ ▄▄ License: MIT
|
|
14
|
+
// ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
|
|
15
|
+
// ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
|
|
16
|
+
// ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
|
|
17
|
+
// ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
|
|
18
|
+
// █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
|
|
19
|
+
// ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
|
|
20
|
+
// ▀█████▀▀
|
|
21
|
+
//
|
|
22
|
+
// src/ts/aes/index.ts
|
|
23
|
+
//
|
|
24
|
+
// Public API classes for the AES WASM module.
|
|
25
|
+
// AES-128/192/256 supported.
|
|
26
|
+
import { getInstance, initModule, _assertNotOwned } from '../init.js';
|
|
27
|
+
/**
|
|
28
|
+
* Load and initialise the AES WASM module from `source`.
|
|
29
|
+
* Must be called before constructing any AES class.
|
|
30
|
+
* @param source WASM binary, gzip+base64 string, URL, ArrayBuffer, Uint8Array,
|
|
31
|
+
* pre-compiled WebAssembly.Module, Response, or Promise<Response>
|
|
32
|
+
*/
|
|
33
|
+
export async function aesInit(source) {
|
|
34
|
+
return initModule('aes', source);
|
|
35
|
+
}
|
|
36
|
+
export { isInitialized } from '../init.js';
|
|
37
|
+
/** Returns the raw AES WASM export object. @internal */
|
|
38
|
+
function getExports() {
|
|
39
|
+
return getInstance('aes').exports;
|
|
40
|
+
}
|
|
41
|
+
// ── AES ─────────────────────────────────────────────────────────────────────
|
|
42
|
+
/**
|
|
43
|
+
* Low-level AES block cipher, raw ECB encrypt + decrypt.
|
|
44
|
+
*
|
|
45
|
+
* AES-128/192/256 supported. `loadKey` accepts 16, 24, or 32 byte keys;
|
|
46
|
+
* Nr (10, 12, or 14) is derived and persisted in WASM memory between
|
|
47
|
+
* `loadKey` and the cipher calls.
|
|
48
|
+
*
|
|
49
|
+
* Decrypt uses the FIPS 197 §5.3.5 Equivalent Inverse Cipher: the round
|
|
50
|
+
* loop mirrors encrypt, and round keys 1..Nr-1 are pre-transformed by
|
|
51
|
+
* InvMixColumns inside `loadKey`.
|
|
52
|
+
*
|
|
53
|
+
* Atomic (stateless): each method call is independent. Does not hold
|
|
54
|
+
* exclusive module access. Call `dispose()` after use to wipe WASM key
|
|
55
|
+
* material.
|
|
56
|
+
*/
|
|
57
|
+
export class AES {
|
|
58
|
+
x;
|
|
59
|
+
constructor() {
|
|
60
|
+
this.x = getExports();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Expand `key` into the WASM key schedule (forward + EqInvCipher
|
|
64
|
+
* inverse round keys). Must be called before `encryptBlock` or
|
|
65
|
+
* `decryptBlock`.
|
|
66
|
+
* @param key 16, 24, or 32 bytes (AES-128 / 192 / 256)
|
|
67
|
+
*/
|
|
68
|
+
loadKey(key) {
|
|
69
|
+
_assertNotOwned('aes');
|
|
70
|
+
if (key.length !== 16 && key.length !== 24 && key.length !== 32)
|
|
71
|
+
throw new RangeError(`AES.loadKey: key must be 16, 24, or 32 bytes (got ${key.length})`);
|
|
72
|
+
const mem = new Uint8Array(this.x.memory.buffer);
|
|
73
|
+
mem.set(key, this.x.getKeyOffset());
|
|
74
|
+
if (this.x.loadKey(key.length) !== 0) {
|
|
75
|
+
this.x.wipeBuffers();
|
|
76
|
+
throw new Error('loadKey failed');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Encrypt one 128-bit block with the previously loaded key schedule.
|
|
81
|
+
* FIPS 197 §5.1 Algorithm 1, Nr ∈ {10, 12, 14}.
|
|
82
|
+
* @param plaintext 16-byte plaintext block
|
|
83
|
+
* @returns 16-byte ciphertext block
|
|
84
|
+
*/
|
|
85
|
+
encryptBlock(plaintext) {
|
|
86
|
+
_assertNotOwned('aes');
|
|
87
|
+
if (plaintext.length !== 16)
|
|
88
|
+
throw new RangeError(`block must be 16 bytes (got ${plaintext.length})`);
|
|
89
|
+
const mem = new Uint8Array(this.x.memory.buffer);
|
|
90
|
+
const ptOff = this.x.getBlockPtOffset();
|
|
91
|
+
const ctOff = this.x.getBlockCtOffset();
|
|
92
|
+
mem.set(plaintext, ptOff);
|
|
93
|
+
this.x.encryptBlock();
|
|
94
|
+
return mem.slice(ctOff, ctOff + 16);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Decrypt one 128-bit block with the previously loaded key schedule.
|
|
98
|
+
* FIPS 197 §5.3.5 Equivalent Inverse Cipher, Nr ∈ {10, 12, 14}.
|
|
99
|
+
* @param ciphertext 16-byte ciphertext block
|
|
100
|
+
* @returns 16-byte plaintext block
|
|
101
|
+
*/
|
|
102
|
+
decryptBlock(ciphertext) {
|
|
103
|
+
_assertNotOwned('aes');
|
|
104
|
+
if (ciphertext.length !== 16)
|
|
105
|
+
throw new RangeError(`block must be 16 bytes (got ${ciphertext.length})`);
|
|
106
|
+
const mem = new Uint8Array(this.x.memory.buffer);
|
|
107
|
+
const ptOff = this.x.getBlockPtOffset();
|
|
108
|
+
const ctOff = this.x.getBlockCtOffset();
|
|
109
|
+
mem.set(ciphertext, ptOff);
|
|
110
|
+
this.x.decryptBlock();
|
|
111
|
+
return mem.slice(ctOff, ctOff + 16);
|
|
112
|
+
}
|
|
113
|
+
/** Wipe WASM key material and intermediate buffers. */
|
|
114
|
+
dispose() {
|
|
115
|
+
_assertNotOwned('aes');
|
|
116
|
+
this.x.wipeBuffers();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// ── CBC + CTR + GCM mode wrappers ───────────────────────────────────────────
|
|
120
|
+
export { AESCbc } from './aes-cbc.js';
|
|
121
|
+
export { AESCtr } from './aes-ctr.js';
|
|
122
|
+
export { AESGCM } from './aes-gcm.js';
|
|
123
|
+
export { AESGCMSIV } from './aes-gcm-siv.js';
|
|
124
|
+
export { AESGenerator } from './generator.js';
|
|
125
|
+
export { AESGCMSIVCipher } from './cipher-suite.js';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { AesExports } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* AES-256-GCM-SIV AEAD encrypt (RFC 8452). Single-shot per call; the
|
|
4
|
+
* plaintext is bounded by the AES module's WASM CHUNK_SIZE.
|
|
5
|
+
*
|
|
6
|
+
* Stage: write KGK at KEY_OFFSET, expand round keys, write nonce/AAD/PT
|
|
7
|
+
* into their slots, run `sivDeriveKeys(NONCE_OFFSET)`, then `sivSeal`.
|
|
8
|
+
* `sivSeal` overwrites CHUNK_PT with the ciphertext in place; the tag
|
|
9
|
+
* lands at TAG_OFFSET.
|
|
10
|
+
*
|
|
11
|
+
* @note AES-256 only, the key MUST be 32 bytes. The standalone
|
|
12
|
+
* `AESGCMSIV` class accepts both 16-byte (AES-128) and 32-byte
|
|
13
|
+
* (AES-256) keys per RFC 8452 §6, but this `ops.ts` path is the
|
|
14
|
+
* internal helper for `AESGCMSIVCipher` and the AES pool worker,
|
|
15
|
+
* both of which fix the cipher suite at AES-256 to keep the wire
|
|
16
|
+
* format uniform across deployments. A 16-byte key here throws
|
|
17
|
+
* `RangeError('AES-GCM-SIV: key must be 32 bytes (got 16)')`. Use
|
|
18
|
+
* the `AESGCMSIV` class directly if you need AES-128.
|
|
19
|
+
*
|
|
20
|
+
* @param x AES WASM exports
|
|
21
|
+
* @param key 32-byte AES-256 key (KGK in RFC 8452 terminology)
|
|
22
|
+
* @param nonce 12-byte nonce, must be unique per `(key, message)`
|
|
23
|
+
* under the standard nonce-respecting model; reuse is
|
|
24
|
+
* tolerated by the SIV construction but reduces IND-CPA
|
|
25
|
+
* to message-equality leakage
|
|
26
|
+
* @param plaintext Data to encrypt; must be ≤ `x.getChunkSize()`
|
|
27
|
+
* @param aad Additional authenticated data; must be ≤ 64 KiB
|
|
28
|
+
* @returns `{ ciphertext, tag }`, tag is 16 bytes
|
|
29
|
+
*/
|
|
30
|
+
export declare function sivAeadEncrypt(x: AesExports, key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, aad: Uint8Array): {
|
|
31
|
+
ciphertext: Uint8Array;
|
|
32
|
+
tag: Uint8Array;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* AES-256-GCM-SIV AEAD decrypt (RFC 8452). Verify-after-decrypt, the
|
|
36
|
+
* tag is a function of the plaintext, so SIV reconstructs the plaintext
|
|
37
|
+
* before recomputing and comparing the tag in constant time.
|
|
38
|
+
*
|
|
39
|
+
* On mismatch, `sivWipeOnFail()` zeroes the unauthenticated plaintext at
|
|
40
|
+
* CHUNK_PT_OFFSET before this function throws. Subsequent reads of
|
|
41
|
+
* the WASM memory cannot recover plaintext from a forged ciphertext.
|
|
42
|
+
*
|
|
43
|
+
* @note AES-256 only, the key MUST be 32 bytes (matching
|
|
44
|
+
* `sivAeadEncrypt`). The standalone `AESGCMSIV` class supports
|
|
45
|
+
* both AES-128 and AES-256, but this `ops.ts` helper is the
|
|
46
|
+
* internal path used by `AESGCMSIVCipher` and the AES pool
|
|
47
|
+
* worker, both of which fix the cipher suite at AES-256. A
|
|
48
|
+
* 16-byte key here throws
|
|
49
|
+
* `RangeError('AES-GCM-SIV: key must be 32 bytes (got 16)')`.
|
|
50
|
+
*
|
|
51
|
+
* @param x AES WASM exports
|
|
52
|
+
* @param key 32-byte AES-256 key
|
|
53
|
+
* @param nonce 12-byte nonce, must match the value used to encrypt
|
|
54
|
+
* @param ciphertext Ciphertext bytes (must be ≤ `x.getChunkSize()`)
|
|
55
|
+
* @param tag 16-byte SIV tag
|
|
56
|
+
* @param aad Additional authenticated data
|
|
57
|
+
* @param cipherName Error label for `AuthenticationError` (default 'aes-gcm-siv')
|
|
58
|
+
* @returns Plaintext
|
|
59
|
+
*/
|
|
60
|
+
export declare function sivAeadDecrypt(x: AesExports, key: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array, tag: Uint8Array, aad: Uint8Array, cipherName?: string): Uint8Array;
|
package/dist/aes/ops.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// ▄▄▄▄▄▄▄▄▄▄
|
|
2
|
+
// ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
|
|
3
|
+
// ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
|
|
4
|
+
// ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
|
|
5
|
+
// ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
|
|
6
|
+
// ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
|
|
7
|
+
// ███████▌ ▀██▀ ███
|
|
8
|
+
// ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
|
|
9
|
+
// ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
|
|
10
|
+
// ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
|
|
11
|
+
// ▀████▄ ▄██▄
|
|
12
|
+
// ▐████ ▐███ Author: xero (https://x-e.ro)
|
|
13
|
+
// ▄▄██████████ ▐███ ▄▄ License: MIT
|
|
14
|
+
// ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
|
|
15
|
+
// ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
|
|
16
|
+
// ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
|
|
17
|
+
// ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
|
|
18
|
+
// █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
|
|
19
|
+
// ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
|
|
20
|
+
// ▀█████▀▀
|
|
21
|
+
//
|
|
22
|
+
// src/ts/aes/ops.ts
|
|
23
|
+
//
|
|
24
|
+
// Raw AES-GCM-SIV operations, standalone functions that take AesExports
|
|
25
|
+
// explicitly. Used by both `AESGCMSIVCipher` (cipher-suite.ts) and the
|
|
26
|
+
// pool worker (pool-worker.ts), eliminating duplication.
|
|
27
|
+
//
|
|
28
|
+
// This file MUST NOT import from `../init.js`. Pool workers have their
|
|
29
|
+
// own WASM instances; importing init in shared ops would couple them.
|
|
30
|
+
// The cipher suite obtains exports via getInstance at the call site and
|
|
31
|
+
// passes them down.
|
|
32
|
+
import { constantTimeEqual, wipe } from '../utils.js';
|
|
33
|
+
import { AuthenticationError } from '../errors.js';
|
|
34
|
+
const KEY_LEN_256 = 32;
|
|
35
|
+
const NONCE_LEN = 12;
|
|
36
|
+
const TAG_LEN = 16;
|
|
37
|
+
const MAX_AAD = 65536;
|
|
38
|
+
/**
|
|
39
|
+
* AES-256-GCM-SIV AEAD encrypt (RFC 8452). Single-shot per call; the
|
|
40
|
+
* plaintext is bounded by the AES module's WASM CHUNK_SIZE.
|
|
41
|
+
*
|
|
42
|
+
* Stage: write KGK at KEY_OFFSET, expand round keys, write nonce/AAD/PT
|
|
43
|
+
* into their slots, run `sivDeriveKeys(NONCE_OFFSET)`, then `sivSeal`.
|
|
44
|
+
* `sivSeal` overwrites CHUNK_PT with the ciphertext in place; the tag
|
|
45
|
+
* lands at TAG_OFFSET.
|
|
46
|
+
*
|
|
47
|
+
* @note AES-256 only, the key MUST be 32 bytes. The standalone
|
|
48
|
+
* `AESGCMSIV` class accepts both 16-byte (AES-128) and 32-byte
|
|
49
|
+
* (AES-256) keys per RFC 8452 §6, but this `ops.ts` path is the
|
|
50
|
+
* internal helper for `AESGCMSIVCipher` and the AES pool worker,
|
|
51
|
+
* both of which fix the cipher suite at AES-256 to keep the wire
|
|
52
|
+
* format uniform across deployments. A 16-byte key here throws
|
|
53
|
+
* `RangeError('AES-GCM-SIV: key must be 32 bytes (got 16)')`. Use
|
|
54
|
+
* the `AESGCMSIV` class directly if you need AES-128.
|
|
55
|
+
*
|
|
56
|
+
* @param x AES WASM exports
|
|
57
|
+
* @param key 32-byte AES-256 key (KGK in RFC 8452 terminology)
|
|
58
|
+
* @param nonce 12-byte nonce, must be unique per `(key, message)`
|
|
59
|
+
* under the standard nonce-respecting model; reuse is
|
|
60
|
+
* tolerated by the SIV construction but reduces IND-CPA
|
|
61
|
+
* to message-equality leakage
|
|
62
|
+
* @param plaintext Data to encrypt; must be ≤ `x.getChunkSize()`
|
|
63
|
+
* @param aad Additional authenticated data; must be ≤ 64 KiB
|
|
64
|
+
* @returns `{ ciphertext, tag }`, tag is 16 bytes
|
|
65
|
+
*/
|
|
66
|
+
export function sivAeadEncrypt(x, key, nonce, plaintext, aad) {
|
|
67
|
+
if (key.length !== KEY_LEN_256)
|
|
68
|
+
throw new RangeError(`AES-GCM-SIV: key must be ${KEY_LEN_256} bytes (got ${key.length})`);
|
|
69
|
+
if (nonce.length !== NONCE_LEN)
|
|
70
|
+
throw new RangeError(`AES-GCM-SIV: nonce must be ${NONCE_LEN} bytes (got ${nonce.length})`);
|
|
71
|
+
const maxChunk = x.getChunkSize();
|
|
72
|
+
if (plaintext.length > maxChunk)
|
|
73
|
+
throw new RangeError(`AES-GCM-SIV: plaintext exceeds ${maxChunk} bytes, split into smaller chunks`);
|
|
74
|
+
if (aad.length > MAX_AAD)
|
|
75
|
+
throw new RangeError(`AES-GCM-SIV: AAD must be ≤ ${MAX_AAD} bytes (got ${aad.length})`);
|
|
76
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
77
|
+
mem.set(key, x.getKeyOffset());
|
|
78
|
+
if (x.loadKey(KEY_LEN_256) !== 0) {
|
|
79
|
+
x.wipeBuffers();
|
|
80
|
+
throw new Error('AES-GCM-SIV: loadKey failed');
|
|
81
|
+
}
|
|
82
|
+
mem.set(nonce, x.getNonceOffset());
|
|
83
|
+
if (aad.length > 0)
|
|
84
|
+
mem.set(aad, x.getAadOffset());
|
|
85
|
+
mem.set(plaintext, x.getChunkPtOffset());
|
|
86
|
+
x.sivDeriveKeys(x.getNonceOffset());
|
|
87
|
+
x.sivSeal(aad.length, plaintext.length);
|
|
88
|
+
// sivSeal writes the ciphertext in place at CHUNK_PT_OFFSET.
|
|
89
|
+
const ctOff = x.getChunkPtOffset();
|
|
90
|
+
const tagOff = x.getTagOffset();
|
|
91
|
+
const memView = new Uint8Array(x.memory.buffer);
|
|
92
|
+
const ciphertext = memView.slice(ctOff, ctOff + plaintext.length);
|
|
93
|
+
const tag = memView.slice(tagOff, tagOff + TAG_LEN);
|
|
94
|
+
return { ciphertext, tag };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* AES-256-GCM-SIV AEAD decrypt (RFC 8452). Verify-after-decrypt, the
|
|
98
|
+
* tag is a function of the plaintext, so SIV reconstructs the plaintext
|
|
99
|
+
* before recomputing and comparing the tag in constant time.
|
|
100
|
+
*
|
|
101
|
+
* On mismatch, `sivWipeOnFail()` zeroes the unauthenticated plaintext at
|
|
102
|
+
* CHUNK_PT_OFFSET before this function throws. Subsequent reads of
|
|
103
|
+
* the WASM memory cannot recover plaintext from a forged ciphertext.
|
|
104
|
+
*
|
|
105
|
+
* @note AES-256 only, the key MUST be 32 bytes (matching
|
|
106
|
+
* `sivAeadEncrypt`). The standalone `AESGCMSIV` class supports
|
|
107
|
+
* both AES-128 and AES-256, but this `ops.ts` helper is the
|
|
108
|
+
* internal path used by `AESGCMSIVCipher` and the AES pool
|
|
109
|
+
* worker, both of which fix the cipher suite at AES-256. A
|
|
110
|
+
* 16-byte key here throws
|
|
111
|
+
* `RangeError('AES-GCM-SIV: key must be 32 bytes (got 16)')`.
|
|
112
|
+
*
|
|
113
|
+
* @param x AES WASM exports
|
|
114
|
+
* @param key 32-byte AES-256 key
|
|
115
|
+
* @param nonce 12-byte nonce, must match the value used to encrypt
|
|
116
|
+
* @param ciphertext Ciphertext bytes (must be ≤ `x.getChunkSize()`)
|
|
117
|
+
* @param tag 16-byte SIV tag
|
|
118
|
+
* @param aad Additional authenticated data
|
|
119
|
+
* @param cipherName Error label for `AuthenticationError` (default 'aes-gcm-siv')
|
|
120
|
+
* @returns Plaintext
|
|
121
|
+
*/
|
|
122
|
+
export function sivAeadDecrypt(x, key, nonce, ciphertext, tag, aad, cipherName = 'aes-gcm-siv') {
|
|
123
|
+
if (key.length !== KEY_LEN_256)
|
|
124
|
+
throw new RangeError(`AES-GCM-SIV: key must be ${KEY_LEN_256} bytes (got ${key.length})`);
|
|
125
|
+
if (nonce.length !== NONCE_LEN)
|
|
126
|
+
throw new RangeError(`AES-GCM-SIV: nonce must be ${NONCE_LEN} bytes (got ${nonce.length})`);
|
|
127
|
+
if (tag.length !== TAG_LEN)
|
|
128
|
+
throw new RangeError(`AES-GCM-SIV: tag must be ${TAG_LEN} bytes (got ${tag.length})`);
|
|
129
|
+
const maxChunk = x.getChunkSize();
|
|
130
|
+
if (ciphertext.length > maxChunk)
|
|
131
|
+
throw new RangeError(`AES-GCM-SIV: ciphertext exceeds ${maxChunk} bytes, split into smaller chunks`);
|
|
132
|
+
if (aad.length > MAX_AAD)
|
|
133
|
+
throw new RangeError(`AES-GCM-SIV: AAD must be ≤ ${MAX_AAD} bytes (got ${aad.length})`);
|
|
134
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
135
|
+
mem.set(key, x.getKeyOffset());
|
|
136
|
+
if (x.loadKey(KEY_LEN_256) !== 0) {
|
|
137
|
+
x.wipeBuffers();
|
|
138
|
+
throw new Error('AES-GCM-SIV: loadKey failed');
|
|
139
|
+
}
|
|
140
|
+
mem.set(nonce, x.getNonceOffset());
|
|
141
|
+
if (aad.length > 0)
|
|
142
|
+
mem.set(aad, x.getAadOffset());
|
|
143
|
+
mem.set(ciphertext, x.getChunkCtOffset());
|
|
144
|
+
// sivOpen reads the provided tag from SIV_IC_OFFSET (the CTR initial
|
|
145
|
+
// counter slot, RFC 8452 §4, where the tag drives the CTR start).
|
|
146
|
+
mem.set(tag, x.getSivIcOffset());
|
|
147
|
+
x.sivDeriveKeys(x.getNonceOffset());
|
|
148
|
+
x.sivOpen(aad.length, ciphertext.length);
|
|
149
|
+
// Read the recomputed expected tag from TAG_OFFSET. slice() so the
|
|
150
|
+
// buffer survives any subsequent WASM memory growth.
|
|
151
|
+
const memView = new Uint8Array(x.memory.buffer);
|
|
152
|
+
const expectedTag = memView.slice(x.getTagOffset(), x.getTagOffset() + TAG_LEN);
|
|
153
|
+
// Defensive copy of the provided tag for the constant-time compare,
|
|
154
|
+
// callers may pass a view over a mutable buffer.
|
|
155
|
+
const providedTagCopy = new Uint8Array(tag);
|
|
156
|
+
if (!constantTimeEqual(expectedTag, providedTagCopy)) {
|
|
157
|
+
x.sivWipeOnFail();
|
|
158
|
+
wipe(expectedTag);
|
|
159
|
+
wipe(providedTagCopy);
|
|
160
|
+
throw new AuthenticationError(cipherName);
|
|
161
|
+
}
|
|
162
|
+
const ptOff = x.getChunkPtOffset();
|
|
163
|
+
return memView.slice(ptOff, ptOff + ciphertext.length);
|
|
164
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// / <reference lib="webworker" />
|
|
2
|
+
// src/ts/aes/pool-worker.ts
|
|
3
|
+
//
|
|
4
|
+
// Worker for SealStreamPool with AESGCMSIVCipher.
|
|
5
|
+
// Holds derived AES-256-GCM-SIV key and the AES WASM instance for the
|
|
6
|
+
// pool's lifetime. Per-job: AES-GCM-SIV AEAD with 12-byte counter nonce.
|
|
7
|
+
import { sivAeadEncrypt, sivAeadDecrypt } from './ops.js';
|
|
8
|
+
import { AuthenticationError } from '../errors.js';
|
|
9
|
+
let x;
|
|
10
|
+
let derivedKey;
|
|
11
|
+
/**
|
|
12
|
+
* Message handler for the AES pool worker.
|
|
13
|
+
*
|
|
14
|
+
* Accepts three message types:
|
|
15
|
+
* - `'init'` , instantiate the aes WASM module and store the derived AES key
|
|
16
|
+
* - `'wipe'` , zero key and WASM buffers, then post `{ type: 'wiped' }`
|
|
17
|
+
* - `{ op: 'seal' | 'open', ... }`, encrypt or decrypt one chunk
|
|
18
|
+
*
|
|
19
|
+
* Replies with `{ type: 'result', id, data }` on success or
|
|
20
|
+
* `{ type: 'error', id, message, isAuthError }` on failure.
|
|
21
|
+
*/
|
|
22
|
+
self.onmessage = async (e) => {
|
|
23
|
+
const msg = e.data;
|
|
24
|
+
if (msg.type === 'init') {
|
|
25
|
+
try {
|
|
26
|
+
// AES module is 4 pages = 256 KiB; matches src/asm/aes/buffers.ts.
|
|
27
|
+
const mem = new WebAssembly.Memory({ initial: 4, maximum: 4 });
|
|
28
|
+
const mod = msg.modules.aes;
|
|
29
|
+
const inst = await WebAssembly.instantiate(mod, { env: { memory: mem } });
|
|
30
|
+
x = inst.exports;
|
|
31
|
+
derivedKey = new Uint8Array(msg.derivedKeyBytes);
|
|
32
|
+
if (derivedKey.length !== 32)
|
|
33
|
+
throw new Error(`expected 32 derived key bytes (got ${derivedKey.length})`);
|
|
34
|
+
msg.derivedKeyBytes.fill(0);
|
|
35
|
+
self.postMessage({ type: 'ready' });
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
if (msg.derivedKeyBytes)
|
|
39
|
+
msg.derivedKeyBytes.fill(0);
|
|
40
|
+
self.postMessage({ type: 'error', id: -1, message: err.message, isAuthError: false });
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (msg.type === 'wipe') {
|
|
45
|
+
if (derivedKey)
|
|
46
|
+
derivedKey.fill(0);
|
|
47
|
+
derivedKey = undefined;
|
|
48
|
+
if (x)
|
|
49
|
+
x.wipeBuffers();
|
|
50
|
+
x = undefined;
|
|
51
|
+
self.postMessage({ type: 'wiped' });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (!x || !derivedKey) {
|
|
55
|
+
self.postMessage({ type: 'error', id: msg.id, message: 'worker not initialized', isAuthError: false });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const { id, op, counterNonce, data, aad } = msg;
|
|
60
|
+
const aadBytes = aad ?? new Uint8Array(0);
|
|
61
|
+
const jobKey = msg.derivedKeyBytes ?? derivedKey;
|
|
62
|
+
let result;
|
|
63
|
+
if (op === 'seal') {
|
|
64
|
+
const { ciphertext, tag } = sivAeadEncrypt(x, jobKey, counterNonce, data, aadBytes);
|
|
65
|
+
result = new Uint8Array(ciphertext.length + 16);
|
|
66
|
+
result.set(ciphertext);
|
|
67
|
+
result.set(tag, ciphertext.length);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
const ct = data.subarray(0, data.length - 16);
|
|
71
|
+
const tag = data.subarray(data.length - 16);
|
|
72
|
+
result = sivAeadDecrypt(x, jobKey, counterNonce, ct, tag, aadBytes, 'aes-gcm-siv');
|
|
73
|
+
}
|
|
74
|
+
const transfer = result.buffer instanceof ArrayBuffer ? [result.buffer] : [];
|
|
75
|
+
self.postMessage({ type: 'result', id, data: result }, { transfer });
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const isAuth = err instanceof AuthenticationError;
|
|
79
|
+
self.postMessage({
|
|
80
|
+
type: 'error', id: msg.id,
|
|
81
|
+
message: err.message,
|
|
82
|
+
cipher: isAuth ? 'aes-gcm-siv' : undefined,
|
|
83
|
+
isAuthError: isAuth,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
if (msg.derivedKeyBytes)
|
|
88
|
+
msg.derivedKeyBytes.fill(0);
|
|
89
|
+
if (x)
|
|
90
|
+
x.wipeBuffers();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// ▄▄▄▄▄▄▄▄▄▄
|
|
2
|
+
// ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
|
|
3
|
+
// ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
|
|
4
|
+
// ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
|
|
5
|
+
// ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
|
|
6
|
+
// ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
|
|
7
|
+
// ███████▌ ▀██▀ ███
|
|
8
|
+
// ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
|
|
9
|
+
// ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
|
|
10
|
+
// ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
|
|
11
|
+
// ▀████▄ ▄██▄
|
|
12
|
+
// ▐████ ▐███ Author: xero (https://x-e.ro)
|
|
13
|
+
// ▄▄██████████ ▐███ ▄▄ License: MIT
|
|
14
|
+
// ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
|
|
15
|
+
// ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
|
|
16
|
+
// ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
|
|
17
|
+
// ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
|
|
18
|
+
// █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
|
|
19
|
+
// ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
|
|
20
|
+
// ▀█████▀▀
|
|
21
|
+
//
|
|
22
|
+
// src/ts/aes/types.ts
|
|
23
|
+
export {};
|
package/dist/aes.wasm
ADDED
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { WASM_GZ_BASE64 as blake3Wasm } from '../embedded/blake3.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// ▄▄▄▄▄▄▄▄▄▄
|
|
2
|
+
// ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
|
|
3
|
+
// ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
|
|
4
|
+
// ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
|
|
5
|
+
// ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
|
|
6
|
+
// ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
|
|
7
|
+
// ███████▌ ▀██▀ ███
|
|
8
|
+
// ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
|
|
9
|
+
// ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
|
|
10
|
+
// ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
|
|
11
|
+
// ▀████▄ ▄██▄
|
|
12
|
+
// ▐████ ▐███ Author: xero (https://x-e.ro)
|
|
13
|
+
// ▄▄██████████ ▐███ ▄▄ License: MIT
|
|
14
|
+
// ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
|
|
15
|
+
// ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
|
|
16
|
+
// ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
|
|
17
|
+
// ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
|
|
18
|
+
// █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
|
|
19
|
+
// ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
|
|
20
|
+
// ▀█████▀▀
|
|
21
|
+
//
|
|
22
|
+
// src/ts/blake3/embedded.ts
|
|
23
|
+
//
|
|
24
|
+
// Exports the gzip+base64 blake3 WASM blob for use as a WasmSource.
|
|
25
|
+
// Import via `leviathan-crypto/blake3/embedded`.
|
|
26
|
+
export { WASM_GZ_BASE64 as blake3Wasm } from '../embedded/blake3.js';
|