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
package/dist/serpent/index.d.ts
CHANGED
|
@@ -1,12 +1,45 @@
|
|
|
1
1
|
import type { WasmSource } from '../wasm-source.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load and initialise the Serpent WASM module from `source`.
|
|
4
|
+
* Must be called before constructing any Serpent class.
|
|
5
|
+
* @param source WASM binary, gzip+base64 string, URL, ArrayBuffer, Uint8Array,
|
|
6
|
+
* pre-compiled WebAssembly.Module, Response, or Promise<Response>
|
|
7
|
+
*/
|
|
2
8
|
export declare function serpentInit(source: WasmSource): Promise<void>;
|
|
3
9
|
export type { WasmSource };
|
|
10
|
+
export { isInitialized } from '../init.js';
|
|
11
|
+
/**
|
|
12
|
+
* Low-level Serpent-256 block cipher, raw ECB encrypt/decrypt.
|
|
13
|
+
*
|
|
14
|
+
* Atomic (stateless) class: each method call is independent.
|
|
15
|
+
* Does not hold exclusive module access; cannot be used while a stateful
|
|
16
|
+
* instance (`SerpentCtr`, `SerpentCbc`, `SerpentCipher`) is alive.
|
|
17
|
+
* Call `dispose()` after use to wipe WASM key material.
|
|
18
|
+
*/
|
|
4
19
|
export declare class Serpent {
|
|
5
20
|
private readonly x;
|
|
6
21
|
constructor();
|
|
22
|
+
/**
|
|
23
|
+
* Expand `key` into the WASM key schedule. Must be called before
|
|
24
|
+
* `encryptBlock` / `decryptBlock`.
|
|
25
|
+
* @param key 16, 24, or 32 bytes
|
|
26
|
+
*/
|
|
7
27
|
loadKey(key: Uint8Array): void;
|
|
28
|
+
/**
|
|
29
|
+
* Encrypt one 128-bit block with the previously loaded key schedule.
|
|
30
|
+
* Serpent AES submission §2.2.
|
|
31
|
+
* @param plaintext 16-byte plaintext block
|
|
32
|
+
* @returns 16-byte ciphertext block
|
|
33
|
+
*/
|
|
8
34
|
encryptBlock(plaintext: Uint8Array): Uint8Array;
|
|
35
|
+
/**
|
|
36
|
+
* Decrypt one 128-bit block with the previously loaded key schedule.
|
|
37
|
+
* Serpent AES submission §2.2.
|
|
38
|
+
* @param ciphertext 16-byte ciphertext block
|
|
39
|
+
* @returns 16-byte plaintext block
|
|
40
|
+
*/
|
|
9
41
|
decryptBlock(ciphertext: Uint8Array): Uint8Array;
|
|
42
|
+
/** Wipe WASM key material and release memory. */
|
|
10
43
|
dispose(): void;
|
|
11
44
|
}
|
|
12
45
|
/**
|
|
@@ -15,19 +48,47 @@ export declare class Serpent {
|
|
|
15
48
|
* **WARNING: CTR mode is unauthenticated.** An attacker can flip ciphertext
|
|
16
49
|
* bits without detection. Always pair with HMAC-SHA256 (Encrypt-then-MAC)
|
|
17
50
|
* or use `XChaCha20Poly1305` instead.
|
|
51
|
+
*
|
|
52
|
+
* Holds exclusive access to the `serpent` WASM module from construction
|
|
53
|
+
* until `dispose()`. Constructing a second SerpentCtr/SerpentCbc/
|
|
54
|
+
* SerpentCipher or any other serpent user while this instance is live
|
|
55
|
+
* throws. Call `dispose()` when done.
|
|
18
56
|
*/
|
|
19
57
|
export declare class SerpentCtr {
|
|
20
58
|
private readonly x;
|
|
59
|
+
private _tok;
|
|
21
60
|
constructor(opts?: {
|
|
22
61
|
dangerUnauthenticated: true;
|
|
23
62
|
});
|
|
63
|
+
/**
|
|
64
|
+
* Load key and nonce into WASM state and reset the block counter to 0.
|
|
65
|
+
* Must be called before each message.
|
|
66
|
+
* @param key 16, 24, or 32 bytes
|
|
67
|
+
* @param nonce 16 bytes, must be unique per (key, message)
|
|
68
|
+
*/
|
|
24
69
|
beginEncrypt(key: Uint8Array, nonce: Uint8Array): void;
|
|
70
|
+
/**
|
|
71
|
+
* XOR `chunk` with the next keystream block(s). Counter advances automatically.
|
|
72
|
+
* @param chunk Plaintext chunk, must not exceed WASM CHUNK_SIZE
|
|
73
|
+
* @returns Ciphertext of the same length
|
|
74
|
+
*/
|
|
25
75
|
encryptChunk(chunk: Uint8Array): Uint8Array;
|
|
76
|
+
/**
|
|
77
|
+
* Alias for `beginEncrypt`, CTR mode is symmetric.
|
|
78
|
+
* @param key 16, 24, or 32 bytes
|
|
79
|
+
* @param nonce 16 bytes, must match the value used to encrypt
|
|
80
|
+
*/
|
|
26
81
|
beginDecrypt(key: Uint8Array, nonce: Uint8Array): void;
|
|
82
|
+
/**
|
|
83
|
+
* Alias for `encryptChunk`, CTR mode is symmetric.
|
|
84
|
+
* @param chunk Ciphertext chunk
|
|
85
|
+
* @returns Plaintext of the same length
|
|
86
|
+
*/
|
|
27
87
|
decryptChunk(chunk: Uint8Array): Uint8Array;
|
|
88
|
+
/** Wipe WASM state and release exclusive module access. Idempotent. */
|
|
28
89
|
dispose(): void;
|
|
29
90
|
}
|
|
30
91
|
export { SerpentCbc } from './serpent-cbc.js';
|
|
31
92
|
export { AuthenticationError } from '../errors.js';
|
|
32
93
|
export { SerpentCipher } from './cipher-suite.js';
|
|
33
|
-
export
|
|
94
|
+
export { SerpentGenerator } from './generator.js';
|
package/dist/serpent/index.js
CHANGED
|
@@ -22,29 +22,60 @@
|
|
|
22
22
|
// src/ts/serpent/index.ts
|
|
23
23
|
//
|
|
24
24
|
// Public API classes for the Serpent-256 WASM module.
|
|
25
|
-
// Uses the init() module cache
|
|
26
|
-
import { getInstance, initModule } from '../init.js';
|
|
25
|
+
// Uses the init() module cache, call serpentInit(source) before constructing.
|
|
26
|
+
import { getInstance, initModule, _acquireModule, _releaseModule, _assertNotOwned } from '../init.js';
|
|
27
|
+
/**
|
|
28
|
+
* Load and initialise the Serpent WASM module from `source`.
|
|
29
|
+
* Must be called before constructing any Serpent class.
|
|
30
|
+
* @param source WASM binary, gzip+base64 string, URL, ArrayBuffer, Uint8Array,
|
|
31
|
+
* pre-compiled WebAssembly.Module, Response, or Promise<Response>
|
|
32
|
+
*/
|
|
27
33
|
export async function serpentInit(source) {
|
|
28
34
|
return initModule('serpent', source);
|
|
29
35
|
}
|
|
36
|
+
export { isInitialized } from '../init.js';
|
|
37
|
+
/** Returns the raw serpent WASM export object. @internal */
|
|
30
38
|
function getExports() {
|
|
31
39
|
return getInstance('serpent').exports;
|
|
32
40
|
}
|
|
33
|
-
// ── Serpent
|
|
41
|
+
// ── Serpent ─────────────────────────────────────────────────────────────────
|
|
42
|
+
/**
|
|
43
|
+
* Low-level Serpent-256 block cipher, raw ECB encrypt/decrypt.
|
|
44
|
+
*
|
|
45
|
+
* Atomic (stateless) class: each method call is independent.
|
|
46
|
+
* Does not hold exclusive module access; cannot be used while a stateful
|
|
47
|
+
* instance (`SerpentCtr`, `SerpentCbc`, `SerpentCipher`) is alive.
|
|
48
|
+
* Call `dispose()` after use to wipe WASM key material.
|
|
49
|
+
*/
|
|
34
50
|
export class Serpent {
|
|
35
51
|
x;
|
|
36
52
|
constructor() {
|
|
37
53
|
this.x = getExports();
|
|
38
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Expand `key` into the WASM key schedule. Must be called before
|
|
57
|
+
* `encryptBlock` / `decryptBlock`.
|
|
58
|
+
* @param key 16, 24, or 32 bytes
|
|
59
|
+
*/
|
|
39
60
|
loadKey(key) {
|
|
61
|
+
_assertNotOwned('serpent');
|
|
40
62
|
if (key.length !== 16 && key.length !== 24 && key.length !== 32)
|
|
41
63
|
throw new RangeError(`key must be 16, 24, or 32 bytes (got ${key.length})`);
|
|
42
64
|
const mem = new Uint8Array(this.x.memory.buffer);
|
|
43
65
|
mem.set(key, this.x.getKeyOffset());
|
|
44
|
-
if (this.x.loadKey(key.length) !== 0)
|
|
66
|
+
if (this.x.loadKey(key.length) !== 0) {
|
|
67
|
+
this.x.wipeBuffers();
|
|
45
68
|
throw new Error('loadKey failed');
|
|
69
|
+
}
|
|
46
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Encrypt one 128-bit block with the previously loaded key schedule.
|
|
73
|
+
* Serpent AES submission §2.2.
|
|
74
|
+
* @param plaintext 16-byte plaintext block
|
|
75
|
+
* @returns 16-byte ciphertext block
|
|
76
|
+
*/
|
|
47
77
|
encryptBlock(plaintext) {
|
|
78
|
+
_assertNotOwned('serpent');
|
|
48
79
|
if (plaintext.length !== 16)
|
|
49
80
|
throw new RangeError(`block must be 16 bytes (got ${plaintext.length})`);
|
|
50
81
|
const mem = new Uint8Array(this.x.memory.buffer);
|
|
@@ -54,7 +85,14 @@ export class Serpent {
|
|
|
54
85
|
this.x.encryptBlock();
|
|
55
86
|
return mem.slice(ctOff, ctOff + 16);
|
|
56
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Decrypt one 128-bit block with the previously loaded key schedule.
|
|
90
|
+
* Serpent AES submission §2.2.
|
|
91
|
+
* @param ciphertext 16-byte ciphertext block
|
|
92
|
+
* @returns 16-byte plaintext block
|
|
93
|
+
*/
|
|
57
94
|
decryptBlock(ciphertext) {
|
|
95
|
+
_assertNotOwned('serpent');
|
|
58
96
|
if (ciphertext.length !== 16)
|
|
59
97
|
throw new RangeError(`block must be 16 bytes (got ${ciphertext.length})`);
|
|
60
98
|
const mem = new Uint8Array(this.x.memory.buffer);
|
|
@@ -64,28 +102,45 @@ export class Serpent {
|
|
|
64
102
|
this.x.decryptBlock();
|
|
65
103
|
return mem.slice(ptOff, ptOff + 16);
|
|
66
104
|
}
|
|
105
|
+
/** Wipe WASM key material and release memory. */
|
|
67
106
|
dispose() {
|
|
107
|
+
_assertNotOwned('serpent');
|
|
68
108
|
this.x.wipeBuffers();
|
|
69
109
|
}
|
|
70
110
|
}
|
|
71
|
-
// ── SerpentCtr
|
|
111
|
+
// ── SerpentCtr ──────────────────────────────────────────────────────────────
|
|
72
112
|
/**
|
|
73
113
|
* Serpent-256 in CTR mode.
|
|
74
114
|
*
|
|
75
115
|
* **WARNING: CTR mode is unauthenticated.** An attacker can flip ciphertext
|
|
76
116
|
* bits without detection. Always pair with HMAC-SHA256 (Encrypt-then-MAC)
|
|
77
117
|
* or use `XChaCha20Poly1305` instead.
|
|
118
|
+
*
|
|
119
|
+
* Holds exclusive access to the `serpent` WASM module from construction
|
|
120
|
+
* until `dispose()`. Constructing a second SerpentCtr/SerpentCbc/
|
|
121
|
+
* SerpentCipher or any other serpent user while this instance is live
|
|
122
|
+
* throws. Call `dispose()` when done.
|
|
78
123
|
*/
|
|
79
124
|
export class SerpentCtr {
|
|
80
125
|
x;
|
|
126
|
+
_tok;
|
|
81
127
|
constructor(opts) {
|
|
82
128
|
if (!opts?.dangerUnauthenticated) {
|
|
83
|
-
throw new Error('leviathan-crypto: SerpentCtr is unauthenticated
|
|
129
|
+
throw new Error('leviathan-crypto: SerpentCtr is unauthenticated, use Seal with SerpentCipher instead. ' +
|
|
84
130
|
'To use SerpentCtr directly, pass { dangerUnauthenticated: true }.');
|
|
85
131
|
}
|
|
86
132
|
this.x = getExports();
|
|
133
|
+
this._tok = _acquireModule('serpent');
|
|
87
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Load key and nonce into WASM state and reset the block counter to 0.
|
|
137
|
+
* Must be called before each message.
|
|
138
|
+
* @param key 16, 24, or 32 bytes
|
|
139
|
+
* @param nonce 16 bytes, must be unique per (key, message)
|
|
140
|
+
*/
|
|
88
141
|
beginEncrypt(key, nonce) {
|
|
142
|
+
if (this._tok === undefined)
|
|
143
|
+
throw new Error('SerpentCtr: instance has been disposed');
|
|
89
144
|
if (key.length !== 16 && key.length !== 24 && key.length !== 32)
|
|
90
145
|
throw new RangeError('key must be 16, 24, or 32 bytes');
|
|
91
146
|
if (nonce.length !== 16)
|
|
@@ -93,13 +148,23 @@ export class SerpentCtr {
|
|
|
93
148
|
const mem = new Uint8Array(this.x.memory.buffer);
|
|
94
149
|
mem.set(key, this.x.getKeyOffset());
|
|
95
150
|
mem.set(nonce, this.x.getNonceOffset());
|
|
96
|
-
this.x.loadKey(key.length)
|
|
151
|
+
if (this.x.loadKey(key.length) !== 0) {
|
|
152
|
+
this.x.wipeBuffers();
|
|
153
|
+
throw new Error('SerpentCtr: loadKey failed');
|
|
154
|
+
}
|
|
97
155
|
this.x.resetCounter();
|
|
98
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* XOR `chunk` with the next keystream block(s). Counter advances automatically.
|
|
159
|
+
* @param chunk Plaintext chunk, must not exceed WASM CHUNK_SIZE
|
|
160
|
+
* @returns Ciphertext of the same length
|
|
161
|
+
*/
|
|
99
162
|
encryptChunk(chunk) {
|
|
163
|
+
if (this._tok === undefined)
|
|
164
|
+
throw new Error('SerpentCtr: instance has been disposed');
|
|
100
165
|
const maxChunk = this.x.getChunkSize();
|
|
101
166
|
if (chunk.length > maxChunk)
|
|
102
|
-
throw new RangeError(`chunk exceeds maximum size of ${maxChunk} bytes
|
|
167
|
+
throw new RangeError(`chunk exceeds maximum size of ${maxChunk} bytes, split into smaller chunks`);
|
|
103
168
|
const mem = new Uint8Array(this.x.memory.buffer);
|
|
104
169
|
const ptOff = this.x.getChunkPtOffset();
|
|
105
170
|
const ctOff = this.x.getChunkCtOffset();
|
|
@@ -107,28 +172,39 @@ export class SerpentCtr {
|
|
|
107
172
|
this.x.encryptChunk_simd(chunk.length);
|
|
108
173
|
return mem.slice(ctOff, ctOff + chunk.length);
|
|
109
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Alias for `beginEncrypt`, CTR mode is symmetric.
|
|
177
|
+
* @param key 16, 24, or 32 bytes
|
|
178
|
+
* @param nonce 16 bytes, must match the value used to encrypt
|
|
179
|
+
*/
|
|
110
180
|
beginDecrypt(key, nonce) {
|
|
111
181
|
this.beginEncrypt(key, nonce);
|
|
112
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Alias for `encryptChunk`, CTR mode is symmetric.
|
|
185
|
+
* @param chunk Ciphertext chunk
|
|
186
|
+
* @returns Plaintext of the same length
|
|
187
|
+
*/
|
|
113
188
|
decryptChunk(chunk) {
|
|
114
189
|
return this.encryptChunk(chunk);
|
|
115
190
|
}
|
|
191
|
+
/** Wipe WASM state and release exclusive module access. Idempotent. */
|
|
116
192
|
dispose() {
|
|
117
|
-
this.
|
|
193
|
+
if (this._tok === undefined)
|
|
194
|
+
return;
|
|
195
|
+
try {
|
|
196
|
+
this.x.wipeBuffers();
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
_releaseModule('serpent', this._tok);
|
|
200
|
+
this._tok = undefined;
|
|
201
|
+
}
|
|
118
202
|
}
|
|
119
203
|
}
|
|
120
|
-
// ── SerpentCbc
|
|
204
|
+
// ── SerpentCbc ──────────────────────────────────────────────────────────────
|
|
121
205
|
export { SerpentCbc } from './serpent-cbc.js';
|
|
122
206
|
export { AuthenticationError } from '../errors.js';
|
|
123
|
-
// ── SerpentCipher re-export
|
|
207
|
+
// ── SerpentCipher re-export ─────────────────────────────────────────────────
|
|
124
208
|
export { SerpentCipher } from './cipher-suite.js';
|
|
125
|
-
// ──
|
|
126
|
-
export
|
|
127
|
-
try {
|
|
128
|
-
getInstance('serpent');
|
|
129
|
-
return true;
|
|
130
|
-
}
|
|
131
|
-
catch {
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
209
|
+
// ── SerpentGenerator ────────────────────────────────────────────────────────
|
|
210
|
+
export { SerpentGenerator } from './generator.js';
|
|
@@ -3,108 +3,31 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Worker for SealStreamPool with SerpentCipher.
|
|
5
5
|
// Holds 3 derived keys (enc/mac/iv) and raw WASM instances.
|
|
6
|
-
// Direct WASM calls
|
|
6
|
+
// Direct WASM calls, no initModule (avoids same-thread module cache conflicts
|
|
7
7
|
// in @vitest/web-worker test environment).
|
|
8
|
+
//
|
|
9
|
+
// All HMAC / CBC / PKCS7 primitives come from `./shared-ops.js`, the same
|
|
10
|
+
// module the main-thread `SerpentCipher` uses. Byte-identical output with
|
|
11
|
+
// the main thread is the regression guard (see
|
|
12
|
+
// test/unit/stream/pool-byte-exact.test.ts). Must NOT import from `../init.js`:
|
|
13
|
+
// workers have their own isolated WASM instances, no shared-state registry.
|
|
8
14
|
import { constantTimeEqual, wipe, concat } from '../utils.js';
|
|
9
15
|
import { AuthenticationError } from '../errors.js';
|
|
16
|
+
import { hmacSha256, cbcEncryptChunk, cbcDecryptChunk, } from './shared-ops.js';
|
|
10
17
|
let sha2;
|
|
11
18
|
let serpent;
|
|
12
19
|
let keys;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
mem.set(k, x.getSha256InputOffset());
|
|
25
|
-
x.hmac256Init(k.length);
|
|
26
|
-
feedHmac(msg);
|
|
27
|
-
x.hmac256Final();
|
|
28
|
-
return new Uint8Array(x.memory.buffer).slice(x.getSha256OutOffset(), x.getSha256OutOffset() + 32);
|
|
29
|
-
}
|
|
30
|
-
function feedSha2(data) {
|
|
31
|
-
const x = sha2;
|
|
32
|
-
const mem = new Uint8Array(x.memory.buffer);
|
|
33
|
-
const off = x.getSha256InputOffset();
|
|
34
|
-
let pos = 0;
|
|
35
|
-
while (pos < data.length) {
|
|
36
|
-
const n = Math.min(data.length - pos, 64);
|
|
37
|
-
mem.set(data.subarray(pos, pos + n), off);
|
|
38
|
-
x.sha256Update(n);
|
|
39
|
-
pos += n;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function feedHmac(data) {
|
|
43
|
-
const x = sha2;
|
|
44
|
-
const mem = new Uint8Array(x.memory.buffer);
|
|
45
|
-
const off = x.getSha256InputOffset();
|
|
46
|
-
let pos = 0;
|
|
47
|
-
while (pos < data.length) {
|
|
48
|
-
const n = Math.min(data.length - pos, 64);
|
|
49
|
-
mem.set(data.subarray(pos, pos + n), off);
|
|
50
|
-
x.hmac256Update(n);
|
|
51
|
-
pos += n;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function pkcs7Pad(data) {
|
|
55
|
-
const padLen = 16 - (data.length % 16);
|
|
56
|
-
const out = new Uint8Array(data.length + padLen);
|
|
57
|
-
out.set(data);
|
|
58
|
-
out.fill(padLen, data.length);
|
|
59
|
-
return out;
|
|
60
|
-
}
|
|
61
|
-
// pkcs7Strip is only called after HMAC authentication succeeds (verify-then-decrypt).
|
|
62
|
-
// The early throw on invalid padLen is not a padding oracle in this context —
|
|
63
|
-
// the HMAC check is the oracle gate and runs in constant time before this point.
|
|
64
|
-
// If you move this call to a pre-auth site, revisit the timing properties.
|
|
65
|
-
function pkcs7Strip(data) {
|
|
66
|
-
if (data.length === 0)
|
|
67
|
-
throw new RangeError('empty ciphertext');
|
|
68
|
-
const padLen = data[data.length - 1];
|
|
69
|
-
if (padLen === 0 || padLen > 16)
|
|
70
|
-
throw new RangeError('invalid PKCS7 padding');
|
|
71
|
-
if (padLen > data.length)
|
|
72
|
-
throw new RangeError('invalid PKCS7 padding');
|
|
73
|
-
let bad = 0;
|
|
74
|
-
for (let i = data.length - padLen; i < data.length; i++)
|
|
75
|
-
bad |= data[i] ^ padLen;
|
|
76
|
-
if (bad !== 0)
|
|
77
|
-
throw new RangeError('invalid PKCS7 padding');
|
|
78
|
-
return data.subarray(0, data.length - padLen);
|
|
79
|
-
}
|
|
80
|
-
function cbcEncrypt(encKey, iv, plaintext) {
|
|
81
|
-
const s = serpent;
|
|
82
|
-
const mem = new Uint8Array(s.memory.buffer);
|
|
83
|
-
mem.set(encKey, s.getKeyOffset());
|
|
84
|
-
s.loadKey(encKey.length);
|
|
85
|
-
mem.set(iv, s.getCbcIvOffset());
|
|
86
|
-
const padded = pkcs7Pad(plaintext);
|
|
87
|
-
mem.set(padded, s.getChunkPtOffset());
|
|
88
|
-
const ret = s.cbcEncryptChunk(padded.length);
|
|
89
|
-
if (ret < 0)
|
|
90
|
-
throw new RangeError(`cbcEncryptChunk rejected len=${padded.length}` +
|
|
91
|
-
` (WASM CHUNK_SIZE=${s.getChunkSize()})`);
|
|
92
|
-
return new Uint8Array(s.memory.buffer).slice(s.getChunkCtOffset(), s.getChunkCtOffset() + padded.length);
|
|
93
|
-
}
|
|
94
|
-
function cbcDecrypt(encKey, iv, ct) {
|
|
95
|
-
const s = serpent;
|
|
96
|
-
const mem = new Uint8Array(s.memory.buffer);
|
|
97
|
-
mem.set(encKey, s.getKeyOffset());
|
|
98
|
-
s.loadKey(encKey.length);
|
|
99
|
-
mem.set(iv, s.getCbcIvOffset());
|
|
100
|
-
mem.set(ct, s.getChunkCtOffset());
|
|
101
|
-
const ret = s.cbcDecryptChunk(ct.length);
|
|
102
|
-
if (ret < 0)
|
|
103
|
-
throw new RangeError(`cbcDecryptChunk rejected len=${ct.length}` +
|
|
104
|
-
` (WASM CHUNK_SIZE=${s.getChunkSize()})`);
|
|
105
|
-
const raw = new Uint8Array(s.memory.buffer).slice(s.getChunkPtOffset(), s.getChunkPtOffset() + ct.length);
|
|
106
|
-
return pkcs7Strip(raw);
|
|
107
|
-
}
|
|
20
|
+
/**
|
|
21
|
+
* Message handler for the Serpent pool worker.
|
|
22
|
+
*
|
|
23
|
+
* Accepts three message types:
|
|
24
|
+
* - `'init'` , instantiate sha2 + serpent WASM modules and store derived keys
|
|
25
|
+
* - `'wipe'` , zero keys and WASM buffers, then post `{ type: 'wiped' }`
|
|
26
|
+
* - `{ op: 'seal' | 'open', ... }`, encrypt or decrypt one chunk
|
|
27
|
+
*
|
|
28
|
+
* Replies with `{ type: 'result', id, data }` on success or
|
|
29
|
+
* `{ type: 'error', id, message, isAuthError }` on failure.
|
|
30
|
+
*/
|
|
108
31
|
self.onmessage = async (e) => {
|
|
109
32
|
const msg = e.data;
|
|
110
33
|
if (msg.type === 'init') {
|
|
@@ -122,6 +45,8 @@ self.onmessage = async (e) => {
|
|
|
122
45
|
self.postMessage({ type: 'ready' });
|
|
123
46
|
}
|
|
124
47
|
catch (err) {
|
|
48
|
+
if (msg.derivedKeyBytes)
|
|
49
|
+
msg.derivedKeyBytes.fill(0);
|
|
125
50
|
self.postMessage({ type: 'error', id: -1, message: err.message, isAuthError: false });
|
|
126
51
|
}
|
|
127
52
|
return;
|
|
@@ -136,6 +61,7 @@ self.onmessage = async (e) => {
|
|
|
136
61
|
serpent.wipeBuffers();
|
|
137
62
|
sha2 = undefined;
|
|
138
63
|
serpent = undefined;
|
|
64
|
+
self.postMessage({ type: 'wiped' });
|
|
139
65
|
return;
|
|
140
66
|
}
|
|
141
67
|
if (!keys || !sha2 || !serpent) {
|
|
@@ -151,14 +77,14 @@ self.onmessage = async (e) => {
|
|
|
151
77
|
const ivKey = jobKey.subarray(64, 96);
|
|
152
78
|
let result;
|
|
153
79
|
if (op === 'seal') {
|
|
154
|
-
const ivFull = hmacSha256(ivKey, counterNonce);
|
|
80
|
+
const ivFull = hmacSha256(sha2, ivKey, counterNonce);
|
|
155
81
|
const iv = ivFull.slice(0, 16);
|
|
156
82
|
wipe(ivFull);
|
|
157
|
-
const ct =
|
|
83
|
+
const ct = cbcEncryptChunk(serpent, encKey, iv, data);
|
|
158
84
|
const aadLenBuf = new Uint8Array(4);
|
|
159
85
|
new DataView(aadLenBuf.buffer).setUint32(0, aadBytes.length, false);
|
|
160
86
|
const tagInput = concat(counterNonce, aadLenBuf, aadBytes, ct);
|
|
161
|
-
const tag = hmacSha256(macKey, tagInput);
|
|
87
|
+
const tag = hmacSha256(sha2, macKey, tagInput);
|
|
162
88
|
result = concat(ct, tag);
|
|
163
89
|
wipe(iv);
|
|
164
90
|
wipe(tagInput);
|
|
@@ -166,13 +92,13 @@ self.onmessage = async (e) => {
|
|
|
166
92
|
else {
|
|
167
93
|
const ct = data.subarray(0, data.length - 32);
|
|
168
94
|
const receivedTag = data.subarray(data.length - 32);
|
|
169
|
-
const ivFull = hmacSha256(ivKey, counterNonce);
|
|
95
|
+
const ivFull = hmacSha256(sha2, ivKey, counterNonce);
|
|
170
96
|
const iv = ivFull.slice(0, 16);
|
|
171
97
|
wipe(ivFull);
|
|
172
98
|
const aadLenBuf = new Uint8Array(4);
|
|
173
99
|
new DataView(aadLenBuf.buffer).setUint32(0, aadBytes.length, false);
|
|
174
100
|
const tagInput = concat(counterNonce, aadLenBuf, aadBytes, ct);
|
|
175
|
-
const expectedTag = hmacSha256(macKey, tagInput);
|
|
101
|
+
const expectedTag = hmacSha256(sha2, macKey, tagInput);
|
|
176
102
|
// CRITICAL: verify HMAC before decrypting (Vaudenay 2002)
|
|
177
103
|
if (!constantTimeEqual(expectedTag, receivedTag)) {
|
|
178
104
|
wipe(iv);
|
|
@@ -182,7 +108,7 @@ self.onmessage = async (e) => {
|
|
|
182
108
|
}
|
|
183
109
|
wipe(tagInput);
|
|
184
110
|
wipe(expectedTag);
|
|
185
|
-
result =
|
|
111
|
+
result = cbcDecryptChunk(serpent, encKey, iv, ct);
|
|
186
112
|
wipe(iv);
|
|
187
113
|
}
|
|
188
114
|
const transfer = result.buffer instanceof ArrayBuffer ? [result.buffer] : [];
|
|
@@ -3,28 +3,38 @@
|
|
|
3
3
|
*
|
|
4
4
|
* **WARNING: CBC mode is unauthenticated.** Always authenticate the output
|
|
5
5
|
* with HMAC-SHA256 (Encrypt-then-MAC) or use `XChaCha20Poly1305` instead.
|
|
6
|
+
*
|
|
7
|
+
* Holds exclusive access to the `serpent` WASM module from construction
|
|
8
|
+
* until `dispose()`. Constructing a second SerpentCbc/SerpentCtr/
|
|
9
|
+
* SerpentCipher or any other serpent user while this instance is live
|
|
10
|
+
* throws. Call `dispose()` when done.
|
|
6
11
|
*/
|
|
7
12
|
export declare class SerpentCbc {
|
|
8
13
|
private readonly x;
|
|
14
|
+
private _tok;
|
|
9
15
|
constructor(opts?: {
|
|
10
16
|
dangerUnauthenticated: true;
|
|
11
17
|
});
|
|
12
|
-
private get mem();
|
|
13
18
|
/**
|
|
14
19
|
* Encrypt plaintext with Serpent-256 CBC + PKCS7 padding.
|
|
15
20
|
*
|
|
16
21
|
* @param key 16, 24, or 32 bytes
|
|
17
|
-
* @param iv 16 bytes
|
|
18
|
-
* @param plaintext any length
|
|
22
|
+
* @param iv 16 bytes, must be random and unique per (key, message)
|
|
23
|
+
* @param plaintext any length, PKCS7 padding applied automatically
|
|
19
24
|
* @returns ciphertext (length = ceil((plaintext.length + 1) / 16) * 16)
|
|
20
25
|
*/
|
|
21
26
|
encrypt(key: Uint8Array, iv: Uint8Array, plaintext: Uint8Array): Uint8Array;
|
|
22
27
|
/**
|
|
23
28
|
* Decrypt Serpent-256 CBC + PKCS7.
|
|
24
|
-
*
|
|
29
|
+
*
|
|
30
|
+
* All failure modes, empty input, non-multiple-of-16 length, and any
|
|
31
|
+
* PKCS7 validation failure, throw the same generic `RangeError` with
|
|
32
|
+
* message `'invalid ciphertext'`. Padding validation runs branch-free
|
|
33
|
+
* over the last 16 bytes regardless of where the mismatch is, closing
|
|
34
|
+
* the Vaudenay 2002 padding-oracle surface for callers using
|
|
35
|
+
* `{ dangerUnauthenticated: true }` without an outer HMAC.
|
|
25
36
|
*/
|
|
26
37
|
decrypt(key: Uint8Array, iv: Uint8Array, ciphertext: Uint8Array): Uint8Array;
|
|
38
|
+
/** Wipe WASM state and release exclusive module access. Idempotent. */
|
|
27
39
|
dispose(): void;
|
|
28
|
-
private _loadKey;
|
|
29
|
-
private _setIv;
|
|
30
40
|
}
|