Skip to content

Commit

Permalink
add context computation
Browse files Browse the repository at this point in the history
  • Loading branch information
OR13 committed Feb 23, 2024
1 parent 93a4bef commit a52bbf9
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 9 deletions.
2 changes: 1 addition & 1 deletion examples/hpke.direct.diag
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16([h'a1011823', {4: "[email protected]", -1: {1: 5, -1: h'047e28c472862e148b3a039640f3a2461855ab43b955b2232575e2c2d2e5998369c38ea1be27f483c2d2fc860345298bf3316737b8771c8aa4783b366914199ab0'}}, h'6fde098224bc4f8661fb7c268dbce2269612a092490e94cb9b0de698ed015e2594e148b5ec418a7c397866c66f26af4ddf8d5c602899fe5d494833390e47075a6b7243e0594e930947c906f365626506'])
16([h'a1011823', {4: "[email protected]", -1: {1: 5, -1: h'04ea598ce9d7ff813ef17aa8594083684ca09902778cecd53ed0135d1645e68aa91b70f8523aa970b569df7345bc6914fe031b4ab7dc5f4c87126b6465c7cbe1b7'}}, h'3fd73a830be4df98a6b56c47282a18cbbe321355d73670b559222588f9205695851060f5c4818e886002737443e691e119c6938529e9d5c6038ab2ba7a13e8d7378a44b18f62efb0618515a7126e084e'])
2 changes: 1 addition & 1 deletion examples/hpke.wrap.diag
Original file line number Diff line number Diff line change
@@ -1 +1 @@
96([h'a10101', {5: 64(h'd87da66c769df98f417188913d393f63')}, h'71b7f5825726e08580d95d5b3123af4cb3013bf9835302486fcbf306010af64cb085ce936746a97fadf0ca6e7b59347c03e9404a232603ce7911a5eb31c3070062938e90488fa7b631b4f4a0be619aaf', [[h'a1011823', {4: "[email protected]", -1: {1: 5, -1: h'0484a62d158fadb34eaf812aa7a246dfb1c2aaac313b3dc6d6388fd3729f61dd1b87a9b51a1d12dc281fa8ebfa34d219088e46a6038363717fd94aaa1aeb796ce7'}}, h'755902f15658d8ebbbf47667a5e93f88903188dda2e6f04b58f5f13c466d0070']]])
96([h'a10101', {5: 64(h'02aeece48a6acb8283626684aadafec3')}, h'3b12f74131624c529bb81d830d4e6f20d6cdf4e63483cd008c66f6335db308e00705bd45e3f0b47b9c01c3a0150fd09354a5eb18906569cb49044f913a345707bfe555e8c5bd74ba3c2687c49793c349', [[h'a1011823', {4: "[email protected]", -1: {1: 5, -1: h'047dfb4519b37232544da9652c8b30499ed9b3c6aa7a1c64c6e20615518d2c499d79d1e441af2d085dc51d411fb68bf8c4cdefbb56c052c0e01b3535e819978fa9'}}, h'e36a3c29cbe95ec0b638330c16de6d3a76d6256152e2d4a825b30f83da362829']]])
83 changes: 76 additions & 7 deletions src/cose/encrypt/hpke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,45 @@ export const secondaryAlgorithm = {
'value': 37
}


const keyLength = {
'35': 16, // ...AES128GCM
} as Record<number | string, number>;


type PartyInfo = [Buffer | null, Buffer | number | null, Buffer | null]

const compute_PartyInfo = (identity: Buffer | null, nonce: Buffer | number | null, other: Buffer | null) => {
return [
identity || null, // identity
nonce || null, // nonce
other || null // other
] as PartyInfo
}

// https://datatracker.ietf.org/doc/html/draft-ietf-cose-hpke-07#section-3.2
const compute_COSE_KDF_Context = (
AlgorithmID: number,
PartyUInfo: PartyInfo,
PartyVInfo: PartyInfo,
Protected: Buffer,
SuppPrivInfo?: Buffer
) => {
const info = [
AlgorithmID, // AlgorithmID
PartyUInfo,
PartyVInfo,
[ // SuppPubInfo
keyLength[`${AlgorithmID}`] * 8, // keyDataLength
Protected
]
]
if (SuppPrivInfo) {
(info as any).push(SuppPrivInfo)
}
return encodeAsync(info);
}

