@veramo/did-comm
Version:
Veramo messaging plugin implementing DIDComm v2.
93 lines • 3.7 kB
JavaScript
import { parse as parseDidUrl } from 'did-resolver';
import Debug from 'debug';
import { bytesToHex, decodeJoseBlob, extractPublicKeyHex, hexToBytes, isDefined, mapIdentifierKeysToDoc, resolveDidOrThrow, } from '@veramo/utils';
import { x25519 } from '@noble/curves/ed25519';
const debug = Debug('veramo:did-comm:action-handler');
export function createEcdhWrapper(secretKeyRef, context) {
return async (theirPublicKey) => {
if (theirPublicKey.length !== 32) {
throw new Error('invalid_argument: incorrect publicKey key length for X25519');
}
const publicKey = { type: 'X25519', publicKeyHex: bytesToHex(theirPublicKey) };
const shared = await context.agent.keyManagerSharedSecret({ secretKeyRef, publicKey });
return hexToBytes(shared);
};
}
export async function extractSenderEncryptionKey(jwe, context, resolutionOptions) {
let senderKey = null;
const protectedHeader = decodeJoseBlob(jwe.protected);
if (typeof protectedHeader.skid === 'string') {
const senderDoc = await resolveDidOrThrow(protectedHeader.skid, context, resolutionOptions);
const sKey = (await context.agent.getDIDComponentById({
didDocument: senderDoc,
didUrl: protectedHeader.skid,
section: 'keyAgreement',
}));
let { publicKeyHex, keyType } = extractPublicKeyHex(sKey, true);
if (keyType !== 'X25519') {
throw new Error(`not_supported: sender key of type ${sKey.type} is not supported`);
}
senderKey = hexToBytes(publicKeyHex);
}
return senderKey;
}
export async function extractManagedRecipients(jwe, context) {
const parsedDIDs = (jwe.recipients || [])
.map((recipient) => {
const kid = recipient?.header?.kid;
const did = parseDidUrl(kid || '')?.did;
if (kid && did) {
return { recipient, kid, did };
}
else {
return null;
}
})
.filter(isDefined);
let managedRecipients = (await Promise.all(parsedDIDs.map(async ({ recipient, kid, did }) => {
try {
const identifier = await context.agent.didManagerGet({ did });
return { recipient, kid, identifier };
}
catch (e) {
// identifier not found, skip it
return null;
}
}))).filter(isDefined);
return managedRecipients;
}
export async function mapRecipientsToLocalKeys(managedKeys, context, resolutionOptions) {
const potentialKeys = await Promise.all(managedKeys.map(async ({ recipient, kid, identifier }) => {
// TODO: use caching, since all recipients are supposed to belong to the same identifier
const identifierKeys = await mapIdentifierKeysToDoc(identifier, 'keyAgreement', context, resolutionOptions);
const localKey = identifierKeys.find((key) => key.meta.verificationMethod.id === kid);
if (localKey) {
return { localKeyRef: localKey.kid, recipient };
}
else {
return null;
}
}));
const localKeys = potentialKeys.filter(isDefined);
return localKeys;
}
/**
* Generate private-public x25519 key pair
*/
export function generateX25519KeyPair() {
const secretKey = x25519.utils.randomPrivateKey();
return generateX25519KeyPairFromSeed(secretKey);
}
/**
* Generate private-public x25519 key pair from a 32 byte secret.
*/
export function generateX25519KeyPairFromSeed(seed) {
if (seed.length !== 32) {
throw new Error(`x25519: seed must be 32 bytes`);
}
return {
publicKey: x25519.getPublicKey(seed),
secretKey: seed,
};
}
//# sourceMappingURL=utils.js.map