Skip to content

Commit

Permalink
Merge pull request #8 from chris-wood/caw/encode-configs
Browse files Browse the repository at this point in the history
Add APIs for encoding and decoding key configs for wire transmission
  • Loading branch information
dajiaji authored Mar 7, 2023
2 parents 378e1a8 + f07b69a commit 5eff12c
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 7 deletions.
107 changes: 107 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dnt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ await emptyDir("./npm");
await build({
entryPoints: ["./mod.ts"],
outDir: "./npm",
typeCheck: true,
typeCheck: false,
test: true,
declaration: true,
scriptModule: "umd",
Expand Down
4 changes: 2 additions & 2 deletions import-map.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"imports": {
"testing/": "https://deno.land/std@0.163.0/testing/",
"dnt": "https://deno.land/x/dnt@0.31.0/mod.ts",
"hpke": "https://deno.land/x/hpke@v0.15.0/mod.ts",
"dnt": "https://deno.land/x/dnt@0.33.1/mod.ts",
"hpke": "https://deno.land/x/hpke@v0.18.2/mod.ts",
"bhttp": "https://deno.land/x/bhttp@v0.2.1/mod.ts"
}
}
67 changes: 67 additions & 0 deletions src/ohttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ function checkHpkeCiphersuite(kem: Kem, kdf: Kdf, aead: Aead) {
}
}

function encodeSymmetricAlgorithms(kdf: Kdf, aead: Aead): Uint8Array {
return new Uint8Array([
0x00,
0x04, // Length
(kdf >> 8) & 0xFF,
kdf & 0xFF,
(aead >> 8) & 0xFF,
aead & 0xFF,
]);
}

export class KeyConfig {
public keyId: number;
public kem: Kem;
Expand Down Expand Up @@ -75,6 +86,7 @@ export class PublicKeyConfig {
public kem: Kem;
public kdf: Kdf;
public aead: Aead;
public suite: CipherSuite;
public publicKey: CryptoKey; // XXX(caw): should this be public?

constructor(
Expand All @@ -93,6 +105,12 @@ export class PublicKeyConfig {
this.kem = kem;
this.kdf = kdf;
this.aead = aead;
this.suite = new CipherSuite({
kem: this.kem,
kdf: this.kdf,
aead: this.aead,
});

this.publicKey = publicKey;
}
}
Expand Down Expand Up @@ -246,6 +264,55 @@ export class Server {
const encapRequestBody = new Uint8Array(await request.arrayBuffer());
return this.decodeAndDecapsulate(encapRequestBody);
}

async encodeKeyConfig(): Promise<Uint8Array> {
const preamble = new Uint8Array([
this.config.keyId & 0xFF,
(this.config.kem >> 8) & 0xFF,
this.config.kem & 0xFF,
]);
const publicConfig = await this.config.publicConfig();
const kemContext = await this.suite.kemContext();
const encodedKey = new Uint8Array(
await kemContext.serializePublicKey(
publicConfig.publicKey,
),
);
const algorithms = encodeSymmetricAlgorithms(
this.config.kdf,
this.config.aead,
);
return concatArrays(concatArrays(preamble, encodedKey), algorithms);
}
}

export class ClientConstructor {
async clientForConfig(config: Uint8Array): Promise<Client> {
const keyId = config[0];
const kemId = (config[1] << 8) | config[2];
const suite = new CipherSuite({
kem: kemId,
kdf: Kdf.HkdfSha256, // Garbage (to create the suite)
aead: Aead.Aes128Gcm, // Garbage (to create the suite)
});
const kemContext = await suite.kemContext();
const publicKey = await kemContext.deserializePublicKey(
config.slice(3, 3 + suite.kemPublicKeySize),
);
const offset = 3 + suite.kemPublicKeySize + 2; // skip over the length, since we pick the first one pair of symmetric algorithms
const kdfId = (config[offset] << 8) | config[offset + 1];
const aeadId = (config[offset + 2] << 8) | config[offset + 3];

const publicKeyConfig = new PublicKeyConfig(
keyId,
kemId,
kdfId,
aeadId,
publicKey,
);

return new Client(publicKeyConfig);
}
}

export class Client {
Expand Down
10 changes: 6 additions & 4 deletions test/ohttp.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assertEquals, assertStrictEquals } from "testing/asserts.ts";
import { describe, it } from "testing/bdd.ts";

import { Client, KeyConfig, Server } from "../src/ohttp.ts";
import { Client, ClientConstructor, KeyConfig, Server } from "../src/ohttp.ts";

describe("test OHTTP end-to-end", () => {
it("Happy Path", async () => {
Expand All @@ -28,17 +28,19 @@ describe("test OHTTP end-to-end", () => {
it("Happy Path with encoding and decoding", async () => {
const keyId = 0x01;
const keyConfig = new KeyConfig(keyId);
const publicKeyConfig = await keyConfig.publicConfig();
const server = new Server(keyConfig);

const encodedKeyConfig = await server.encodeKeyConfig();

const encodedRequest = new TextEncoder().encode("Happy");
const encodedResponse = new TextEncoder().encode("Path");

const client = new Client(publicKeyConfig);
const constructor = new ClientConstructor();
const client = await constructor.clientForConfig(encodedKeyConfig);
const requestContext = await client.encapsulate(encodedRequest);
const clientRequest = requestContext.request;
const encodedClientRequest = clientRequest.encode();

const server = new Server(keyConfig);
const responseContext = await server.decodeAndDecapsulate(
encodedClientRequest,
);
Expand Down

0 comments on commit 5eff12c

Please sign in to comment.