Go crypto/mlkem 怎样封装后量子密钥协商
Go crypto/mlkem 可以把后量子密钥建立封装成三个职责:接收侧生成并保管解封装私钥,发送侧使用公开封装密钥生成共享秘密及密文,接收侧用私钥解封装密文。网络上传的是公钥与封装密文,不是共享秘密。它不是业务明文加密函数,也不是带身份认证的完整握手协议。
Go 官方地址:https://go.dev/;标准库地址:https://pkg.go.dev/crypto/mlkem。
标准库提供的是 KEM 原语
Go 1.24 将 crypto/mlkem 加入标准库,实现 FIPS 203 定义的 ML-KEM;本文以 ML-KEM-768 为例,参见 Go 1.24 发布说明。示例使用该版本已有的具体类型接口,不依赖后续新增的通用封装接口。
KEM 的目标是建立共享秘密。NIST 的 FIPS 203 标准说明将它作为密钥封装机制,而非消息签名机制。若把业务字符串塞给 Encapsulate,接口本身就不匹配:该方法不接收业务明文,而是产生随机共享秘密及其封装密文。
先区分公钥、私钥与封装密文
在本文封装中,Receiver 持有 dk,PublicKey 只导出封装公钥,SealKey 的结果明确区分 ciphertext 与 secret。GenerateKey768 提供随机密钥生成,EncapsulationKey().Bytes() 提供公开编码;解封装私钥与共享秘密都要保密,详见 标准库接口文档。
| 材料 | 本文变量或入口 | 放置位置 |
|---|---|---|
| 解封装私钥 | dk | 接收侧内部 |
| 公开封装密钥 | PublicKey | 可公开,但接收方身份必须另行确认 |
| 封装密文 | ciphertext | 发给接收侧 |
| 共享秘密 | secret | 各端本地,不写日志 |

用函数封装一次密钥建立
下面是同进程教学示例,用于理解两侧职责,没有网络层、身份认证或业务数据加密。Receiver 不允许零值直接使用,应从 NewReceiver 创建;示例未在本文环境执行,末尾文案仅为代码设定的成功分支。
package main
import (
"bytes"
"crypto/mlkem"
"errors"
"fmt"
)
// Receiver 只在接收侧持有解封装私钥,不把它装进网络消息。
type Receiver struct {
dk *mlkem.DecapsulationKey768
}
func NewReceiver() (*Receiver, error) {
dk, err := mlkem.GenerateKey768()
if err != nil {
return nil, fmt.Errorf("生成密钥: %w", err)
}
return &Receiver{dk: dk}, nil
}
// PublicKey 只导出公开封装密钥;不要改成 dk.Bytes()。
func (r *Receiver) PublicKey() []byte {
return r.dk.EncapsulationKey().Bytes()
}
// SealKey 返回可传输密文与本地秘密,两者不能混成一个网络包。
func SealKey(public []byte) (ciphertext, secret []byte, err error) {
ek, err := mlkem.NewEncapsulationKey768(public)
if err != nil {
return nil, nil, fmt.Errorf("解析封装公钥: %w", err)
}
// 标准库返回顺序是秘密在前、密文在后,此处显式重排。
shared, ct := ek.Encapsulate()
return ct, shared, nil
}
func (r *Receiver) OpenKey(ciphertext []byte) ([]byte, error) {
// 输入长度检查在原语中完成;错误逐层返回,不生成替代密钥。
secret, err := r.dk.Decapsulate(ciphertext)
if err != nil {
return nil, fmt.Errorf("解封装: %w", err)
}
return secret, nil
}
func demo() error {
receiver, err := NewReceiver()
if err != nil {
return err
}
ct, senderSecret, err := SealKey(receiver.PublicKey())
if err != nil {
return err
}
receiverSecret, err := receiver.OpenKey(ct)
if err != nil {
return err
}
// 仅在同进程教学示例比较两端结果,不打印或传输秘密。
if !bytes.Equal(senderSecret, receiverSecret) {
return errors.New("示例密钥不一致")
}
return nil
}
func main() {
if err := demo(); err != nil {
fmt.Println("示例失败:", err)
return
}
fmt.Println("示例密钥一致")
}
这里特意将封装函数命名为 SealKey,而不是 EncryptMessage,避免调用方把它当成通用加密器。标准库 Encapsulate 返回 sharedKey、ciphertext,本文函数则返回 ciphertext、secret、error,因此中间使用具名局部变量,避免反向传输秘密。PublicKey 中的导出方法也不能与私钥的 Bytes 混用。
解封装无错误不等于身份可信
Decapsulate 对长度错误返回 error,但长度正确而无效的密文可能不报错,而是得到与发送侧不同的密钥。这是文档明示的行为,不能把 err == nil 当成密文完整性或发送者身份已经得到确认。公开密钥解析成功,同样只说明编码有效,不说明它属于期望的接收者。
在这份教学封装里,NewReceiver 处理生成错误,SealKey 处理公钥解析错误,OpenKey 处理解封装错误,demo 只比较本地两端结果。应用协议的认证与确认不在这几个函数内;实际系统应使用经过审查的认证协议,不应把这个示例直接当作生产握手替代品。

