@airprompter/agent-core 0.1.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/README.md +28 -0
- package/dist/cjs/bundle/apbundle.js +98 -0
- package/dist/cjs/bundle/apbundle.js.map +1 -0
- package/dist/cjs/bundle/hpke.js +120 -0
- package/dist/cjs/bundle/hpke.js.map +1 -0
- package/dist/cjs/checks/index.js +450 -0
- package/dist/cjs/checks/index.js.map +1 -0
- package/dist/cjs/control/client.js +85 -0
- package/dist/cjs/control/client.js.map +1 -0
- package/dist/cjs/golden/index.js +138 -0
- package/dist/cjs/golden/index.js.map +1 -0
- package/dist/cjs/index.js +125 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/judge/index.js +134 -0
- package/dist/cjs/judge/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/ports/node.js +30 -0
- package/dist/cjs/ports/node.js.map +1 -0
- package/dist/cjs/protocol/assignment.js +158 -0
- package/dist/cjs/protocol/assignment.js.map +1 -0
- package/dist/cjs/protocol/canonicalJson.js +72 -0
- package/dist/cjs/protocol/canonicalJson.js.map +1 -0
- package/dist/cjs/protocol/errors.js +22 -0
- package/dist/cjs/protocol/errors.js.map +1 -0
- package/dist/cjs/protocol/ports.js +19 -0
- package/dist/cjs/protocol/ports.js.map +1 -0
- package/dist/cjs/protocol/trust.js +225 -0
- package/dist/cjs/protocol/trust.js.map +1 -0
- package/dist/cjs/protocol/types.js +15 -0
- package/dist/cjs/protocol/types.js.map +1 -0
- package/dist/cjs/protocol/version.js +8 -0
- package/dist/cjs/protocol/version.js.map +1 -0
- package/dist/cjs/release/bundleRelease.js +61 -0
- package/dist/cjs/release/bundleRelease.js.map +1 -0
- package/dist/cjs/release/reader.js +12 -0
- package/dist/cjs/release/reader.js.map +1 -0
- package/dist/cjs/render/runRef.js +33 -0
- package/dist/cjs/render/runRef.js.map +1 -0
- package/dist/cjs/render/template.js +71 -0
- package/dist/cjs/render/template.js.map +1 -0
- package/dist/cjs/telemetry/feedback.js +81 -0
- package/dist/cjs/telemetry/feedback.js.map +1 -0
- package/dist/cjs/telemetry/rows.js +28 -0
- package/dist/cjs/telemetry/rows.js.map +1 -0
- package/dist/cjs/telemetry/uploadSink.js +13 -0
- package/dist/cjs/telemetry/uploadSink.js.map +1 -0
- package/dist/cjs/testing/controlPlane.js +381 -0
- package/dist/cjs/testing/controlPlane.js.map +1 -0
- package/dist/cjs/testing/index.js +45 -0
- package/dist/cjs/testing/index.js.map +1 -0
- package/dist/cjs/testing/memoryFs.js +236 -0
- package/dist/cjs/testing/memoryFs.js.map +1 -0
- package/dist/esm/.tsbuildinfo +1 -0
- package/dist/esm/bundle/apbundle.d.ts +33 -0
- package/dist/esm/bundle/apbundle.js +89 -0
- package/dist/esm/bundle/apbundle.js.map +1 -0
- package/dist/esm/bundle/hpke.d.ts +48 -0
- package/dist/esm/bundle/hpke.js +107 -0
- package/dist/esm/bundle/hpke.js.map +1 -0
- package/dist/esm/checks/index.d.ts +85 -0
- package/dist/esm/checks/index.js +436 -0
- package/dist/esm/checks/index.js.map +1 -0
- package/dist/esm/control/client.d.ts +78 -0
- package/dist/esm/control/client.js +81 -0
- package/dist/esm/control/client.js.map +1 -0
- package/dist/esm/golden/index.d.ts +97 -0
- package/dist/esm/golden/index.js +130 -0
- package/dist/esm/golden/index.js.map +1 -0
- package/dist/esm/index.d.ts +41 -0
- package/dist/esm/index.js +31 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/judge/index.d.ts +51 -0
- package/dist/esm/judge/index.js +127 -0
- package/dist/esm/judge/index.js.map +1 -0
- package/dist/esm/ports/node.d.ts +8 -0
- package/dist/esm/ports/node.js +27 -0
- package/dist/esm/ports/node.js.map +1 -0
- package/dist/esm/protocol/assignment.d.ts +49 -0
- package/dist/esm/protocol/assignment.js +143 -0
- package/dist/esm/protocol/assignment.js.map +1 -0
- package/dist/esm/protocol/canonicalJson.d.ts +10 -0
- package/dist/esm/protocol/canonicalJson.js +65 -0
- package/dist/esm/protocol/canonicalJson.js.map +1 -0
- package/dist/esm/protocol/errors.d.ts +15 -0
- package/dist/esm/protocol/errors.js +19 -0
- package/dist/esm/protocol/errors.js.map +1 -0
- package/dist/esm/protocol/ports.d.ts +65 -0
- package/dist/esm/protocol/ports.js +16 -0
- package/dist/esm/protocol/ports.js.map +1 -0
- package/dist/esm/protocol/trust.d.ts +60 -0
- package/dist/esm/protocol/trust.js +211 -0
- package/dist/esm/protocol/trust.js.map +1 -0
- package/dist/esm/protocol/types.d.ts +235 -0
- package/dist/esm/protocol/types.js +12 -0
- package/dist/esm/protocol/types.js.map +1 -0
- package/dist/esm/protocol/version.d.ts +4 -0
- package/dist/esm/protocol/version.js +5 -0
- package/dist/esm/protocol/version.js.map +1 -0
- package/dist/esm/release/bundleRelease.d.ts +45 -0
- package/dist/esm/release/bundleRelease.js +57 -0
- package/dist/esm/release/bundleRelease.js.map +1 -0
- package/dist/esm/release/reader.d.ts +30 -0
- package/dist/esm/release/reader.js +11 -0
- package/dist/esm/release/reader.js.map +1 -0
- package/dist/esm/render/runRef.d.ts +17 -0
- package/dist/esm/render/runRef.js +29 -0
- package/dist/esm/render/runRef.js.map +1 -0
- package/dist/esm/render/template.d.ts +38 -0
- package/dist/esm/render/template.js +65 -0
- package/dist/esm/render/template.js.map +1 -0
- package/dist/esm/telemetry/feedback.d.ts +21 -0
- package/dist/esm/telemetry/feedback.js +77 -0
- package/dist/esm/telemetry/feedback.js.map +1 -0
- package/dist/esm/telemetry/rows.d.ts +85 -0
- package/dist/esm/telemetry/rows.js +22 -0
- package/dist/esm/telemetry/rows.js.map +1 -0
- package/dist/esm/telemetry/uploadSink.d.ts +52 -0
- package/dist/esm/telemetry/uploadSink.js +12 -0
- package/dist/esm/telemetry/uploadSink.js.map +1 -0
- package/dist/esm/testing/controlPlane.d.ts +116 -0
- package/dist/esm/testing/controlPlane.js +341 -0
- package/dist/esm/testing/controlPlane.js.map +1 -0
- package/dist/esm/testing/index.d.ts +25 -0
- package/dist/esm/testing/index.js +35 -0
- package/dist/esm/testing/index.js.map +1 -0
- package/dist/esm/testing/memoryFs.d.ts +64 -0
- package/dist/esm/testing/memoryFs.js +232 -0
- package/dist/esm/testing/memoryFs.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @airprompter/agent-core
|
|
2
|
+
|
|
3
|
+
The pure half of the AirPrompter agent SDK: the wire types, canonical JSON
|
|
4
|
+
and SHA-256, the trust chain (root metadata R1–R5, manifest M1–M14), arm
|
|
5
|
+
assignment and the signed ramp plan walked on the host's clock, template
|
|
6
|
+
rendering with trust-aware fencing, declared output checks, golden sets,
|
|
7
|
+
the judge, `.apbundle` reading (HPKE), the telemetry row schemas, the
|
|
8
|
+
control-plane HTTP client, and the port interfaces (`FsPort`, `ClockPort`,
|
|
9
|
+
`FetchPort`) with their Node adapters. Nothing here opens a file, a socket
|
|
10
|
+
or a timer at import time, and nothing here depends on a sibling package.
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { verifyManifest, trustedRootFromPinnedKey, assignArm, renderTemplate, BundleRelease } from "@airprompter/agent-core";
|
|
14
|
+
import { FakeControlPlane, MemoryFs, FakeClock } from "@airprompter/agent-core/testing"; // the CI kit; never loaded by a runtime
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`BundleRelease.load({ bundle, root, scope, now })` turns a bundle the
|
|
18
|
+
customer loads into a `LoadedRelease` — the seam `@airprompter/agent-runtime`
|
|
19
|
+
renders over — after the same chain as an over-the-air update: signatures,
|
|
20
|
+
scope, expiry, every payload hash.
|
|
21
|
+
|
|
22
|
+
One of five packages released in lockstep — `@airprompter/agent-core`, `-sync`,
|
|
23
|
+
`-runtime`, `-telemetry` and the facade `@airprompter/agent-sdk` — one
|
|
24
|
+
version, exact-pinned siblings. The direction is core → clients → sdk and is
|
|
25
|
+
linted. The full README, the module map and the compatibility table are in
|
|
26
|
+
[`sdk-typescript/README.md`](https://github.com/airprompter/airprompter-agent-sdk/tree/main/sdk-typescript);
|
|
27
|
+
the protocol is in [`protocol/`](https://github.com/airprompter/airprompter-agent-sdk/tree/main/protocol).
|
|
28
|
+
BSD-3-Clause.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `.apbundle` (`protocol/schemas/bundle.schema.json`): the OTA release,
|
|
4
|
+
* serialized — manifest, every payload, the root document(s), a `notAfter`.
|
|
5
|
+
* Encrypted to the target's X25519 distribution key by default; plaintext
|
|
6
|
+
* is a `dev` opt-in. `open` runs the identical verification the sync path
|
|
7
|
+
* runs, so a bundle is never a way around the trust chain.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.BundleError = exports.APBUNDLE_INFO = void 0;
|
|
11
|
+
exports.distributionKeyId = distributionKeyId;
|
|
12
|
+
exports.createPlaintextBundle = createPlaintextBundle;
|
|
13
|
+
exports.createEncryptedBundle = createEncryptedBundle;
|
|
14
|
+
exports.openBundle = openBundle;
|
|
15
|
+
exports.bundlePayloadBytes = bundlePayloadBytes;
|
|
16
|
+
const node_crypto_1 = require("node:crypto");
|
|
17
|
+
const canonicalJson_js_1 = require("../protocol/canonicalJson.js");
|
|
18
|
+
const hpke_js_1 = require("./hpke.js");
|
|
19
|
+
exports.APBUNDLE_INFO = "airprompter-apbundle-v1";
|
|
20
|
+
/** RFC 7638 thumbprint of an OKP JWK: sha256 over canonical {crv, kty, x}, hex. */
|
|
21
|
+
function distributionKeyId(publicRaw) {
|
|
22
|
+
return (0, node_crypto_1.createHash)("sha256").update((0, canonicalJson_js_1.canonicalJson)({ crv: "X25519", kty: "OKP", x: Buffer.from(publicRaw).toString("base64url") }), "utf8").digest("hex");
|
|
23
|
+
}
|
|
24
|
+
function bundleAad(contents) {
|
|
25
|
+
return Buffer.from(`${contents.manifest.payload.agentId}|${contents.manifest.payload.target}`, "utf8");
|
|
26
|
+
}
|
|
27
|
+
function createPlaintextBundle(contents) {
|
|
28
|
+
return { format: "apbundle", version: 1, protocol: contents.manifest.payload.protocol, encryption: { scheme: "none", contents } };
|
|
29
|
+
}
|
|
30
|
+
function createEncryptedBundle(contents, recipientPublicRaw) {
|
|
31
|
+
const sealed = (0, hpke_js_1.sealTo)(recipientPublicRaw, Buffer.from(exports.APBUNDLE_INFO, "utf8"), bundleAad(contents), Buffer.from((0, canonicalJson_js_1.canonicalJson)(contents), "utf8"), hpke_js_1.AEAD_AES_256_GCM);
|
|
32
|
+
return {
|
|
33
|
+
format: "apbundle",
|
|
34
|
+
version: 1,
|
|
35
|
+
protocol: contents.manifest.payload.protocol,
|
|
36
|
+
encryption: {
|
|
37
|
+
scheme: "hpke-x25519-hkdf-sha256-aes-256-gcm",
|
|
38
|
+
recipientKeyId: distributionKeyId(recipientPublicRaw),
|
|
39
|
+
enc: sealed.enc.toString("base64url"),
|
|
40
|
+
info: exports.APBUNDLE_INFO,
|
|
41
|
+
ciphertext: sealed.ciphertext.toString("base64url"),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
class BundleError extends Error {
|
|
46
|
+
code;
|
|
47
|
+
constructor(code, message) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.code = code;
|
|
50
|
+
this.name = "BundleError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.BundleError = BundleError;
|
|
54
|
+
/**
|
|
55
|
+
* Decrypts (when sealed) and returns the contents. The AAD binds the bundle
|
|
56
|
+
* to the agent and target the caller expects, so a bundle cannot be
|
|
57
|
+
* relabelled for another target; signature and hash verification is the
|
|
58
|
+
* caller's (the same path as OTA).
|
|
59
|
+
*/
|
|
60
|
+
function openBundle(bundle, expected, distributionKey) {
|
|
61
|
+
if (bundle.format !== "apbundle" || bundle.version !== 1)
|
|
62
|
+
throw new BundleError("malformed", "not an apbundle v1");
|
|
63
|
+
if (bundle.encryption.scheme === "none") {
|
|
64
|
+
const contents = bundle.encryption.contents;
|
|
65
|
+
if (contents.manifest.payload.agentId !== expected.agentId || contents.manifest.payload.target !== expected.target) {
|
|
66
|
+
throw new BundleError("relabelled", "bundle is for another agent or target");
|
|
67
|
+
}
|
|
68
|
+
return contents;
|
|
69
|
+
}
|
|
70
|
+
if (!distributionKey)
|
|
71
|
+
throw new BundleError("wrong_recipient", "an encrypted bundle needs the target's distribution key");
|
|
72
|
+
if (bundle.encryption.recipientKeyId !== distributionKeyId(distributionKey.publicRaw))
|
|
73
|
+
throw new BundleError("wrong_recipient", "bundle was sealed to another distribution key");
|
|
74
|
+
let plaintext;
|
|
75
|
+
try {
|
|
76
|
+
plaintext = (0, hpke_js_1.openFrom)({
|
|
77
|
+
enc: Buffer.from(bundle.encryption.enc, "base64url"),
|
|
78
|
+
recipientPrivateKey: distributionKey.privateKey,
|
|
79
|
+
recipientPublicRaw: distributionKey.publicRaw,
|
|
80
|
+
info: Buffer.from(bundle.encryption.info ?? exports.APBUNDLE_INFO, "utf8"),
|
|
81
|
+
aad: Buffer.from(`${expected.agentId}|${expected.target}`, "utf8"),
|
|
82
|
+
ciphertext: Buffer.from(bundle.encryption.ciphertext, "base64url"),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// A wrong AAD and a tampered ciphertext are indistinguishable by design; both mean "not for this target as sealed".
|
|
87
|
+
throw new BundleError("decrypt_failed", "bundle does not open for this agent and target");
|
|
88
|
+
}
|
|
89
|
+
const contents = JSON.parse(plaintext.toString("utf8"));
|
|
90
|
+
if (contents.manifest.payload.agentId !== expected.agentId || contents.manifest.payload.target !== expected.target) {
|
|
91
|
+
throw new BundleError("relabelled", "bundle is for another agent or target");
|
|
92
|
+
}
|
|
93
|
+
return contents;
|
|
94
|
+
}
|
|
95
|
+
function bundlePayloadBytes(contents) {
|
|
96
|
+
return new Map(contents.payloads.map((entry) => [entry.contentHash, Buffer.from(entry.bytes, "base64url")]));
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=apbundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apbundle.js","sourceRoot":"","sources":["../../../src/bundle/apbundle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* HPKE base mode (RFC 9180) with DHKEM(X25519, HKDF-SHA256), HKDF-SHA256 and
|
|
4
|
+
* AES-GCM, on node:crypto alone. The offline bundle (`.apbundle`) is sealed
|
|
5
|
+
* to the target's X25519 distribution key with AES-256-GCM; AES-128-GCM is
|
|
6
|
+
* here only so the implementation can be checked against RFC 9180's A.1
|
|
7
|
+
* test vector, which uses that AEAD with the same KEM and KDF.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.AEAD_AES_256_GCM = exports.AEAD_AES_128_GCM = void 0;
|
|
11
|
+
exports.x25519PublicKeyFromRaw = x25519PublicKeyFromRaw;
|
|
12
|
+
exports.x25519PrivateKeyFromRaw = x25519PrivateKeyFromRaw;
|
|
13
|
+
exports.generateX25519KeyPair = generateX25519KeyPair;
|
|
14
|
+
exports.encap = encap;
|
|
15
|
+
exports.decap = decap;
|
|
16
|
+
exports.keySchedule = keySchedule;
|
|
17
|
+
exports.seal = seal;
|
|
18
|
+
exports.open = open;
|
|
19
|
+
exports.sealTo = sealTo;
|
|
20
|
+
exports.openFrom = openFrom;
|
|
21
|
+
const node_crypto_1 = require("node:crypto");
|
|
22
|
+
const KEM_X25519 = 0x0020;
|
|
23
|
+
const KDF_HKDF_SHA256 = 0x0001;
|
|
24
|
+
exports.AEAD_AES_128_GCM = 0x0001;
|
|
25
|
+
exports.AEAD_AES_256_GCM = 0x0002;
|
|
26
|
+
const NSECRET = 32;
|
|
27
|
+
const NN = 12;
|
|
28
|
+
const utf8 = (text) => Buffer.from(text, "utf8");
|
|
29
|
+
const i2osp2 = (value) => Buffer.from([(value >> 8) & 0xff, value & 0xff]);
|
|
30
|
+
const kemSuiteId = Buffer.concat([utf8("KEM"), i2osp2(KEM_X25519)]);
|
|
31
|
+
const hpkeSuiteId = (aead) => Buffer.concat([utf8("HPKE"), i2osp2(KEM_X25519), i2osp2(KDF_HKDF_SHA256), i2osp2(aead)]);
|
|
32
|
+
function hkdfExtract(salt, ikm) {
|
|
33
|
+
return (0, node_crypto_1.createHmac)("sha256", salt.length ? salt : Buffer.alloc(32)).update(ikm).digest();
|
|
34
|
+
}
|
|
35
|
+
function hkdfExpand(prk, info, length) {
|
|
36
|
+
const blocks = [];
|
|
37
|
+
let previous = Buffer.alloc(0);
|
|
38
|
+
for (let counter = 1; Buffer.concat(blocks).length < length; counter += 1) {
|
|
39
|
+
previous = (0, node_crypto_1.createHmac)("sha256", prk).update(Buffer.concat([previous, info, Buffer.from([counter])])).digest();
|
|
40
|
+
blocks.push(previous);
|
|
41
|
+
}
|
|
42
|
+
return Buffer.concat(blocks).subarray(0, length);
|
|
43
|
+
}
|
|
44
|
+
function labeledExtract(suiteId, salt, label, ikm) {
|
|
45
|
+
return hkdfExtract(salt, Buffer.concat([utf8("HPKE-v1"), suiteId, utf8(label), ikm]));
|
|
46
|
+
}
|
|
47
|
+
function labeledExpand(suiteId, prk, label, info, length) {
|
|
48
|
+
return hkdfExpand(prk, Buffer.concat([i2osp2(length), utf8("HPKE-v1"), suiteId, utf8(label), info]), length);
|
|
49
|
+
}
|
|
50
|
+
function rawPublic(key) {
|
|
51
|
+
return Buffer.from(key.export({ format: "jwk" }).x, "base64url");
|
|
52
|
+
}
|
|
53
|
+
function x25519PublicKeyFromRaw(raw) {
|
|
54
|
+
return (0, node_crypto_1.createPublicKey)({ key: { kty: "OKP", crv: "X25519", x: Buffer.from(raw).toString("base64url") }, format: "jwk" });
|
|
55
|
+
}
|
|
56
|
+
function x25519PrivateKeyFromRaw(raw, publicRaw) {
|
|
57
|
+
return (0, node_crypto_1.createPrivateKey)({ key: { kty: "OKP", crv: "X25519", x: Buffer.from(publicRaw).toString("base64url"), d: Buffer.from(raw).toString("base64url") }, format: "jwk" });
|
|
58
|
+
}
|
|
59
|
+
function generateX25519KeyPair() {
|
|
60
|
+
const pair = (0, node_crypto_1.generateKeyPairSync)("x25519");
|
|
61
|
+
return { privateKey: pair.privateKey, publicKey: pair.publicKey, publicRaw: rawPublic(pair.publicKey) };
|
|
62
|
+
}
|
|
63
|
+
function extractAndExpand(dh, kemContext) {
|
|
64
|
+
const eaePrk = labeledExtract(kemSuiteId, Buffer.alloc(0), "eae_prk", dh);
|
|
65
|
+
return labeledExpand(kemSuiteId, eaePrk, "shared_secret", kemContext, NSECRET);
|
|
66
|
+
}
|
|
67
|
+
function encap(recipientPublicRaw, ephemeral) {
|
|
68
|
+
const e = ephemeral ?? generateX25519KeyPair();
|
|
69
|
+
const dh = (0, node_crypto_1.diffieHellman)({ privateKey: e.privateKey, publicKey: x25519PublicKeyFromRaw(recipientPublicRaw) });
|
|
70
|
+
const enc = e.publicRaw;
|
|
71
|
+
return { sharedSecret: extractAndExpand(dh, Buffer.concat([enc, Buffer.from(recipientPublicRaw)])), enc };
|
|
72
|
+
}
|
|
73
|
+
function decap(enc, recipientPrivateKey, recipientPublicRaw) {
|
|
74
|
+
const dh = (0, node_crypto_1.diffieHellman)({ privateKey: recipientPrivateKey, publicKey: x25519PublicKeyFromRaw(enc) });
|
|
75
|
+
return extractAndExpand(dh, Buffer.concat([Buffer.from(enc), Buffer.from(recipientPublicRaw)]));
|
|
76
|
+
}
|
|
77
|
+
function keySchedule(sharedSecret, info, aead) {
|
|
78
|
+
const suite = hpkeSuiteId(aead);
|
|
79
|
+
const pskIdHash = labeledExtract(suite, Buffer.alloc(0), "psk_id_hash", Buffer.alloc(0));
|
|
80
|
+
const infoHash = labeledExtract(suite, Buffer.alloc(0), "info_hash", info);
|
|
81
|
+
const context = Buffer.concat([Buffer.from([0x00]), pskIdHash, infoHash]);
|
|
82
|
+
const secret = labeledExtract(suite, sharedSecret, "secret", Buffer.alloc(0));
|
|
83
|
+
const nk = aead === exports.AEAD_AES_256_GCM ? 32 : 16;
|
|
84
|
+
return { key: labeledExpand(suite, secret, "key", context, nk), baseNonce: labeledExpand(suite, secret, "base_nonce", context, NN), aead };
|
|
85
|
+
}
|
|
86
|
+
function nonceFor(context, seq) {
|
|
87
|
+
const nonce = Buffer.from(context.baseNonce);
|
|
88
|
+
// XOR the sequence number into the low-order bytes (big-endian).
|
|
89
|
+
let remaining = seq;
|
|
90
|
+
for (let index = nonce.length - 1; index >= 0 && remaining > 0; index -= 1) {
|
|
91
|
+
nonce[index] = nonce[index] ^ (remaining & 0xff);
|
|
92
|
+
remaining = Math.floor(remaining / 256);
|
|
93
|
+
}
|
|
94
|
+
return nonce;
|
|
95
|
+
}
|
|
96
|
+
/** ct ‖ tag(16), as HPKE's AEAD.Seal returns it. */
|
|
97
|
+
function seal(context, aad, plaintext, seq = 0) {
|
|
98
|
+
const algorithm = context.aead === exports.AEAD_AES_256_GCM ? "aes-256-gcm" : "aes-128-gcm";
|
|
99
|
+
const cipher = (0, node_crypto_1.createCipheriv)(algorithm, context.key, nonceFor(context, seq));
|
|
100
|
+
cipher.setAAD(aad);
|
|
101
|
+
return Buffer.concat([cipher.update(plaintext), cipher.final(), cipher.getAuthTag()]);
|
|
102
|
+
}
|
|
103
|
+
function open(context, aad, ciphertext, seq = 0) {
|
|
104
|
+
const algorithm = context.aead === exports.AEAD_AES_256_GCM ? "aes-256-gcm" : "aes-128-gcm";
|
|
105
|
+
const buffer = Buffer.from(ciphertext);
|
|
106
|
+
const decipher = (0, node_crypto_1.createDecipheriv)(algorithm, context.key, nonceFor(context, seq));
|
|
107
|
+
decipher.setAAD(aad);
|
|
108
|
+
decipher.setAuthTag(buffer.subarray(buffer.length - 16));
|
|
109
|
+
return Buffer.concat([decipher.update(buffer.subarray(0, buffer.length - 16)), decipher.final()]);
|
|
110
|
+
}
|
|
111
|
+
/** Single-shot base-mode seal: returns `enc` and the ciphertext. */
|
|
112
|
+
function sealTo(recipientPublicRaw, info, aad, plaintext, aead = exports.AEAD_AES_256_GCM) {
|
|
113
|
+
const { sharedSecret, enc } = encap(recipientPublicRaw);
|
|
114
|
+
return { enc, ciphertext: seal(keySchedule(sharedSecret, Buffer.from(info), aead), aad, plaintext) };
|
|
115
|
+
}
|
|
116
|
+
function openFrom(input) {
|
|
117
|
+
const sharedSecret = decap(input.enc, input.recipientPrivateKey, input.recipientPublicRaw);
|
|
118
|
+
return open(keySchedule(sharedSecret, Buffer.from(input.info), input.aead ?? exports.AEAD_AES_256_GCM), input.aad, input.ciphertext);
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=hpke.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hpke.js","sourceRoot":"","sources":["../../../src/bundle/hpke.ts"],"names":[],"mappings":"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"}
|