Skip to content

Commit

Permalink
Merge pull request #468 from dajiaji/hybridkem-x-wing-refine-import-k…
Browse files Browse the repository at this point in the history
…ey-support

hybridkem-x-wing: refine import key support.
  • Loading branch information
dajiaji authored Nov 7, 2024
2 parents aba1430 + 58e5abe commit e55aada
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 72 deletions.
30 changes: 19 additions & 11 deletions packages/hybridkem-x-wing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,52 @@ Documentation: [jsr.io](https://jsr.io/@hpke/hybridkem-x-wing/doc) |

</div>

An example of use:

```ts
import { Aes256Gcm, CipherSuite, HkdfSha256 } from "@hpke/core";
import { XWing } from "@hpke/hybridkem-x-wing";

async function doHpke() {
const suite = new CipherSuite({
kem: new XWing(),
kdf: new HkdfSha256(),
aead: new Aes256Gcm(),
});

// NOTE: The following support for JWKs with the AKP key type is experimental. Please be aware that the specifications are subject to change without notice.
const jwkPkR = {
// NOTE: The following support for JWKs with the AKP key type is experimental.
// Please be aware that the specifications are subject to change without notice.
const jwkPub = {
kty: "AKP",
kid: "01",
alg: "X-Wing",
pub:
"4iNrNajCSzmxCqEyOpapGaLO2IQAYzp7BxMXE_wUsrWxnPw9pfoaksSfJVE-D9MNaxYRyauWNdcIZyekt9IdNCROZpac8Vs7KnhTKfYbCWsnfqA3ODR5prVW3nIx_kt_qcmsJMBpmgAYpSU0AbrPqQXKgWVz5WotLgZ-m3KHUzuhOpN97bMfpEus7UB2mSNhADSuMeYZoXAkUZmzxcOYZIWf4bTJcXoHwwSVvfuYoKACzPVsEobO9QQd7ePETPFr9WLHRIUYAms9i5lAaAq9OKFXX9J7WNoGO_rDLDnDCGk3TAXBrrGJi2swPMaL5FU0buCvaZY2IkoUjKKuoQRjERxwn2m2nHDOhTh0ZpjExgqa7wAwx5JM7sQqXTaBb1RerhMpNGCzrLN-oOE9cOSqeGhto5ioOXwI6vloghE_5Pe61NpAsFAeHHU-_nMFPIcBToZhwzCZr-i-3kFKWxqifYOSs-Ex6acMEFWHgkDK0PQNX-PN-FI26tl-KpdEg2OygIyq_VFs0lBSxcNiVDwlF-Ss0OYOwHFjAJtkJfwyJ3rO5xwkurU-2fKedMZqCjVklVmY12uWqai1DRY1pNemfrQt9WRNMwRXKTqAQvU8x6aSiPF-1Vgn6Cso6CZlqGoU-9lmReyoFywET4O8DYwLTIYmmFYxyoevgpBo8TWJY8szNmTKSCdjujs7sghXf5umrGLCX3ZZJ0O2S-UZMXcUy0ECy3svmiWytPBhXeMd7NnKVQJtbaC2URGxb-Uv7tikh-FERiptupNyj1ALb_xJ5RVWnvJf7Rev9SBQc2glNSWGD1i-O-YclkYEpqyBTmk1WWQCpSCkZws9KEMYhmWT0VpLsBw14-WH7gxn0ogNbyQH-3pwcSuDjeuWxde_K0S89gOMy-M_vPUaVKWE_pAIPJHHptQ9T7FfSMYML9ZuCoqtStZOXEK7iHfA6-wrXjh8ipiP3CO-ueFsh1d4HgoUmcYeE4wh8hbCnQdpeYccqmlCuvwJBUS-6ZtUsWy5qaNk1iRtn0LM5TxmtZxFyPmukpmnXRUYDDyVIVGpG3oQdyQp3Ey65vzGIvqAGMY0OfiQYwuZKNtrt_lDiuQGXtNNc9SG8_UvkPCAfciN_djHKOlU8aw1wGwADOQaBYJYDju1e2cpcokKxeeYjnhQZXEW8bV9CAmq7ewL7eGuFIFIMRxvfjFzRuUYn7jNY1uYb4wL3SdkHFhLd4s6kRqAvhyWkquOG7sSg5VzzOGd8YO0WDW7tVBS-fxmoWeO8qNt6nhBHmyNYFAbTmBZLRNpipQ7UJGF25EuLqEL4GFxI2syfHFxYJTJZKaLAzd_UToFvNmcHzRlg7sFKXehChKt_HWANOVhfaTBJ2WF5XdOHzuZeLCdDpxE07yGFRxDqtGFcScXNAIjrDgdIRUKBClOl7sTu9ohtaGCttqWnhmn_QcnN_qOiApTwkKOPQSbfSGXQFKW3bNhkSp7z0gnztYR0Men2hBN3kMiCVM59kph1bsQj_C_TXgMrlCfsiwlaRQZP_c0kEJYEjfVIoKIJO4739B_sD8flC0uoXn-ci8GzAPeW2mFntsG7_OJsn3OWYRFcCFiI1k9S6MtmrrIzQSQQO9lNA",
key_ops: [],
};
const pkR = await suite.kem.importKey("jwk", jwkPkR, true);
const sender = await suite.createSenderContext({
recipientPublicKey: pkR,
});
const pk = await suite.kem.importKey("jwk", jwkPub, true);
// In addition to importing keys from external sources, you can also generate keys as follows:
// const rkp = await suite.kem.generateKeyPair();
// const rkp = await suite.kem.deriveKeyPair(random32bytesValue);

const jwkSkR = {
const sender = await suite.createSenderContext({ recipientPublicKey: pk });

const jwkPriv = {
kty: "AKP",
kid: "01",
alg: "X-Wing",
priv: "f5wrpOiPgn1hYEVQdgWFPtc7gJP277yI6xpurPpm7yY",
key_ops: ["deriveBits"],
};
const skR = await suite.kem.importKey("jwk", jwkSkR, false);
const sk = await suite.kem.importKey("jwk", jwkPriv, false);
const recipient = await suite.createRecipientContext({
recipientKey: skR,
recipientKey: sk,
enc: sender.enc,
});
const ct = await sender.seal(
const encrypted = await sender.seal(
new TextEncoder().encode("Hellow world!"),
);
const pt = await recipient.open(ct);
const pt = await recipient.open(encrypted);

// Hello world!
console.log(new TextDecoder().decode(pt));
Expand Down
72 changes: 28 additions & 44 deletions packages/hybridkem-x-wing/src/xWing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,33 @@ export class XWing implements KemInterface {
): Promise<CryptoKey> {
await this._setup();
try {
if (format === "raw") {
return await this._importRawKey(key as ArrayBuffer, isPublic);
let ret: Uint8Array;
if (format === "jwk") {
if (key instanceof ArrayBuffer || key instanceof Uint8Array) {
throw new Error("Invalid jwk key format");
}
ret = await this._importJWK(key as JsonWebKey, isPublic);
} else {
if (key instanceof ArrayBuffer) {
ret = new Uint8Array(key);
} else if (key instanceof Uint8Array) {
ret = key;
} else {
throw new Error("Invalid key format");
}
}
if (isPublic && ret.byteLength !== this.publicKeySize) {
throw new Error("Invalid length of the key");
}
if (key instanceof ArrayBuffer) {
throw new Error("Invalid jwk key format");
if (!isPublic && ret.byteLength !== this.privateKeySize) {
throw new Error("Invalid length of the key");
}
return await this._importJWK(key as JsonWebKey, isPublic);
return new XCryptoKey(
ALG_NAME,
ret,
isPublic ? "public" : "private",
isPublic ? [] : KEM_USAGES,
);
} catch (e: unknown) {
throw new DeserializeError(e);
}
Expand Down Expand Up @@ -406,32 +426,10 @@ export class XWing implements KemInterface {
});
}

private _importRawKey(
key: ArrayBuffer,
isPublic: boolean,
): Promise<CryptoKey> {
return new Promise((resolve, reject) => {
if (isPublic && key.byteLength !== this.publicKeySize) {
reject(new Error("Invalid length of the key"));
}
if (!isPublic && key.byteLength !== this.privateKeySize) {
reject(new Error("Invalid length of the key"));
}
resolve(
new XCryptoKey(
ALG_NAME,
new Uint8Array(key),
isPublic ? "public" : "private",
isPublic ? [] : KEM_USAGES,
),
);
});
}

private _importJWK(
key: JsonWebKeyExtended,
isPublic: boolean,
): Promise<CryptoKey> {
): Promise<Uint8Array> {
return new Promise((resolve, reject) => {
if (typeof key.kty === "undefined" || key.kty !== "AKP") {
reject(new Error(`Invalid kty: ${key.kty}`));
Expand All @@ -449,15 +447,7 @@ export class XWing implements KemInterface {
) {
reject(new Error("Invalid key: `key_ops` should be ['deriveBits']"));
}
resolve(
new XCryptoKey(
ALG_NAME,
base64UrlToBytes(key.priv as string),
"private",
KEM_USAGES,
),
);
return;
resolve(base64UrlToBytes(key.priv as string));
}
if (typeof key.priv !== "undefined") {
reject(new Error("Invalid key: `priv` should not be set"));
Expand All @@ -468,13 +458,7 @@ export class XWing implements KemInterface {
if (typeof key.key_ops !== "undefined" && key.key_ops.length > 0) {
reject(new Error("Invalid key: `key_ops` should not be set"));
}
resolve(
new XCryptoKey(
ALG_NAME,
base64UrlToBytes(key.pub as string),
"public",
),
);
resolve(base64UrlToBytes(key.pub as string));
});
}
}
Loading

0 comments on commit e55aada

Please sign in to comment.