Skip to content

Commit

Permalink
chore tests
Browse files Browse the repository at this point in the history
  • Loading branch information
OR13 committed Mar 2, 2024
1 parent e33a203 commit 2805d2d
Show file tree
Hide file tree
Showing 14 changed files with 491 additions and 110 deletions.
2 changes: 1 addition & 1 deletion src/cose/encrypt/hpke/wrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const encryptWrap = async (req: RequestWrapEncryption) => {
const unprotectedHeader = req.unprotectedHeader;
const encodedProtectedHeader = encode(req.protectedHeader)
const cek = await aes.generateKey(alg);
const iv = await aes.getIv(alg);
const iv = toArrayBuffer(await aes.getIv(alg));
unprotectedHeader.set(5, iv); // set IV
const senderRecipients = []
for (const recipient of req.recipients.keys) {
Expand Down
4 changes: 3 additions & 1 deletion src/cose/encrypt/wrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const decrypt = async (req: RequestWrapDecryption) => {
const receiverPrivateKeyJwk = req.recipients.keys.find((k) => {
return k.kid === kid
})

if (receiverPrivateKeyJwk.alg === 'HPKE-Base-P256-SHA256-AES128GCM') {
return hpke.decrypt.wrap(req)
}
Expand All @@ -33,6 +34,7 @@ export const decrypt = async (req: RequestWrapDecryption) => {
}
const decodedRecipientProtectedHeader = await decodeFirst(recipientProtectedHeader)
const recipientAlgorithm = decodedRecipientProtectedHeader.get(Protected.Alg)

const epk = recipientUnprotectedHeader.get(Unprotected.Epk)
// ensure the epk has the algorithm that is set in the protected header
epk.set(Epk.Alg, recipientAlgorithm)
Expand Down Expand Up @@ -89,7 +91,7 @@ export const encrypt = async (req: RequestWrapEncryption) => {
const kek = await ecdh.deriveKey(protectedHeader, recipientProtectedHeader, recipientPublicKeyJwk, senderPrivateKeyJwk)

const cek = await aes.generateKey(alg);
const iv = await aes.getIv(alg);
const iv = toArrayBuffer(await aes.getIv(alg));
unprotectedHeader.set(Unprotected.Iv, iv)
let kwAlg = KeyWrap.A128KW
if (keyAgreementWithKeyWrappingAlgorithm === KeyAgreementWithKeyWrap["ECDH-ES+A128KW"]) {
Expand Down
4 changes: 4 additions & 0 deletions src/cose/key/convertJsonWebKeyToCoseKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ export const convertJsonWebKeyToCoseKey = async <T>(jwk: PublicKeyJwk | SecretKe
break
}
case 'alg': {
if (value === 'HPKE-Base-P256-SHA256-AES128GCM') {
coseKey.set(label, 35)
break
}
if (foundCommonParam) {
const foundAlgorithm = algorithms.find((param) => {
return param.Name === value
Expand Down
4 changes: 4 additions & 0 deletions src/cose/key/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { convertJsonWebKeyToCoseKey } from './convertJsonWebKeyToCoseKey'
import { thumbprint } from "./thumbprint"

import { formatJwk } from './formatJwk'
import { cbor } from "../.."


export const generate = async <T>(alg: CoseSignatureAlgorithms | CoseDirectEncryptionAlgorithms, contentType: PrivateKeyContentType = 'application/jwk+json'): Promise<T> => {
Expand Down Expand Up @@ -48,6 +49,9 @@ export const generate = async <T>(alg: CoseSignatureAlgorithms | CoseDirectEncry
const secretKeyCoseKey = await convertJsonWebKeyToCoseKey<CoseKey>(secretKeyJwk)
const coseKeyThumbprint = await thumbprint.calculateCoseKeyThumbprint(secretKeyCoseKey)
secretKeyCoseKey.set(2, coseKeyThumbprint)
if (alg === 'HPKE-Base-P256-SHA256-AES128GCM') {
return new Uint8Array(cbor.encode(secretKeyCoseKey)) as T
}
return secretKeyCoseKey as T
}
throw new Error('Unsupported content type.')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,211 @@ import * as jose from '../jose-hpke'

import * as cose from '../../src'

import fs from 'fs'
import { publicFromPrivate } from '../../src/cose/key'

let examples = ``

let privateKeyJwk: any
let publicKeyJwk: any

let privateKeyCose: any
let publicKeyCose: any

it('generate private keys', async () => {
const k1 = await jose.key.generate('HPKE-Base-P256-SHA256-AES128GCM')
const k2 = await cose.key.generate('HPKE-Base-P256-SHA256-AES128GCM', 'application/cose-key')
privateKeyJwk = await jose.key.generate('HPKE-Base-P256-SHA256-AES128GCM')
const k1 = Buffer.from(JSON.stringify(privateKeyJwk, null, 2))
publicKeyJwk = publicFromPrivate(privateKeyJwk)
const k1c = await cose.key.convertJsonWebKeyToCoseKey<Map<any, any>>(JSON.parse(k1.toString()))
k1c.set(2, await cose.key.thumbprint.calculateCoseKeyThumbprintUri(k1c))
privateKeyCose = k1c
publicKeyCose = publicFromPrivate(privateKeyCose)
const k2 = await cose.cbor.encode(k1c)
examples += `
## Private Key
### application/jwk+json
~~~
${k1.toString('hex')}
~~~
{: #private-key-jwk-hex align="left" title="JSON Web Key Bytes"}
~~~json
${k1.toString()}
~~~
{: #private-key-jwk align="left" title="JSON Web Key"}
### application/cose-key
~~~
${Buffer.from(k2).toString('hex')}
~~~
{: #private-key-cose-key align="left" title="COSE Key Bytes"}
~~~ cbor-diag
${(await cose.cbor.diagnose(k2)).trim()}
~~~
{: #private-key-cose-key align="left" title="COSE Key Diagnostic"}
`.trim() + '\n\n'
})

it('direct encryption', async () => {
const messsageText = `⌛ My lungs taste the air of Time Blown past falling sands ⌛`
const aadText = `✨ It’s a dangerous business, Frodo, going out your door. ✨`
const plaintext = new TextEncoder().encode(messsageText)
const aad = new TextEncoder().encode(aadText)

const jwe = await jose.IntegratedEncryption.encrypt(plaintext, publicKeyJwk, aad, { serialization: 'GeneralJson' })
const decryptedJwe = await jose.IntegratedEncryption.decrypt(jwe, privateKeyJwk, { serialization: 'GeneralJson' })
expect(new TextDecoder().decode(decryptedJwe.plaintext)).toBe(messsageText)
expect(new TextDecoder().decode(decryptedJwe.additionalAuthenticatedData)).toBe(aadText)

const ct = await cose.encrypt.direct({
protectedHeader: cose.ProtectedHeader([
[cose.Protected.Alg, cose.Direct['HPKE-Base-P256-SHA256-AES128GCM']],
]),
aad,
plaintext,
recipients: {
keys: [{ ...publicKeyJwk, kid: publicKeyCose.get(2) }]
}
})
const pt = await cose.decrypt.direct({
ciphertext: ct,
aad,
recipients: {
keys: [{ ...privateKeyJwk, kid: publicKeyCose.get(2) }]
}
})
expect(new TextDecoder().decode(pt)).toBe(messsageText)
examples += `
## Direct Encryption
~~~
${messsageText}
~~~
{: #direct-encryption-message align="left" title="Direct Encryption Message"}
~~~
${aadText}
~~~
{: #direct-encryption-addition-authenticated-data align="left" title="Direct Encryption AAD"}
### application/jose+json
~~~
${Buffer.from(JSON.stringify(jwe, null, 2)).toString('hex')}
~~~
{: #direct-ciphertext-jose-bytes align="left" title="Direct JOSE Bytes"}
~~~json
${JSON.stringify(jwe, null, 2)}
~~~
{: #direct-ciphertext-json align="left" title="Direct JOSE JSON"}
### application/cose
~~~
${ct.toString('hex')}
~~~
{: #direct-ciphertext-cose-bytes align="left" title="Direct COSE Bytes"}
~~~ cbor-diag
${(await cose.cbor.diagnose(ct)).trim()}
~~~
{: #direct-ciphertext-cose-diag align="left" title="Direct COSE Diagnostic"}
`.trim() + '\n\n'
})


it('key encryption', async () => {
const messsageText = `⌛ My lungs taste the air of Time Blown past falling sands ⌛`
const aadText = `✨ It’s a dangerous business, Frodo, going out your door. ✨`
const plaintext = new TextEncoder().encode(messsageText)
const aad = new TextEncoder().encode(aadText)
const jwe = await jose.KeyEncryption.encrypt({
protectedHeader: { enc: 'A128GCM' },
additionalAuthenticatedData: aad,
plaintext,
recipients: {
keys: [publicKeyJwk]
}
})
const decryptedJwe = await jose.KeyEncryption.decrypt({
jwe,
recipients: {
keys: [privateKeyJwk]
}
})
expect(new TextDecoder().decode(decryptedJwe.plaintext)).toBe(messsageText)
expect(new TextDecoder().decode(decryptedJwe.additionalAuthenticatedData)).toBe(aadText)

const ct = await cose.encrypt.wrap({
protectedHeader: cose.ProtectedHeader([
[cose.Protected.Alg, cose.Aead.A128GCM],
]),
aad,
plaintext,
recipients: {
keys: [{ ...publicKeyJwk, kid: publicKeyCose.get(2) }]
}
})

const pt = await cose.decrypt.wrap({
ciphertext: ct,
aad,
recipients: {
keys: [{ ...privateKeyJwk, kid: publicKeyCose.get(2) }]
}
})
expect(new TextDecoder().decode(pt)).toBe(messsageText)
examples += `
## Key Encryption
~~~
${messsageText}
~~~
{: #key-encryption-message align="left" title="Key Encryption Message"}
~~~
${aadText}
~~~
{: #key-encryption-addition-authenticated-data align="left" title="Key Encryption AAD"}
### application/jose+json
~~~
${Buffer.from(JSON.stringify(jwe, null, 2)).toString('hex')}
~~~
{: #wrap-ciphertext-jose-bytes align="left" title="Key Encryption JOSE Bytes"}
~~~json
${JSON.stringify(jwe, null, 2)}
~~~
{: #wrap-ciphertext-jose-json align="left" title="Key Encryption JOSE JSON"}
### application/cose
~~~
${ct.toString('hex')}
~~~
{: #wrap-ciphertext-cose-bytes align="left" title="Key Encryption COSE Bytes"}
~~~ cbor-diag
${(await cose.cbor.diagnose(ct)).trim()}
~~~
{: #wrap-ciphertext-cose-diag align="left" title="Key Encryption COSE Diagnostic"}
`.trim() + '\n\n'
})


afterAll(() => {
// fs.writeFileSync('./test/draft-jose-cose-hpke-cookbook/examples.md', examples)
})
117 changes: 117 additions & 0 deletions test/draft-jose-cose-hpke-cookbook/examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
## Private Key

### application/jwk+json

~~~
7b0a2020226b6964223a202275726e3a696574663a706172616d733a6f617574683a6a776b2d7468756d627072696e743a7368612d3235363a5a74467579756f396c47777a6b5a543072564d6345464e716e50425736546439326c50597a6a794b675659222c0a202022616c67223a202248504b452d426173652d503235362d5348413235362d41455331323847434d222c0a2020226b7479223a20224543222c0a202022637276223a2022502d323536222c0a20202278223a202255645241515142396d656e62734f4a574f52376c4e7573445379576931477a7034326e46684a4344574f6f222c0a20202279223a2022666250554b3739374d576e44517a433479746e6c342d784277785a6b7653696c5535664b5479584e734c49222c0a20202264223a202266637a5043694531353479574e5751737379587278425541787532577970566335357a3042393667593034220a7d
~~~
{: #private-key-jwk-hex align="left" title="JSON Web Key Bytes"}

~~~json
{
"kid": "urn:ietf:params:oauth:jwk-thumbprint:sha-256:ZtFuyuo9lGwzkZT0rVMcEFNqnPBW6Td92lPYzjyKgVY",
"alg": "HPKE-Base-P256-SHA256-AES128GCM",
"kty": "EC",
"crv": "P-256",
"x": "UdRAQQB9menbsOJWOR7lNusDSyWi1Gzp42nFhJCDWOo",
"y": "fbPUK797MWnDQzC4ytnl4-xBwxZkvSilU5fKTyXNsLI",
"d": "fczPCiE154yWNWQssyXrxBUAxu2WypVc55z0B96gY04"
}
~~~
{: #private-key-jwk align="left" title="JSON Web Key"}

### application/cose-key

~~~
a702784d75726e3a696574663a706172616d733a6f617574683a636b743a7368612d3235363a76567a736e55563857535069616e714f68425a665038774b303357364d77697a4a496332486664473334490318230102200121582051d44041007d99e9dbb0e256391ee536eb034b25a2d46ce9e369c584908358ea2258207db3d42bbf7b3169c34330b8cad9e5e3ec41c31664bd28a55397ca4f25cdb0b22358207dcccf0a2135e78c9635642cb325ebc41500c6ed96ca955ce79cf407dea0634e
~~~
{: #private-key-cose-key align="left" title="COSE Key Bytes"}

~~~ cbor-diag
{2: "urn:ietf:params:oauth:ckt:sha-256:vVzsnUV8WSPianqOhBZfP8wK03W6MwizJIc2HfdG34I", 3: 35, 1: 2, -1: 1, -2: h'51d44041007d99e9dbb0e256391ee536eb034b25a2d46ce9e369c584908358ea', -3: h'7db3d42bbf7b3169c34330b8cad9e5e3ec41c31664bd28a55397ca4f25cdb0b2', -4: h'7dcccf0a2135e78c9635642cb325ebc41500c6ed96ca955ce79cf407dea0634e'}
~~~
{: #private-key-cose-key align="left" title="COSE Key Diagnostic"}

## Direct Encryption

~~~
⌛ My lungs taste the air of Time Blown past falling sands ⌛
~~~
{: #direct-encryption-message align="left" title="Direct Encryption Message"}

~~~
✨ It’s a dangerous business, Frodo, going out your door. ✨
~~~
{: #direct-encryption-addition-authenticated-data align="left" title="Direct Encryption AAD"}

### application/jose+json

~~~
7b0a20202270726f746563746564223a202265794a68624763694f694a6b615849694c434a6c626d4d694f694a49554574464c554a6863325574554449314e693154534545794e545974515556544d54493452304e4e496977695a584272496a7037496d743065534936496b564c496977695a5773694f694a4354586479564652725556424d58315674526e5a6c65586c48565552785647307962324a6b4c5639775231423055336479596e526b4f4639785a315242636c5a495257647062563933566c70665532553563455a74526a6c5256486c7261486f336544677a4e6d6c42625855314e53314e5a306b69665830222c0a202022616164223a20223470796f49456c30346f435a6379426849475268626d646c636d39316379426964584e70626d567a63797767526e4a765a473873494764766157356e4947393164434235623356794947527662334975494f4b637141222c0a20202263697068657274657874223a20224a484d73652d4c694e4674566f5a675f62486865326561555149736d7562722d59446137595a686b446430615863614e3642425461592d54775830567659716c53774b5453436a727352687a6e7a784c467579527253546f70486664522d473052547050635342656541220a7d
~~~
{: #direct-ciphertext-jose-bytes align="left" title="Direct JOSE Bytes"}

~~~json
{
"protected": "eyJhbGciOiJkaXIiLCJlbmMiOiJIUEtFLUJhc2UtUDI1Ni1TSEEyNTYtQUVTMTI4R0NNIiwiZXBrIjp7Imt0eSI6IkVLIiwiZWsiOiJCTXdyVFRrUVBMX1VtRnZleXlHVURxVG0yb2JkLV9wR1B0U3dyYnRkOF9xZ1RBclZIRWdpbV93VlpfU2U5cEZtRjlRVHlraHo3eDgzNmlBbXU1NS1NZ0kifX0",
"aad": "4pyoIEl04oCZcyBhIGRhbmdlcm91cyBidXNpbmVzcywgRnJvZG8sIGdvaW5nIG91dCB5b3VyIGRvb3IuIOKcqA",
"ciphertext": "JHMse-LiNFtVoZg_bHhe2eaUQIsmubr-YDa7YZhkDd0aXcaN6BBTaY-TwX0VvYqlSwKTSCjrsRhznzxLFuyRrSTopHfdR-G0RTpPcSBeeA"
}
~~~
{: #direct-ciphertext-json align="left" title="Direct JOSE JSON"}

### application/cose

~~~
d08344a1011823a204784d75726e3a696574663a706172616d733a6f617574683a636b743a7368612d3235363a76567a736e55563857535069616e714f68425a665038774b303357364d77697a4a4963324866644733344923584104d39c578ee72f030d145fc92e2088797d39fe94aa03f581ec0d9a63cea0dd2f2500e36c3c30ce4563279334a47cc1bdf476d5d0149ef63150a806971564702dd8584fe14133dadd5c6f92c53aa71eee1c786f92c1199079d75ecde135f15ace97c91dd7b80eafa0129c09f28eb7be3b2b6e1a39d6d17e260b7dad0d7456cd2b0c44374f18173820b80abda93b52ee146f8b
~~~
{: #direct-ciphertext-cose-bytes align="left" title="Direct COSE Bytes"}

~~~ cbor-diag
16([h'a1011823', {4: "urn:ietf:params:oauth:ckt:sha-256:vVzsnUV8WSPianqOhBZfP8wK03W6MwizJIc2HfdG34I", -4: h'04d39c578ee72f030d145fc92e2088797d39fe94aa03f581ec0d9a63cea0dd2f2500e36c3c30ce4563279334a47cc1bdf476d5d0149ef63150a806971564702dd8'}, h'e14133dadd5c6f92c53aa71eee1c786f92c1199079d75ecde135f15ace97c91dd7b80eafa0129c09f28eb7be3b2b6e1a39d6d17e260b7dad0d7456cd2b0c44374f18173820b80abda93b52ee146f8b'])
~~~
{: #direct-ciphertext-cose-diag align="left" title="Direct COSE Diagnostic"}

## Key Encryption

~~~
⌛ My lungs taste the air of Time Blown past falling sands ⌛
~~~
{: #key-encryption-message align="left" title="Key Encryption Message"}

~~~
✨ It’s a dangerous business, Frodo, going out your door. ✨
~~~
{: #key-encryption-addition-authenticated-data align="left" title="Key Encryption AAD"}

### application/jose+json

~~~
7b0a20202270726f746563746564223a202265794a6c626d4d694f694a424d54493452304e4e496977695a584272496a7037496d743065534936496b564c496977695a5773694f694a43526d3947535870535a33567a646a4e714e335a6c5a7a426f55335268533049304c53316d53566b346155524f566b52305a58424e4e304574576b5270536b786c55465a35623055775556426c5830497755324978526e4a75636d7058616d524b576a5272656b6474513251744e465253587a5169665830222c0a202022656e637279707465645f6b6579223a2022393745355031505f356f714972436d4a4370637751536a4d785a733079495a55583757675a5977514b5a6b222c0a2020226976223a2022354f56524d5030684c52503348643147222c0a20202263697068657274657874223a20225041567a51644d587046476873763938494d687352724d6d3754785f6c666f42442d4d7253757538734972497254784f414e6755634830737a6c52615633525764363937514b7249616b6e727645476452687030222c0a202022746167223a20223552584b5963624e4f51756939397049755462625f77222c0a202022616164223a20223470796f49456c30346f435a6379426849475268626d646c636d39316379426964584e70626d567a63797767526e4a765a473873494764766157356e4947393164434235623356794947527662334975494f4b637141220a7d
~~~
{: #wrap-ciphertext-jose-bytes align="left" title="Key Encryption JOSE Bytes"}

~~~json
{
"protected": "eyJlbmMiOiJBMTI4R0NNIiwiZXBrIjp7Imt0eSI6IkVLIiwiZWsiOiJCRm9GSXpSZ3VzdjNqN3ZlZzBoU3RhS0I0LS1mSVk4aUROVkR0ZXBNN0EtWkRpSkxlUFZ5b0UwUVBlX0IwU2IxRnJucmpXamRKWjRrekdtQ2QtNFRSXzQifX0",
"encrypted_key": "97E5P1P_5oqIrCmJCpcwQSjMxZs0yIZUX7WgZYwQKZk",
"iv": "5OVRMP0hLRP3Hd1G",
"ciphertext": "PAVzQdMXpFGhsv98IMhsRrMm7Tx_lfoBD-MrSuu8sIrIrTxOANgUcH0szlRaV3RWd697QKrIaknrvEGdRhp0",
"tag": "5RXKYcbNOQui99pIuTbb_w",
"aad": "4pyoIEl04oCZcyBhIGRhbmdlcm91cyBidXNpbmVzcywgRnJvZG8sIGdvaW5nIG91dCB5b3VyIGRvb3IuIOKcqA"
}
~~~
{: #wrap-ciphertext-jose-json align="left" title="Key Encryption JOSE JSON"}

### application/cose

~~~
d8608443a10101a105503f2ffb31b5937ad71f9c05703444135b584fcac6d2b9d3de828ee3f53315078efe646245a68e8c6ae77dac3518d168c131daee205eacee566db92637c5340899d1ac1035f5e379939f0681e08016f1cb3745e6cf1c4a9247788348d5e6448e8079818344a1011823a204784d75726e3a696574663a706172616d733a6f617574683a636b743a7368612d3235363a76567a736e55563857535069616e714f68425a665038774b303357364d77697a4a49633248666447333449235841047f1321836185571a5d49140b6b823bc40fbbc06365c6e0c0681dd2232ef66aa01b87fbe60829452dfa8c32e867ec1d553e2ded27b5320c9fac4972f7563d51665820927e9cf95a50e2e87244bc2ef923475df2463f8237a7a49c5e8469a58a4486d2
~~~
{: #wrap-ciphertext-cose-bytes align="left" title="Key Encryption COSE Bytes"}

~~~ cbor-diag
96([h'a10101', {5: h'3f2ffb31b5937ad71f9c05703444135b'}, h'cac6d2b9d3de828ee3f53315078efe646245a68e8c6ae77dac3518d168c131daee205eacee566db92637c5340899d1ac1035f5e379939f0681e08016f1cb3745e6cf1c4a9247788348d5e6448e8079', [[h'a1011823', {4: "urn:ietf:params:oauth:ckt:sha-256:vVzsnUV8WSPianqOhBZfP8wK03W6MwizJIc2HfdG34I", -4: h'047f1321836185571a5d49140b6b823bc40fbbc06365c6e0c0681dd2232ef66aa01b87fbe60829452dfa8c32e867ec1d553e2ded27b5320c9fac4972f7563d5166'}, h'927e9cf95a50e2e87244bc2ef923475df2463f8237a7a49c5e8469a58a4486d2']]])
~~~
{: #wrap-ciphertext-cose-diag align="left" title="Key Encryption COSE Diagnostic"}

Loading

0 comments on commit 2805d2d

Please sign in to comment.