@lindorm/aes 0.5.5 → 0.6.1
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/CHANGELOG.md +30 -0
- package/MERMAID.md +155 -0
- package/README.md +365 -199
- package/__tests__/INTEROP-RESULTS.md +66 -0
- package/__tests__/esm-smoke.test.ts +15 -0
- package/__tests__/fixtures/keys.ts +60 -0
- package/__tests__/helpers/buffer-utils.ts +11 -0
- package/__tests__/helpers/index.ts +2 -0
- package/__tests__/helpers/jwe-adapter.ts +117 -0
- package/__tests__/jose-jwe.test.ts +463 -0
- package/__tests__/noble-ciphers.test.ts +208 -0
- package/dist/classes/AesKit.d.ts +10 -8
- package/dist/classes/AesKit.d.ts.map +1 -1
- package/dist/classes/AesKit.js +73 -34
- package/dist/classes/AesKit.js.map +1 -1
- package/dist/constants/private/index.d.ts +0 -1
- package/dist/constants/private/index.d.ts.map +1 -1
- package/dist/constants/private/index.js +0 -1
- package/dist/constants/private/index.js.map +1 -1
- package/dist/constants/private/version.d.ts +3 -1
- package/dist/constants/private/version.d.ts.map +1 -1
- package/dist/constants/private/version.js +4 -2
- package/dist/constants/private/version.js.map +1 -1
- package/dist/interfaces/AesKit.d.ts +12 -7
- package/dist/interfaces/AesKit.d.ts.map +1 -1
- package/dist/mocks/mock-aes-kit.d.ts.map +1 -1
- package/dist/mocks/mock-aes-kit.js +12 -2
- package/dist/mocks/mock-aes-kit.js.map +1 -1
- package/dist/types/aes-decryption-data.d.ts +26 -17
- package/dist/types/aes-decryption-data.d.ts.map +1 -1
- package/dist/types/aes-encryption-data.d.ts +7 -17
- package/dist/types/aes-encryption-data.d.ts.map +1 -1
- package/dist/types/content.d.ts +1 -1
- package/dist/types/content.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/private/aes-data.d.ts.map +1 -1
- package/dist/types/private/aes-key-derivation.d.ts +1 -1
- package/dist/types/private/aes-key-derivation.d.ts.map +1 -1
- package/dist/types/private/auth-tag.d.ts +3 -0
- package/dist/types/private/auth-tag.d.ts.map +1 -1
- package/dist/types/private/content-encryption-key.d.ts +4 -2
- package/dist/types/private/content-encryption-key.d.ts.map +1 -1
- package/dist/types/private/index.d.ts +1 -1
- package/dist/types/private/index.d.ts.map +1 -1
- package/dist/types/private/index.js +1 -1
- package/dist/types/private/index.js.map +1 -1
- package/dist/types/private/prepared-encryption.d.ts +35 -0
- package/dist/types/private/prepared-encryption.d.ts.map +1 -0
- package/dist/types/private/{aes-string.js → prepared-encryption.js} +1 -1
- package/dist/types/private/prepared-encryption.js.map +1 -0
- package/dist/utils/is-aes.d.ts.map +1 -1
- package/dist/utils/is-aes.js +1 -5
- package/dist/utils/is-aes.js.map +1 -1
- package/dist/utils/parse-aes.js +3 -3
- package/dist/utils/parse-aes.js.map +1 -1
- package/dist/utils/private/aes-header.d.ts +42 -0
- package/dist/utils/private/aes-header.d.ts.map +1 -0
- package/dist/utils/private/aes-header.js +75 -0
- package/dist/utils/private/aes-header.js.map +1 -0
- package/dist/utils/private/calculate/calculate-content-encryption-key-size.js +3 -3
- package/dist/utils/private/calculate/calculate-key-wrap-encryption.d.ts.map +1 -1
- package/dist/utils/private/calculate/calculate-key-wrap-encryption.js +2 -1
- package/dist/utils/private/calculate/calculate-key-wrap-encryption.js.map +1 -1
- package/dist/utils/private/content.js +1 -1
- package/dist/utils/private/content.js.map +1 -1
- package/dist/utils/private/data/auth-tag-hmac.d.ts +2 -2
- package/dist/utils/private/data/auth-tag-hmac.d.ts.map +1 -1
- package/dist/utils/private/data/auth-tag-hmac.js +12 -4
- package/dist/utils/private/data/auth-tag-hmac.js.map +1 -1
- package/dist/utils/private/data/auth-tag.d.ts +2 -2
- package/dist/utils/private/data/auth-tag.d.ts.map +1 -1
- package/dist/utils/private/data/auth-tag.js +4 -2
- package/dist/utils/private/data/auth-tag.js.map +1 -1
- package/dist/utils/private/data/split-content-encryption-key.d.ts.map +1 -1
- package/dist/utils/private/data/split-content-encryption-key.js +6 -2
- package/dist/utils/private/data/split-content-encryption-key.js.map +1 -1
- package/dist/utils/private/diffie-hellman/diffie-hellman-key-wrap.d.ts +2 -2
- package/dist/utils/private/diffie-hellman/diffie-hellman-key-wrap.d.ts.map +1 -1
- package/dist/utils/private/diffie-hellman/diffie-hellman-key-wrap.js +12 -8
- package/dist/utils/private/diffie-hellman/diffie-hellman-key-wrap.js.map +1 -1
- package/dist/utils/private/diffie-hellman/diffie-hellman.d.ts +2 -2
- package/dist/utils/private/diffie-hellman/diffie-hellman.d.ts.map +1 -1
- package/dist/utils/private/diffie-hellman/diffie-hellman.js +12 -8
- package/dist/utils/private/diffie-hellman/diffie-hellman.js.map +1 -1
- package/dist/utils/private/diffie-hellman/shared-secret.d.ts.map +1 -1
- package/dist/utils/private/diffie-hellman/shared-secret.js +5 -1
- package/dist/utils/private/diffie-hellman/shared-secret.js.map +1 -1
- package/dist/utils/private/encoded-aes.d.ts +2 -2
- package/dist/utils/private/encoded-aes.d.ts.map +1 -1
- package/dist/utils/private/encoded-aes.js +86 -149
- package/dist/utils/private/encoded-aes.js.map +1 -1
- package/dist/utils/private/encrypt-content.d.ts +3 -0
- package/dist/utils/private/encrypt-content.d.ts.map +1 -0
- package/dist/utils/private/encrypt-content.js +35 -0
- package/dist/utils/private/encrypt-content.js.map +1 -0
- package/dist/utils/private/encrypt-encoded.d.ts +9 -0
- package/dist/utils/private/encrypt-encoded.d.ts.map +1 -0
- package/dist/utils/private/encrypt-encoded.js +53 -0
- package/dist/utils/private/encrypt-encoded.js.map +1 -0
- package/dist/utils/private/encrypt-serialised.d.ts +9 -0
- package/dist/utils/private/encrypt-serialised.d.ts.map +1 -0
- package/dist/utils/private/encrypt-serialised.js +48 -0
- package/dist/utils/private/encrypt-serialised.js.map +1 -0
- package/dist/utils/private/encrypt-tokenised.d.ts +9 -0
- package/dist/utils/private/encrypt-tokenised.d.ts.map +1 -0
- package/dist/utils/private/encrypt-tokenised.js +45 -0
- package/dist/utils/private/encrypt-tokenised.js.map +1 -0
- package/dist/utils/private/encryption.d.ts.map +1 -1
- package/dist/utils/private/encryption.js +27 -27
- package/dist/utils/private/encryption.js.map +1 -1
- package/dist/utils/private/index.d.ts +6 -0
- package/dist/utils/private/index.d.ts.map +1 -1
- package/dist/utils/private/index.js +6 -0
- package/dist/utils/private/index.js.map +1 -1
- package/dist/utils/private/key-derivation/concat-kdf.d.ts +14 -0
- package/dist/utils/private/key-derivation/concat-kdf.d.ts.map +1 -0
- package/dist/utils/private/key-derivation/concat-kdf.js +26 -0
- package/dist/utils/private/key-derivation/concat-kdf.js.map +1 -0
- package/dist/utils/private/key-derivation/index.d.ts +1 -1
- package/dist/utils/private/key-derivation/index.d.ts.map +1 -1
- package/dist/utils/private/key-derivation/index.js +1 -1
- package/dist/utils/private/key-derivation/index.js.map +1 -1
- package/dist/utils/private/key-derivation/pbkdf.d.ts +1 -0
- package/dist/utils/private/key-derivation/pbkdf.d.ts.map +1 -1
- package/dist/utils/private/key-derivation/pbkdf.js +13 -2
- package/dist/utils/private/key-derivation/pbkdf.js.map +1 -1
- package/dist/utils/private/key-wrap/ecb-key-wrap.d.ts.map +1 -1
- package/dist/utils/private/key-wrap/ecb-key-wrap.js +10 -3
- package/dist/utils/private/key-wrap/ecb-key-wrap.js.map +1 -1
- package/dist/utils/private/key-wrap/gcm-key-wrap.d.ts.map +1 -1
- package/dist/utils/private/key-wrap/gcm-key-wrap.js +6 -0
- package/dist/utils/private/key-wrap/gcm-key-wrap.js.map +1 -1
- package/dist/utils/private/oct/get-oct-key-key-wrap.d.ts +1 -1
- package/dist/utils/private/oct/get-oct-key-key-wrap.d.ts.map +1 -1
- package/dist/utils/private/oct/get-oct-key-key-wrap.js +7 -14
- package/dist/utils/private/oct/get-oct-key-key-wrap.js.map +1 -1
- package/dist/utils/private/oct/get-oct-pbkdf-key-wrap-keys.d.ts.map +1 -1
- package/dist/utils/private/oct/get-oct-pbkdf-key-wrap-keys.js +2 -0
- package/dist/utils/private/oct/get-oct-pbkdf-key-wrap-keys.js.map +1 -1
- package/dist/utils/private/prepare-encryption.d.ts +3 -0
- package/dist/utils/private/prepare-encryption.d.ts.map +1 -0
- package/dist/utils/private/prepare-encryption.js +27 -0
- package/dist/utils/private/prepare-encryption.js.map +1 -0
- package/dist/utils/private/serialised-aes.d.ts.map +1 -1
- package/dist/utils/private/serialised-aes.js +38 -46
- package/dist/utils/private/serialised-aes.js.map +1 -1
- package/dist/utils/private/tokenised-aes.d.ts +3 -3
- package/dist/utils/private/tokenised-aes.d.ts.map +1 -1
- package/dist/utils/private/tokenised-aes.js +73 -55
- package/dist/utils/private/tokenised-aes.js.map +1 -1
- package/dist/utils/private/validate-version.d.ts +2 -0
- package/dist/utils/private/validate-version.d.ts.map +1 -0
- package/dist/utils/private/validate-version.js +27 -0
- package/dist/utils/private/validate-version.js.map +1 -0
- package/jest.config.interop.mjs +24 -0
- package/package.json +18 -16
- package/tsconfig.interop.json +9 -0
- package/dist/constants/private/format.d.ts +0 -2
- package/dist/constants/private/format.d.ts.map +0 -1
- package/dist/constants/private/format.js +0 -5
- package/dist/constants/private/format.js.map +0 -1
- package/dist/types/private/aes-string.d.ts +0 -21
- package/dist/types/private/aes-string.d.ts.map +0 -1
- package/dist/types/private/aes-string.js.map +0 -1
- package/dist/utils/private/key-derivation/hkdf.d.ts +0 -13
- package/dist/utils/private/key-derivation/hkdf.d.ts.map +0 -1
- package/dist/utils/private/key-derivation/hkdf.js +0 -12
- package/dist/utils/private/key-derivation/hkdf.js.map +0 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# AES Interop Test Results
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
All 59 interop tests pass. Zero divergences found between `@lindorm/aes`,
|
|
6
|
+
`@noble/ciphers`, and `jose`.
|
|
7
|
+
|
|
8
|
+
| Suite | Tests | Pass | Fail | Skip |
|
|
9
|
+
| ------------- | ------ | ------ | ----- | ----- |
|
|
10
|
+
| noble-ciphers | 21 | 21 | 0 | 0 |
|
|
11
|
+
| jose-jwe | 38 | 38 | 0 | 0 |
|
|
12
|
+
| **Total** | **59** | **59** | **0** | **0** |
|
|
13
|
+
|
|
14
|
+
## noble/ciphers Primitive Tests
|
|
15
|
+
|
|
16
|
+
| Primitive | Key Sizes | Direction | Result |
|
|
17
|
+
| ----------------- | ------------- | ------------------------------ | ------ |
|
|
18
|
+
| AES-GCM | 128, 192, 256 | ours → noble | PASS |
|
|
19
|
+
| AES-GCM | 128, 192, 256 | noble → ours | PASS |
|
|
20
|
+
| AES-GCM | 128, 192, 256 | byte-identical (pinned IV) | PASS |
|
|
21
|
+
| AES-KW (RFC 3394) | 128, 192, 256 | ours → noble | PASS |
|
|
22
|
+
| AES-KW (RFC 3394) | 128, 192, 256 | noble → ours | PASS |
|
|
23
|
+
| AES-KW (RFC 3394) | 128, 192, 256 | byte-identical (deterministic) | PASS |
|
|
24
|
+
| AES-CBC (raw) | 128, 192, 256 | byte-identical (PKCS7) | PASS |
|
|
25
|
+
|
|
26
|
+
## jose JWE Tests
|
|
27
|
+
|
|
28
|
+
| Algorithm | Encryption | Direction | Result |
|
|
29
|
+
| ---------------------- | ------------------------------------------- | ----------- | ------ |
|
|
30
|
+
| dir | A128GCM, A192GCM, A256GCM | ours → jose | PASS |
|
|
31
|
+
| dir | A128GCM, A192GCM, A256GCM | jose → ours | PASS |
|
|
32
|
+
| dir | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | ours → jose | PASS |
|
|
33
|
+
| dir | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | jose → ours | PASS |
|
|
34
|
+
| A128KW, A192KW, A256KW | A128GCM, A256GCM | ours → jose | PASS |
|
|
35
|
+
| A128KW, A192KW, A256KW | A128GCM, A256GCM | jose → ours | PASS |
|
|
36
|
+
| A128KW, A192KW, A256KW | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | ours → jose | PASS |
|
|
37
|
+
| A128KW, A192KW, A256KW | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | jose → ours | PASS |
|
|
38
|
+
| A128GCMKW, A256GCMKW | A256GCM | ours → jose | PASS |
|
|
39
|
+
| A128GCMKW, A256GCMKW | A256GCM | jose → ours | PASS |
|
|
40
|
+
| Pinned deterministic | A256GCM (byte-identical) | comparison | PASS |
|
|
41
|
+
| Pinned deterministic | A256GCM (round-trip) | comparison | PASS |
|
|
42
|
+
| Pinned deterministic | A128CBC-HS256 (byte-identical) | comparison | PASS |
|
|
43
|
+
| Pinned deterministic | A128CBC-HS256 (round-trip) | comparison | PASS |
|
|
44
|
+
|
|
45
|
+
## Validated RFC Compliance
|
|
46
|
+
|
|
47
|
+
- **RFC 7516** (JWE): AAD computation, flattened serialization format
|
|
48
|
+
- **RFC 7518** (JWA): AES-GCM, AES-CBC-HMAC-SHA2, AES Key Wrap, AES-GCM Key Wrap
|
|
49
|
+
- **RFC 3394**: AES Key Wrap (deterministic, AIV verification)
|
|
50
|
+
|
|
51
|
+
## Notes
|
|
52
|
+
|
|
53
|
+
- GCMKW "ours → jose" direction uses a two-pass approach due to the circular
|
|
54
|
+
dependency between key-wrap params and JWE AAD. Content is re-encrypted with
|
|
55
|
+
the correct AAD after extracting key-wrap params from the first pass.
|
|
56
|
+
- jose v6 rejects `setContentEncryptionKey()` with `alg: "dir"`, so deterministic
|
|
57
|
+
pinned tests use A\*KW algorithms instead. Content encryption is identical
|
|
58
|
+
regardless of key management algorithm.
|
|
59
|
+
- `@noble/ciphers` GCM returns ciphertext with auth tag appended (last 16 bytes).
|
|
60
|
+
Tests correctly split/concatenate when converting between formats.
|
|
61
|
+
|
|
62
|
+
## Environment
|
|
63
|
+
|
|
64
|
+
- Node.js >= 24.4.0
|
|
65
|
+
- `@noble/ciphers` ^1.2.1
|
|
66
|
+
- `jose` ^6.1.3
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { gcm, cbc, aeskw } from "@noble/ciphers/aes";
|
|
2
|
+
import { FlattenedEncrypt, flattenedDecrypt } from "jose";
|
|
3
|
+
|
|
4
|
+
describe("ESM import smoke test", () => {
|
|
5
|
+
test("should import @noble/ciphers", () => {
|
|
6
|
+
expect(gcm).toBeDefined();
|
|
7
|
+
expect(cbc).toBeDefined();
|
|
8
|
+
expect(aeskw).toBeDefined();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("should import jose", () => {
|
|
12
|
+
expect(FlattenedEncrypt).toBeDefined();
|
|
13
|
+
expect(flattenedDecrypt).toBeDefined();
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import {
|
|
3
|
+
Kryptos,
|
|
4
|
+
KryptosAlgorithm,
|
|
5
|
+
KryptosEncryption,
|
|
6
|
+
KryptosKit,
|
|
7
|
+
} from "@lindorm/kryptos";
|
|
8
|
+
|
|
9
|
+
// Fixed raw symmetric keys for dir mode (CEK = key)
|
|
10
|
+
export const RAW_KEY_128 = Buffer.from("000102030405060708090a0b0c0d0e0f", "hex");
|
|
11
|
+
export const RAW_KEY_192 = Buffer.from(
|
|
12
|
+
"000102030405060708090a0b0c0d0e0f1011121314151617",
|
|
13
|
+
"hex",
|
|
14
|
+
);
|
|
15
|
+
export const RAW_KEY_256 = Buffer.from(
|
|
16
|
+
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
|
|
17
|
+
"hex",
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
// CBC-HMAC composite keys (double-length: half for HMAC, half for AES-CBC)
|
|
21
|
+
export const RAW_KEY_256_CBC = Buffer.from(
|
|
22
|
+
"202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f",
|
|
23
|
+
"hex",
|
|
24
|
+
);
|
|
25
|
+
export const RAW_KEY_384_CBC = Buffer.from(
|
|
26
|
+
"404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f",
|
|
27
|
+
"hex",
|
|
28
|
+
);
|
|
29
|
+
export const RAW_KEY_512_CBC = Buffer.from(
|
|
30
|
+
"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf",
|
|
31
|
+
"hex",
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// Key Encryption Keys for KW modes
|
|
35
|
+
export const KEK_128 = Buffer.from("c0c1c2c3c4c5c6c7c8c9cacbcccdcecf", "hex");
|
|
36
|
+
export const KEK_192 = Buffer.from(
|
|
37
|
+
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7",
|
|
38
|
+
"hex",
|
|
39
|
+
);
|
|
40
|
+
export const KEK_256 = Buffer.from(
|
|
41
|
+
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
|
|
42
|
+
"hex",
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Helper to create a Kryptos oct key from raw bytes.
|
|
47
|
+
*/
|
|
48
|
+
export const createOctKryptos = (
|
|
49
|
+
raw: Buffer,
|
|
50
|
+
algorithm: KryptosAlgorithm,
|
|
51
|
+
encryption?: KryptosEncryption,
|
|
52
|
+
): Kryptos =>
|
|
53
|
+
KryptosKit.from.der({
|
|
54
|
+
id: randomUUID(),
|
|
55
|
+
algorithm,
|
|
56
|
+
encryption,
|
|
57
|
+
privateKey: raw,
|
|
58
|
+
type: "oct",
|
|
59
|
+
use: "enc",
|
|
60
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert Buffer to Uint8Array (zero-copy view).
|
|
3
|
+
*/
|
|
4
|
+
export const toUint8Array = (buf: Buffer): Uint8Array =>
|
|
5
|
+
new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Convert Uint8Array to Buffer (zero-copy view).
|
|
9
|
+
*/
|
|
10
|
+
export const toBuffer = (arr: Uint8Array): Buffer =>
|
|
11
|
+
Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { FlattenedJWE } from "jose";
|
|
2
|
+
import type { AesDecryptionRecord } from "../../src/types/aes-decryption-data";
|
|
3
|
+
import type { AesEncryptionRecord } from "../../src/types/aes-encryption-data";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Build a JWE protected header JSON string, its base64url encoding,
|
|
7
|
+
* and the AAD buffer (ASCII bytes of the base64url-encoded header).
|
|
8
|
+
*
|
|
9
|
+
* Per RFC 7516 section 5.1 step 14, the JWE AAD is the ASCII representation
|
|
10
|
+
* of the base64url-encoded protected header.
|
|
11
|
+
*
|
|
12
|
+
* For A*GCMKW algorithms, the key-wrap iv and tag go into the protected header
|
|
13
|
+
* per RFC 7518 section 4.7.
|
|
14
|
+
*/
|
|
15
|
+
export const buildProtectedHeader = (
|
|
16
|
+
algorithm: string,
|
|
17
|
+
encryption: string,
|
|
18
|
+
gcmkwParams?: { iv: Buffer; tag: Buffer },
|
|
19
|
+
): {
|
|
20
|
+
headerJson: string;
|
|
21
|
+
headerB64u: string;
|
|
22
|
+
aadBuffer: Buffer;
|
|
23
|
+
} => {
|
|
24
|
+
const header: Record<string, string> = { alg: algorithm, enc: encryption };
|
|
25
|
+
|
|
26
|
+
if (gcmkwParams) {
|
|
27
|
+
header.iv = gcmkwParams.iv.toString("base64url");
|
|
28
|
+
header.tag = gcmkwParams.tag.toString("base64url");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const headerJson = JSON.stringify(header);
|
|
32
|
+
const headerB64u = Buffer.from(headerJson, "utf8").toString("base64url");
|
|
33
|
+
const aadBuffer = Buffer.from(headerB64u, "ascii");
|
|
34
|
+
|
|
35
|
+
return { headerJson, headerB64u, aadBuffer };
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Convert our AesEncryptionRecord to a jose FlattenedJWE object.
|
|
40
|
+
*
|
|
41
|
+
* Field mapping:
|
|
42
|
+
* - protected: base64url-encoded protected header (passed in)
|
|
43
|
+
* - iv: base64url of record.initialisationVector
|
|
44
|
+
* - ciphertext: base64url of record.content
|
|
45
|
+
* - tag: base64url of record.authTag
|
|
46
|
+
* - encrypted_key: base64url of record.publicEncryptionKey (absent for dir)
|
|
47
|
+
*/
|
|
48
|
+
export const toFlattenedJWE = (
|
|
49
|
+
record: AesEncryptionRecord,
|
|
50
|
+
headerB64u: string,
|
|
51
|
+
): FlattenedJWE => {
|
|
52
|
+
const jwe: FlattenedJWE = {
|
|
53
|
+
protected: headerB64u,
|
|
54
|
+
iv: record.initialisationVector.toString("base64url"),
|
|
55
|
+
ciphertext: record.content.toString("base64url"),
|
|
56
|
+
tag: record.authTag.toString("base64url"),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if (record.publicEncryptionKey) {
|
|
60
|
+
jwe.encrypted_key = record.publicEncryptionKey.toString("base64url");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return jwe;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Convert a jose FlattenedJWE back to our AesDecryptionRecord + the AAD buffer.
|
|
68
|
+
*
|
|
69
|
+
* Parses the protected header to extract algorithm, encryption, and optional
|
|
70
|
+
* GCMKW parameters (iv, tag for key-wrap).
|
|
71
|
+
*
|
|
72
|
+
* Field mapping (inverse of toFlattenedJWE):
|
|
73
|
+
* - content: Buffer from base64url ciphertext
|
|
74
|
+
* - initialisationVector: Buffer from base64url iv
|
|
75
|
+
* - authTag: Buffer from base64url tag
|
|
76
|
+
* - publicEncryptionKey: Buffer from base64url encrypted_key (undefined for dir)
|
|
77
|
+
* - publicEncryptionIv: Buffer from protected header iv param (GCMKW only)
|
|
78
|
+
* - publicEncryptionTag: Buffer from protected header tag param (GCMKW only)
|
|
79
|
+
* - encryption: enc value from protected header
|
|
80
|
+
* - algorithm: alg value from protected header
|
|
81
|
+
*/
|
|
82
|
+
export const fromFlattenedJWE = (
|
|
83
|
+
jwe: FlattenedJWE,
|
|
84
|
+
): {
|
|
85
|
+
record: AesDecryptionRecord;
|
|
86
|
+
aad: Buffer;
|
|
87
|
+
} => {
|
|
88
|
+
if (!jwe.protected) {
|
|
89
|
+
throw new Error("FlattenedJWE missing protected header");
|
|
90
|
+
}
|
|
91
|
+
if (!jwe.iv) {
|
|
92
|
+
throw new Error("FlattenedJWE missing iv");
|
|
93
|
+
}
|
|
94
|
+
if (!jwe.tag) {
|
|
95
|
+
throw new Error("FlattenedJWE missing tag");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const headerJson = Buffer.from(jwe.protected, "base64url").toString("utf8");
|
|
99
|
+
const header = JSON.parse(headerJson) as Record<string, string>;
|
|
100
|
+
|
|
101
|
+
const aad = Buffer.from(jwe.protected, "ascii");
|
|
102
|
+
|
|
103
|
+
const record: AesDecryptionRecord = {
|
|
104
|
+
algorithm: header.alg as AesDecryptionRecord["algorithm"],
|
|
105
|
+
encryption: header.enc as AesDecryptionRecord["encryption"],
|
|
106
|
+
content: Buffer.from(jwe.ciphertext, "base64url"),
|
|
107
|
+
initialisationVector: Buffer.from(jwe.iv, "base64url"),
|
|
108
|
+
authTag: Buffer.from(jwe.tag, "base64url"),
|
|
109
|
+
publicEncryptionKey: jwe.encrypted_key
|
|
110
|
+
? Buffer.from(jwe.encrypted_key, "base64url")
|
|
111
|
+
: undefined,
|
|
112
|
+
publicEncryptionIv: header.iv ? Buffer.from(header.iv, "base64url") : undefined,
|
|
113
|
+
publicEncryptionTag: header.tag ? Buffer.from(header.tag, "base64url") : undefined,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return { record, aad };
|
|
117
|
+
};
|