const computeHPKEAad = (protectedHeader: any, protectedRecipientHeader?: any) => {
if (protectedRecipientHeader) {
// not sure what to do when recipient protected header exists...
Expand All @@ -148,13 +187,16 @@ const encryptWrap = async (req: RequestWrapEncryption) => {
const senderRecipients = []
for (const recipient of req.recipients.keys) {
const suite = suites[recipient.alg as JOSE_HPKE_ALG]
const recipientProtectedHeader = new Map([[
1, 35
]])
const encodedRecipientProtectedHeader = encode(recipientProtectedHeader)
const info = await computeInfo(recipientProtectedHeader)
const sender = await suite.createSenderContext({
info,
recipientPublicKey: await publicKeyFromJwk(recipient),
});
const recipientProtectedHeader = encode(new Map([[
1, 35
]]))
const hpkeSealAad = computeHPKEAad(encodedProtectedHeader, recipientProtectedHeader)
const hpkeSealAad = computeHPKEAad(encodedProtectedHeader, encodedRecipientProtectedHeader)
const encryptedKey = await sender.seal(cek, hpkeSealAad)
const encapsulatedKey = Buffer.from(sender.enc);
const recipientCoseKey = new Map<any, any>([
Expand All @@ -166,7 +208,7 @@ const encryptWrap = async (req: RequestWrapEncryption) => {
[-1, recipientCoseKey], // epk
])
senderRecipients.push([
recipientProtectedHeader,
encodedRecipientProtectedHeader,
recipientUnprotectedHeader,
encryptedKey
])
Expand All @@ -188,15 +230,38 @@ const encryptWrap = async (req: RequestWrapEncryption) => {
return encodeAsync(new Tagged(COSE_Encrypt_Tag, COSE_Encrypt), { canonical: true })
}

const computeInfo = async (protectedHeader: Map<any, any>) => {
let info = undefined;
const algorithmId = protectedHeader.get(1)
const partyUIdentity = protectedHeader.get(-21) || null
const partyUNonce = protectedHeader.get(-22) || null
const partyUOther = protectedHeader.get(-23) || null
const partyVIdentity = protectedHeader.get(-24) || null
const partyVNonce = protectedHeader.get(-25) || null
const partyVOther = protectedHeader.get(-26) || null
if (partyUNonce || partyVNonce) {
info = await compute_COSE_KDF_Context(
algorithmId,
compute_PartyInfo(partyUIdentity, partyUNonce, partyUOther),
compute_PartyInfo(partyVIdentity, partyVNonce, partyVOther),
await encodeAsync(protectedHeader),
)
}
return info
}

export const encryptDirect = async (req: RequestDirectEncryption) => {
if (req.protectedHeader.get(1) !== 35) {
const alg = req.protectedHeader.get(1)
if (alg !== 35) {
throw new Error('Only alg 35 is supported')
}
const protectedHeader = await encodeAsync(req.protectedHeader)
const unprotectedHeader = req.unprotectedHeader;
const [recipientPublicKeyJwk] = req.recipients.keys
const suite = suites[recipientPublicKeyJwk.alg as JOSE_HPKE_ALG]
const info = await computeInfo(req.protectedHeader)
const sender = await suite.createSenderContext({
info,
recipientPublicKey: await publicKeyFromJwk(recipientPublicKeyJwk),
});
const hpkeSealAad = computeHPKEAad(protectedHeader)
Expand Down Expand Up @@ -239,7 +304,9 @@ export const decryptWrap = async (req: RequestWrapDecryption) => {
// ensure the epk has the algorithm that is set in the protected header
epk.set(3, recipientAlgorithm) // EPK is allowed to have an alg
const suite = suites[receiverPrivateKeyJwk.alg as JOSE_HPKE_ALG]
const info = await computeInfo(decodedRecipientProtectedHeader)
const hpkeRecipient = await suite.createRecipientContext({
info,
recipientKey: await privateKeyFromJwk(receiverPrivateKeyJwk),
enc: epk.get(-1) // ek
})
Expand All @@ -262,13 +329,15 @@ export const decryptDirect = async (req: RequestDirectDecryption) => {
const receiverPrivateKeyJwk = req.recipients.keys.find((k) => {
return k.kid === kid
})

const decodedProtectedHeader = await decodeFirst(protectedHeader)
const recipientAlgorithm = unprotectedHeader.get(1)
const epk = unprotectedHeader.get(-1)
// ensure the epk has the algorithm that is set in the protected header
epk.set(3, recipientAlgorithm) // EPK is allowed to have an alg
const suite = suites[receiverPrivateKeyJwk.alg as JOSE_HPKE_ALG]
const info = await computeInfo(decodedProtectedHeader)
const hpkeRecipient = await suite.createRecipientContext({
info,
recipientKey: await privateKeyFromJwk(receiverPrivateKeyJwk),
enc: epk.get(-1) // ek
})
Expand Down

0 comments on commit a52bbf9

Please sign in to comment.