ts-mls
Version:
[](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml) [](https://badge.fury.io/js/ts-mls) [ {
const tbs = {
protocolVersion: groupContext.version,
wireformat: "mls_private_message",
content: {
contentType: "application",
applicationData,
groupId: groupContext.groupId,
epoch: groupContext.epoch,
sender: {
senderType: "member",
leafIndex: leafIndex,
},
authenticatedData,
},
senderType: "member",
context: groupContext,
};
const auth = await signFramedContentApplicationOrProposal(signKey, tbs, cs);
const content = {
...tbs.content,
auth,
};
const result = await protect(senderDataSecret, authenticatedData, groupContext, secretTree, content, leafIndex, paddingConfig, cs);
return { newSecretTree: result.tree, privateMessage: result.privateMessage };
}
export async function protectProposal(signKey, senderDataSecret, p, authenticatedData, groupContext, secretTree, leafIndex, paddingConfig, cs) {
const tbs = {
protocolVersion: groupContext.version,
wireformat: "mls_private_message",
content: {
contentType: "proposal",
proposal: p,
groupId: groupContext.groupId,
epoch: groupContext.epoch,
sender: {
senderType: "member",
leafIndex,
},
authenticatedData,
},
senderType: "member",
context: groupContext,
};
const auth = await signFramedContentApplicationOrProposal(signKey, tbs, cs);
const content = { ...tbs.content, auth };
const privateMessage = await protect(senderDataSecret, authenticatedData, groupContext, secretTree, content, leafIndex, paddingConfig, cs);
const newSecretTree = privateMessage.tree;
const authenticatedContent = {
wireformat: "mls_private_message",
content,
auth,
};
const proposalRef = await makeProposalRef(authenticatedContent, cs.hash);
return { privateMessage: privateMessage.privateMessage, newSecretTree, proposalRef };
}
export async function protect(senderDataSecret, authenticatedData, groupContext, secretTree, content, leafIndex, config, cs) {
const node = secretTree[leafToNodeIndex(toLeafIndex(leafIndex))];
if (node === undefined)
throw new InternalError("Bad node index for secret tree");
const { newTree, generation, reuseGuard, nonce, key } = await consumeRatchet(secretTree, leafToNodeIndex(toLeafIndex(leafIndex)), content.contentType, cs);
const aad = {
groupId: groupContext.groupId,
epoch: groupContext.epoch,
contentType: content.contentType,
authenticatedData: authenticatedData,
};
const ciphertext = await cs.hpke.encryptAead(key, nonce, encodePrivateContentAAD(aad), encodePrivateMessageContent(config)(content));
const senderData = {
leafIndex,
generation,
reuseGuard,
};
const senderAad = {
groupId: groupContext.groupId,
epoch: groupContext.epoch,
contentType: content.contentType,
};
const encryptedSenderData = await encryptSenderData(senderDataSecret, senderData, senderAad, ciphertext, cs);
return {
privateMessage: {
groupId: groupContext.groupId,
epoch: groupContext.epoch,
encryptedSenderData,
contentType: content.contentType,
authenticatedData,
ciphertext,
},
tree: newTree,
};
}
export async function unprotectPrivateMessage(senderDataSecret, msg, secretTree, ratchetTree, groupContext, config, cs, overrideSignatureKey) {
const senderData = await decryptSenderData(msg, senderDataSecret, cs);
if (senderData === undefined)
throw new CodecError("Could not decode senderdata");
validateSenderData(senderData, ratchetTree);
const { key, nonce, newTree } = await ratchetToGeneration(secretTree, senderData, msg.contentType, config, cs);
const aad = {
groupId: msg.groupId,
epoch: msg.epoch,
contentType: msg.contentType,
authenticatedData: msg.authenticatedData,
};
const decrypted = await cs.hpke.decryptAead(key, nonce, encodePrivateContentAAD(aad), msg.ciphertext);
const pmc = decodePrivateMessageContent(msg.contentType)(decrypted, 0)?.[0];
if (pmc === undefined)
throw new CodecError("Could not decode PrivateMessageContent");
const content = toAuthenticatedContent(pmc, msg, senderData.leafIndex);
const signaturePublicKey = overrideSignatureKey !== undefined
? overrideSignatureKey
: getSignaturePublicKeyFromLeafIndex(ratchetTree, toLeafIndex(senderData.leafIndex));
const signatureValid = await verifyFramedContentSignature(signaturePublicKey, "mls_private_message", content.content, content.auth, groupContext, cs.signature);
if (!signatureValid)
throw new CryptoVerificationError("Signature invalid");
return { tree: newTree, content };
}
export function validateSenderData(senderData, tree) {
if (tree[leafToNodeIndex(toLeafIndex(senderData.leafIndex))]?.nodeType !== "leaf")
return new ValidationError("SenderData did not point to a non-blank leaf node");
}
//# sourceMappingURL=messageProtection.js.map