迁移时先固定参数与职责
迁移的第一步不是替换所有旧密码接口,而是确定两端都支持同一参数集和编码,并让公开材料与秘密材料在应用接口上分开。本文不讨论业务密钥派生、混合握手、会话恢复或消息加密,也不提供未经审查的自定义协议方案。
- 工具链应支持 crypto/mlkem,部署版本与双方协议约定一致。
- 私钥由接收侧保管,不因调试方便导出到请求体。
- 共享秘密不进入日志、示例输出或监控标签。
- 接口错误直接返回;不在出错时悄悄使用固定值或随机替代值继续。
- 示例两端相等只说明本次内部配对,不等于完成身份认证或互操作认证。
封装密文里是不是业务内容?
不是。它服务于共享秘密的恢复,本文没有传入任何业务明文。
重复封装同一公钥会得到相同结果吗?
不要把封装当作确定性转换。示例依赖标准库随机封装接口,不能通过固定输出字符串判断它是否正确。
为什么没有打印共享秘密供对照?
展示秘密不是理解流程的必要条件。教学比较放在同一进程内;跨端如何认证、确认和使用结果,必须由完整协议负责。
Go runtime.AddCleanup 怎样注册对象清理回调
- 上一篇
- Go runtime.AddCleanup 怎样注册对象清理回调
- 下一篇
- Go cmp.Or 怎样按优先级选择非零配置值
-
- Golang · Go教程 | 29分钟前 | 标准库 · go · url · Go net/url Userinfo url.UserPassword
- Go url.UserPassword 怎样构造带认证信息的 URL
- 160浏览 收藏
-
- Golang · Go教程 | 29分钟前 | Go io.ReadAll io.LimitReader 受限读取
- Go io.ReadAll 怎样配合 LimitReader 防止无界读取
- 176浏览 收藏
-
- Golang · Go教程 | 31分钟前 | 标准库 · 缓存 · HTTP · Go教程 · Go http.ServeContent Last-Modified If-Modified-Since ModTime
- Go http.ServeContent 怎样利用修改时间处理缓存
- 323浏览 收藏
-
- Golang · Go教程 | 1小时前 | 标准库 · JSON · go · Go token encoding/json/jsontext JSON token流
- Go encoding/json/jsontext 怎样读取 JSON token
- 271浏览 收藏
-
- Golang · Go教程 | 1小时前 | 内存管理 · Go教程 · Go 垃圾回收 资源释放 runtime.AddCleanup
- Go runtime.AddCleanup 怎样注册对象清理回调
- 304浏览 收藏
-
- Golang · Go教程 | 1小时前 | go · 泛型 · 内存优化 · Go Handle unique.Make 值唯一化
- Go unique.Make 怎样复用可比较值的唯一实例
- 329浏览 收藏
-
- Golang · Go教程 | 1小时前 | go · 垃圾回收 ·
- Go weak.Pointer 怎样保存可回收对象的弱引用
- 175浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 556次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 606次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 632次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 588次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 413次使用
-
- Java 性能优化上线清单:从定位、改造到灰度发布
- 2026-06-11 860浏览
-
- Spring Boot 压测验证:Gatling、JMeter 与性能回归门禁
- 2026-06-11 843浏览
-
- Java NMT 非堆内存排查:Direct Buffer、线程栈与 Metaspace 分析
- 2026-06-11 826浏览
-
- Spring Boot 容器内存优化:JVM 堆、非堆与 MaxRAMPercentage
- 2026-06-11 809浏览
-
- Tomcat 连接与线程参数调优:maxThreads、acceptCount 与 KeepAlive
- 2026-06-11 792浏览

