UNPKG

1.91 kBPlain TextView Raw
1import type { ECDH, EphemeralKeyPair, Recipient } from './types.js'
2import { base64ToBytes, bytesToBase64url, generateKeyPair, generateKeyPairFromSeed } from '../util.js'
3import { concatKDF } from '../Digest.js'
4import { x25519 } from '@noble/curves/ed25519'
5
6export async function computeX25519EcdhEsKek(recipient: Recipient, receiverSecret: Uint8Array | ECDH, alg: string) {
7 const crv = 'X25519'
8 const keyLen = 256
9 const header = recipient.header
10 if (header.epk?.crv !== crv || typeof header.epk.x == 'undefined') return null
11 const publicKey = base64ToBytes(header.epk.x)
12 let sharedSecret
13 if (receiverSecret instanceof Uint8Array) {
14 sharedSecret = x25519.getSharedSecret(receiverSecret, publicKey)
15 } else {
16 sharedSecret = await receiverSecret(publicKey)
17 }
18
19 // Key Encryption Key
20 let producerInfo: Uint8Array | undefined = undefined
21 let consumerInfo: Uint8Array | undefined = undefined
22 if (recipient.header.apu) producerInfo = base64ToBytes(recipient.header.apu)
23 if (recipient.header.apv) consumerInfo = base64ToBytes(recipient.header.apv)
24 return concatKDF(sharedSecret, keyLen, alg, producerInfo, consumerInfo)
25}
26
27export async function createX25519EcdhEsKek(
28 recipientPublicKey: Uint8Array,
29 senderSecret: Uint8Array | ECDH | undefined, // unused
30 alg: string,
31 apu: string | undefined, // unused
32 apv: string | undefined,
33 ephemeralKeyPair: EphemeralKeyPair | undefined
34) {
35 const crv = 'X25519'
36 const keyLen = 256
37 const ephemeral = ephemeralKeyPair ? generateKeyPairFromSeed(ephemeralKeyPair.secretKey) : generateKeyPair()
38 const epk = { kty: 'OKP', crv, x: bytesToBase64url(ephemeral.publicKey) }
39 const sharedSecret = x25519.getSharedSecret(ephemeral.secretKey, recipientPublicKey)
40 // Key Encryption Key
41 const consumerInfo = base64ToBytes(apv ?? '')
42 const kek = concatKDF(sharedSecret, keyLen, alg, undefined, consumerInfo)
43 return { epk, kek }
44}