UNPKG

ts-mls

Version:

[![CI](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml/badge.svg)](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml) [![npm version](https://badge.fury.io/js/ts-mls.svg)](https://badge.fury.io/js/ts-mls) [![Coverage Status](https://co

114 lines 5.55 kB
import { decodeUint64, encodeUint64 } from "./codec/number.js"; import { mapDecoders } from "./codec/tlsDecoder.js"; import { contramapEncoders } from "./codec/tlsEncoder.js"; import { decodeVarLenData, encodeVarLenData } from "./codec/variableLength.js"; import { decodeCommit, encodeCommit } from "./commit.js"; import { decodeContentType, encodeContentType } from "./contentType.js"; import { decodeFramedContentAuthDataCommit, encodeFramedContentAuthData, } from "./framedContent.js"; import { byteLengthToPad } from "./paddingConfig.js"; import { decodeProposal, encodeProposal } from "./proposal.js"; import { decodeSenderData, encodeSenderData, encodeSenderDataAAD, expandSenderDataKey, expandSenderDataNonce, } from "./sender.js"; export const encodePrivateMessage = contramapEncoders([encodeVarLenData, encodeUint64, encodeContentType, encodeVarLenData, encodeVarLenData, encodeVarLenData], (msg) => [msg.groupId, msg.epoch, msg.contentType, msg.authenticatedData, msg.encryptedSenderData, msg.ciphertext]); export const decodePrivateMessage = mapDecoders([decodeVarLenData, decodeUint64, decodeContentType, decodeVarLenData, decodeVarLenData, decodeVarLenData], (groupId, epoch, contentType, authenticatedData, encryptedSenderData, ciphertext) => ({ groupId, epoch, contentType, authenticatedData, encryptedSenderData, ciphertext, })); export const encodePrivateContentAAD = contramapEncoders([encodeVarLenData, encodeUint64, encodeContentType, encodeVarLenData], (aad) => [aad.groupId, aad.epoch, aad.contentType, aad.authenticatedData]); export const decodePrivateContentAAD = mapDecoders([decodeVarLenData, decodeUint64, decodeContentType, decodeVarLenData], (groupId, epoch, contentType, authenticatedData) => ({ groupId, epoch, contentType, authenticatedData, })); export function decodePrivateMessageContent(contentType) { switch (contentType) { case "application": return decoderWithPadding(mapDecoders([decodeVarLenData, decodeVarLenData], (applicationData, signature) => ({ contentType, applicationData, auth: { contentType, signature }, }))); case "proposal": return decoderWithPadding(mapDecoders([decodeProposal, decodeVarLenData], (proposal, signature) => ({ contentType, proposal, auth: { contentType, signature }, }))); case "commit": return decoderWithPadding(mapDecoders([decodeCommit, decodeVarLenData, decodeFramedContentAuthDataCommit], (commit, signature, auth) => ({ contentType, commit, auth: { ...auth, signature, contentType }, }))); } } export function encodePrivateMessageContent(config) { return (msg) => { switch (msg.contentType) { case "application": return encoderWithPadding(contramapEncoders([encodeVarLenData, encodeFramedContentAuthData], (m) => [m.applicationData, m.auth]), config)(msg); case "proposal": return encoderWithPadding(contramapEncoders([encodeProposal, encodeFramedContentAuthData], (m) => [m.proposal, m.auth]), config)(msg); case "commit": return encoderWithPadding(contramapEncoders([encodeCommit, encodeFramedContentAuthData], (m) => [m.commit, m.auth]), config)(msg); } }; } export async function decryptSenderData(msg, senderDataSecret, cs) { const key = await expandSenderDataKey(cs, senderDataSecret, msg.ciphertext); const nonce = await expandSenderDataNonce(cs, senderDataSecret, msg.ciphertext); const aad = { groupId: msg.groupId, epoch: msg.epoch, contentType: msg.contentType, }; const decrypted = await cs.hpke.decryptAead(key, nonce, encodeSenderDataAAD(aad), msg.encryptedSenderData); return decodeSenderData(decrypted, 0)?.[0]; } export async function encryptSenderData(senderDataSecret, senderData, aad, ciphertext, cs) { const key = await expandSenderDataKey(cs, senderDataSecret, ciphertext); const nonce = await expandSenderDataNonce(cs, senderDataSecret, ciphertext); return await cs.hpke.encryptAead(key, nonce, encodeSenderDataAAD(aad), encodeSenderData(senderData)); } export function toAuthenticatedContent(content, msg, senderLeafIndex) { return { wireformat: "mls_private_message", content: { groupId: msg.groupId, epoch: msg.epoch, sender: { senderType: "member", leafIndex: senderLeafIndex, }, authenticatedData: msg.authenticatedData, ...content, }, auth: content.auth, }; } function encoderWithPadding(encoder, config) { return (t) => { const encoded = encoder(t); const result = new Uint8Array(encoded.length + byteLengthToPad(encoded.length, config)); result.set(encoded, 0); return result; }; } function decoderWithPadding(decoder) { return (bytes, offset) => { const result = decoder(bytes, offset); if (result === undefined) return undefined; const [decoded, innerOffset] = result; const paddingBytes = bytes.subarray(offset + innerOffset, bytes.length); const allZeroes = paddingBytes.every((byte) => byte === 0); if (!allZeroes) return undefined; return [decoded, bytes.length]; }; } //# sourceMappingURL=privateMessage.js.map