mirror of
https://github.com/danbulant/jose
synced 2026-05-24 20:41:46 +00:00
83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
import type {
|
|
EcdhAllowedFunction,
|
|
EcdhESDeriveKeyFunction,
|
|
EphemeralKeyToPublicJwkFunction,
|
|
GenerateEpkFunction,
|
|
PublicJwkToEphemeralKeyFunction,
|
|
} from '../interfaces.d'
|
|
import {
|
|
encoder,
|
|
concat,
|
|
uint32be,
|
|
lengthAndInput,
|
|
concatKdf as KDF,
|
|
} from '../../lib/buffer_utils.js'
|
|
import type { EpkJwk } from '../../types.i.d'
|
|
import crypto, { ensureSecureContext } from './webcrypto.js'
|
|
import digest from './digest.js'
|
|
|
|
const concatKdf = KDF.bind(undefined, digest.bind(undefined, 'sha256'))
|
|
|
|
export const deriveKey: EcdhESDeriveKeyFunction = async (
|
|
publicKey: CryptoKey,
|
|
privateKey: CryptoKey,
|
|
algorithm: string,
|
|
keyLength: number,
|
|
apu: Uint8Array = new Uint8Array(),
|
|
apv: Uint8Array = new Uint8Array(),
|
|
) => {
|
|
ensureSecureContext()
|
|
const value = concat(
|
|
lengthAndInput(encoder.encode(algorithm)),
|
|
lengthAndInput(apu),
|
|
lengthAndInput(apv),
|
|
uint32be(keyLength),
|
|
)
|
|
|
|
if (!privateKey.usages.includes('deriveBits')) {
|
|
throw new TypeError('ECDH-ES private key "usages" must include "deriveBits"')
|
|
}
|
|
|
|
const sharedSecret = new Uint8Array(
|
|
await crypto.subtle.deriveBits(
|
|
{
|
|
name: 'ECDH',
|
|
public: publicKey,
|
|
},
|
|
privateKey,
|
|
Math.ceil(parseInt((<EcKeyAlgorithm>privateKey.algorithm).namedCurve.substr(-3), 10) / 8) <<
|
|
3,
|
|
),
|
|
)
|
|
|
|
return concatKdf(sharedSecret, keyLength, value)
|
|
}
|
|
|
|
export const ephemeralKeyToPublicJWK: EphemeralKeyToPublicJwkFunction = async function ephemeralKeyToPublicJWK(
|
|
key: CryptoKey,
|
|
) {
|
|
ensureSecureContext()
|
|
// eslint-disable-next-line @typescript-eslint/keyword-spacing
|
|
const { crv, kty, x, y } = <EpkJwk>await crypto.subtle.exportKey('jwk', key)
|
|
return { crv, kty, x, y }
|
|
}
|
|
|
|
export const generateEpk: GenerateEpkFunction = async (key: CryptoKey) => {
|
|
ensureSecureContext()
|
|
return (
|
|
await crypto.subtle.generateKey(
|
|
{ name: 'ECDH', namedCurve: (<EcKeyAlgorithm>key.algorithm).namedCurve },
|
|
true,
|
|
['deriveBits'],
|
|
)
|
|
).privateKey
|
|
}
|
|
|
|
export const publicJwkToEphemeralKey: PublicJwkToEphemeralKeyFunction = async (jwk: EpkJwk) => {
|
|
ensureSecureContext()
|
|
return crypto.subtle.importKey('jwk', jwk, { name: 'ECDH', namedCurve: jwk.crv }, true, [])
|
|
}
|
|
|
|
const curves = ['P-256', 'P-384', 'P-521']
|
|
export const ecdhAllowed: EcdhAllowedFunction = (key: CryptoKey) =>
|
|
curves.includes((<EcKeyAlgorithm>key.algorithm).namedCurve)
|