LukaJCB/ts-mls

GitHub: LukaJCB/ts-mls

一个基于 TypeScript 的 MLS(RFC 9420)协议完整实现,支持多种密码套件和后量子算法,适用于浏览器、Node.js 和 Serverless 环境。

Stars: 91 | Forks: 16

# ts-mls:一个 TypeScript MLS (Messaging Layer Security - RFC 9420) 实现 [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/32618a3c75135814.svg)](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml) [![npm 版本](https://badge.fury.io/js/ts-mls.svg)](https://badge.fury.io/js/ts-mls) [![覆盖率状态](https://coveralls.io/repos/github/LukaJCB/ts-mls/badge.svg?branch=main)](https://coveralls.io/github/LukaJCB/ts-mls?branch=main) Messaging Layer Security (RFC 9420, MLS) 的 TypeScript 实现。 本项目旨在完整实现 [RFC 9420](https://datatracker.ietf.org/doc/html/rfc9420),并侧重于不可变性和类型安全。它适用于浏览器、Node.js 或 Serverless 环境,并支持最近标准化的 Post Quantum 公钥算法 (FIPS-203, FIPS-204) 以及结合了 X25519 和 ML-KEM 的 X-Wing 混合 KEM。 ## 安装 ``` # npm npm install ts-mls # yarn yarn add ts-mls # pnpm pnpm add ts-mls ``` 本项目目前只有一个依赖项,即 `@hpke/core`。但是,为了支持不同的 Ciphersuite,您可能需要安装其他库。例如,要使用 `MLS_128_DHKEMP256_AES128GCM_SHA256_P256` Ciphersuite,您还必须安装 `@noble/curves`: ``` # npm npm install @noble/curves # yarn yarn add @noble/curves # pnpm pnpm add @noble/curves ``` 请参阅下表,了解每个 Ciphersuite 需要安装哪些额外的依赖项。 ## 支持的 Ciphersuite 支持以下密码套件: | KEM | AEAD | KDF | Hash | Signature | Name | ID | Dependencies | | ------------------------ | ---------------- | ----------- | ------- | --------- | --------------------------------------------------- | ------ | ------------------------------------------------------- | | DHKEM-X25519-HKDF-SHA256 | AES128GCM | HKDF-SHA256 | SHA-256 | Ed25519 | MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 | 1 | | | DHKEM-P256-HKDF-SHA256 | AES128GCM | HKDF-SHA256 | SHA-256 | P256 | MLS_128_DHKEMP256_AES128GCM_SHA256_P256 | 2 | @noble/curves | | DHKEM-X25519-HKDF-SHA256 | CHACHA20POLY1305 | HKDF-SHA256 | SHA-256 | Ed25519 | MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519 | 3 | @hpke/chacha20poly1305 | | DHKEM-X448-HKDF-SHA512 | AES256GCM | HKDF-SHA512 | SHA-512 | Ed448 | MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448 | 4 | @noble/curves, @hpke/dhkem-x448 | | DHKEM-P521-HKDF-SHA512 | AES256GCM | HKDF-SHA512 | SHA-512 | P521 | MLS_256_DHKEMP521_AES256GCM_SHA512_P521 | 5 | @noble/curves | | DHKEM-X448-HKDF-SHA512 | CHACHA20POLY1305 | HKDF-SHA512 | SHA-512 | Ed448 | MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 | 6 | @hpke/chacha20poly1305, @noble/curves, @hpke/dhkem-x448 | | DHKEM-P384-HKDF-SHA384 | AES256GCM | HKDF-SHA384 | SHA-384 | P384 | MLS_256_DHKEMP384_AES256GCM_SHA384_P384 | 7 | @noble/curves | | ML-KEM-512 | AES128GCM | HKDF-SHA256 | SHA-256 | Ed25519 | MLS_128_MLKEM512_AES128GCM_SHA256_Ed25519 | 0xf007 | @hpke/ml-kem | | ML-KEM-512 | CHACHA20POLY1305 | HKDF-SHA256 | SHA-256 | Ed25519 | MLS_128_MLKEM512_CHACHA20POLY1305_SHA256_Ed25519 | 0xf008 | @hpke/ml-kem, @hpke/chacha20poly1305 | | ML-KEM-768 | AES256GCM | HKDF-SHA384 | SHA-384 | Ed25519 | MLS_256_MLKEM768_AES256GCM_SHA384_Ed25519 | 0xf009 | @hpke/ml-kem | | ML-KEM-768 | CHACHA20POLY1305 | HKDF-SHA384 | SHA-384 | Ed25519 | MLS_256_MLKEM768_CHACHA20POLY1305_SHA384_Ed25519 | 0xf00a | @hpke/ml-kem, @hpke/chacha20poly1305 | | ML-KEM-1024 | AES256GCM | HKDF-SHA512 | SHA-512 | Ed25519 | MLS_256_MLKEM1024_AES256GCM_SHA512_Ed25519 | 0xf00b | @hpke/ml-kem | | ML-KEM-1024 | CHACHA20POLY1305 | HKDF-SHA512 | SHA-512 | Ed25519 | MLS_256_MLKEM1024_CHACHA20POLY1305_SHA512_Ed25519 | 0xf00c | @hpke/ml-kem, @hpke/chacha20poly1305 | | X-Wing | AES256GCM | HKDF-SHA512 | SHA-512 | Ed25519 | MLS_256_XWING_AES256GCM_SHA512_Ed25519 | 0xf00d | @hpke/ml-kem, @noble/curves | | X-Wing | CHACHA20POLY1305 | HKDF-SHA512 | SHA-512 | Ed25519 | MLS_256_XWING_CHACHA20POLY1305_SHA512_Ed25519 | 0xf00e | @hpke/ml-kem, @hpke/chacha20poly1305, @noble/curves | | ML-KEM-1024 | AES256GCM | HKDF-SHA512 | SHA-512 | ML-DSA-87 | MLS_256_MLKEM1024_AES256GCM_SHA512_MLDSA87 | 0xf00f | @hpke/ml-kem | | ML-KEM-1024 | CHACHA20POLY1305 | HKDF-SHA512 | SHA-512 | ML-DSA-87 | MLS_256_MLKEM1024_CHACHA20POLY1305_SHA512_MLDSA87 | 0xf010 | @hpke/ml-kem, @hpke/chacha20poly1305 | | X-Wing | AES256GCM | HKDF-SHA512 | SHA-512 | ML-DSA-87 | MLS_256_XWING_AES256GCM_SHA512_MLDSA87 | 0xf011 | @hpke/ml-kem, @noble/curves | | X-Wing | CHACHA20POLY1305 | HKDF-SHA512 | SHA-512 | ML-DSA-87 | MLS_256_XWING_CHACHA20POLY1305_SHA512_MLDSA87 | 0xf012 | @hpke/ml-kem, @hpke/chacha20poly1305, @noble/curves | ## ⚠️ 安全免责声明 本库尚未经过正式的安全审计。尽管我们已经谨慎地实现正确且安全的 MLS 协议,但它可能包含未发现的漏洞。如果您计划在生产或安全关键型环境中使用本库,请谨慎行事,并考虑进行独立的安全审查。 ## 基本用法 ``` import { createApplicationMessage, createCommit, createGroup, defaultProposalTypes, defaultCredentialTypes, joinGroup, processMessage, getCiphersuiteImpl, Credential, defaultCapabilities, defaultLifetime, generateKeyPackage, MlsContext, encode, decode, mlsMessageEncoder, mlsMessageDecoder, protocolVersions, unsafeTestingAuthenticationService, wireformats, Proposal, zeroOutUint8Array, } from "ts-mls" const impl = await getCiphersuiteImpl("MLS_256_XWING_AES256GCM_SHA512_Ed25519") const context: MlsContext = { cipherSuite: impl, authService: unsafeTestingAuthenticationService, } // alice generates her key package const aliceCredential: Credential = { credentialType: defaultCredentialTypes.basic, identity: new TextEncoder().encode("alice"), } const alice = await generateKeyPackage({ credential: aliceCredential, cipherSuite: impl }) const groupId = new TextEncoder().encode("group1") // alice creates a new group let aliceGroup = await createGroup({ context, groupId, keyPackage: alice.publicPackage, privateKeyPackage: alice.privatePackage, }) // bob generates his key package const bobCredential: Credential = { credentialType: defaultCredentialTypes.basic, identity: new TextEncoder().encode("bob"), } const bob = await generateKeyPackage({ credential: bobCredential, cipherSuite: impl }) // bob sends keyPackage to alice const keyPackageMessage = encode(mlsMessageEncoder, { keyPackage: bob.publicPackage, wireformat: wireformats.mls_key_package, version: protocolVersions.mls10, }) // alice decodes bob's keyPackage const decodedKeyPackage = decode(mlsMessageDecoder, keyPackageMessage)! if (decodedKeyPackage.wireformat !== wireformats.mls_key_package) throw new Error("Expected key package") // alice creates proposal to add bob const addBobProposal: Proposal = { proposalType: defaultProposalTypes.add, add: { keyPackage: decodedKeyPackage.keyPackage, }, } // alice commits const commitResult = await createCommit({ context, state: aliceGroup, extraProposals: [addBobProposal], }) aliceGroup = commitResult.newState // alice deletes the keys used to encrypt the commit message commitResult.consumed.forEach(zeroOutUint8Array) // alice sends welcome message to bob const encodedWelcome = encode(mlsMessageEncoder, commitResult.welcome!) // bob decodes the welcome message const decodedWelcome = decode(mlsMessageDecoder, encodedWelcome)! if (decodedWelcome.wireformat !== wireformats.mls_welcome) throw new Error("Expected welcome") // bob creates his own group state let bobGroup = await joinGroup({ context, welcome: decodedWelcome.welcome, keyPackage: bob.publicPackage, privateKeys: bob.privatePackage, ratchetTree: aliceGroup.ratchetTree, }) const messageToBob = new TextEncoder().encode("Hello bob!") // alice creates a message to the group const aliceCreateMessageResult = await createApplicationMessage({ context, state: aliceGroup, message: messageToBob, }) aliceGroup = aliceCreateMessageResult.newState // alice deletes the keys used to encrypt the application message aliceCreateMessageResult.consumed.forEach(zeroOutUint8Array) // alice sends the message to bob const encodedPrivateMessageAlice = encode(mlsMessageEncoder, aliceCreateMessageResult.message) // bob decodes the message const decodedPrivateMessageAlice = decode(mlsMessageDecoder, encodedPrivateMessageAlice)! if (decodedPrivateMessageAlice.wireformat !== wireformats.mls_private_message) throw new Error("Expected private message") // bob receives the message const bobProcessMessageResult = await processMessage({ context, state: bobGroup, message: decodedPrivateMessageAlice, }) bobGroup = bobProcessMessageResult.newState if (bobProcessMessageResult.kind === "newState") throw new Error("Expected application message") // bob deletes the keys used to decrypt the application message bobProcessMessageResult.consumed.forEach(zeroOutUint8Array) console.log(bobProcessMessageResult.message) ``` ## 文档 请访问 [/docs 目录](docs#readme) 获取有关不同场景的更多文档。 ## 贡献 我们欢迎您的贡献!请阅读我们的 [CONTRIBUTING.md](CONTRIBUTING.md),以获取有关如何设置您的环境、运行检查和提交更改的指南。 # 许可证 [MIT](LICENSE)
标签:E2EE, FIPS-203, FIPS-204, GNU通用公共许可证, HPKE, MITM代理, ML-KEM, MLS, Node.js, npm包, Post-Quantum, RFC 9420, Serverless, TypeScript, X25519, X-Wing混合KEM, 加密算法, 后端开发, 安全插件, 安全通信, 密码学, 手动系统调用, 抗量子密码学, 浏览器, 消息层安全, 端到端加密, 网络安全, 网络安全, 隐私保护, 隐私保护