did-jwt
Version:
Library for Signing and Verifying JWTs that use DIDs as issuers and JWEs that use DIDs as recipients
78 lines (68 loc) • 2.85 kB
text/typescript
import type { ECDH, EphemeralKeyPair, Recipient } from './types.js'
import { base64ToBytes, bytesToBase64url, generateKeyPair, generateKeyPairFromSeed } from '../util.js'
import { concatKDF } from '../Digest.js'
import { x25519 } from '@noble/curves/ed25519'
export async function computeX25519Ecdh1PUv3Kek(
recipient: Recipient,
recipientSecret: Uint8Array | ECDH,
senderPublicKey: Uint8Array,
alg: string
) {
const crv = 'X25519'
const keyLen = 256
const header = recipient.header
if (header.epk?.crv !== crv || typeof header.epk.x == 'undefined') return null
// ECDH-1PU requires additional shared secret between
// static key of sender and static key of recipient
const publicKey = base64ToBytes(header.epk.x)
let zE: Uint8Array
let zS: Uint8Array
if (recipientSecret instanceof Uint8Array) {
zE = x25519.getSharedSecret(recipientSecret, publicKey)
zS = x25519.getSharedSecret(recipientSecret, senderPublicKey)
} else {
zE = await recipientSecret(publicKey)
zS = await recipientSecret(senderPublicKey)
}
const sharedSecret = new Uint8Array(zE.length + zS.length)
sharedSecret.set(zE)
sharedSecret.set(zS, zE.length)
// Key Encryption Key
let producerInfo
let consumerInfo
if (recipient.header.apu) producerInfo = base64ToBytes(recipient.header.apu)
if (recipient.header.apv) consumerInfo = base64ToBytes(recipient.header.apv)
return concatKDF(sharedSecret, keyLen, alg, producerInfo, consumerInfo)
}
export async function createX25519Ecdh1PUv3Kek(
recipientPublicKey: Uint8Array,
senderSecret: Uint8Array | ECDH,
alg: string, // must be provided as this is the key agreement alg + the key wrapper alg, Example: 'ECDH-ES+A256KW'
apu: string | undefined,
apv: string | undefined,
ephemeralKeyPair: EphemeralKeyPair | undefined
) {
const crv = 'X25519'
const keyLen = 256
const ephemeral = ephemeralKeyPair ? generateKeyPairFromSeed(ephemeralKeyPair.secretKey) : generateKeyPair()
const epk = { kty: 'OKP', crv, x: bytesToBase64url(ephemeral.publicKey) }
const zE = x25519.getSharedSecret(ephemeral.secretKey, recipientPublicKey)
// ECDH-1PU requires additional shared secret between
// static key of sender and static key of recipient
let zS
if (senderSecret instanceof Uint8Array) {
zS = x25519.getSharedSecret(senderSecret, recipientPublicKey)
} else {
zS = await senderSecret(recipientPublicKey)
}
const sharedSecret = new Uint8Array(zE.length + zS.length)
sharedSecret.set(zE)
sharedSecret.set(zS, zE.length)
let partyUInfo: Uint8Array = new Uint8Array(0)
let partyVInfo: Uint8Array = new Uint8Array(0)
if (apu) partyUInfo = base64ToBytes(apu)
if (apv) partyVInfo = base64ToBytes(apv)
// Key Encryption Key
const kek = concatKDF(sharedSecret, keyLen, alg, partyUInfo, partyVInfo)
return { epk, kek }
}