当前位置: 首页 > news >正文

关于 Kyber:抗量子密码算法 Kyber 详解

一、基本概念

后量子密码学(PQC)
│
├──> 是一个领域(研究如何在“量子时代”保护数据安全)
│
└──> Kyber 是这个领域中设计出来的一个“抗量子密码算法”└──> Kyber 是用于加密密钥交换的算法(叫 KEM)

>后量子密码学(Post-Quantum Cryptography, PQC)

这是一个“研究领域/学科”,目标是:设计在“未来量子计算机”也无法破解的密码算法。

因为像 RSA、ECC(椭圆曲线加密)这类传统算法,如果未来有量子计算机,会被很快破解(因为 Shor 算法可以高效分解大数)。

所以现在提前研究“后量子密码学”,防止将来量子计算一来,所有通信瞬间不安全。

>抗量子密码算法(Post-Quantum Algorithms)

是后量子密码学这个领域研究出来的“成果”之一,也叫:

  • 抗量子密码算法

  • 后量子密码算法

  • 有时简称“PQC算法”

它是具体的算法,用来实现:

  • 密钥交换

  • 数字签名

  • 加密传输

而这些算法的设计目标就是:在量子计算机出现后依然安全。

常见的有:

算法类型算法名称
密钥交换 / 加密Kyber, NTRU, FrodoKEM
签名算法Dilithium, Falcon, SPHINCS+

>Kyber 是什么?

Kyber 属于后量子密码算法,一种基于格(lattice)密码学的密钥封装机制(KEM),由 NIST 选为后量子密码标准,用于安全密钥交换

你可以把它当成是“后量子密码学”这个领域里的一种技术实现,目标是:

  • 在量子时代 安全地协商出对称密钥(例如 HTTPS 用的 AES 密钥)

Kyber 有以下几个等级:

名称安全级别(对抗强度)
Kyber512轻量级安全(类比 AES-128)
Kyber768中等安全
Kyber1024高强度安全(类比 AES-256)
  • 不是加密消息,而是用于共享对称密钥(适合 TLS、VPN、SSH 等应用)

  • 安全性基于数学难题:学习带噪声问题(LWE) 的模块变种

  • 实现快速、高效、参数可扩展


二、Kyber 使用流程(API)

Kyber 的典型使用涉及三个 API:

int crypto_kem_keypair(unsigned char *pk, unsigned char *sk);
int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk);
int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk);
步骤函数说明
1crypto_kem_keypair()生成公钥 + 私钥
2crypto_kem_enc()封装密钥:用公钥生成密文 ct + 对称密钥 ss
3crypto_kem_dec()解封装密钥:用私钥解密 ct 得到密钥 ss

三、数学原理

Kyber 的加密基于以下数学结构:

1)模数与多项式

  • 所有计算都在有限环中进行:
    $Z_q[X]/(X^n + 1)$

  • 常用参数:$q = 3329$,$n = 256$,即多项式系数范围 [0, 3328]

2)模式(Module)LWE

Kyber 不是普通 LWE,而是模块化版本:Module-LWE(模块学习带噪声)

  • 模块结构:A 是 $k \times k$ 多项式矩阵,s 是多项式向量

  • 密文结构:一对多项式向量(u, v)


四、核心结构与流程详解

我们用 Kyber768 为例。

1)crypto_kem_keypair

步骤:

  1. 随机生成种子 seed

  2. 生成公共矩阵 $A$,秘密向量 $s$ 和错误向量 $e$

  3. 计算公钥:$pk = A·s + e$

  4. 私钥保留原始 $s$,并包含 $pk$、哈希(pk)、随机值 z

对应代码:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>#define KYBER_K 2       // 向量维度(Kyber512=2,Kyber768=3,Kyber1024=4)
#define N 256           // 多项式长度(固定为 256)
#define Q 3329          // Kyber 模数// --------- 多项式与多项式向量结构定义 ---------
typedef struct {int16_t coeffs[N]; // 多项式系数
} poly;typedef struct {poly vec[KYBER_K]; // 多项式向量
} polyvec;// --------- 简化的随机数与噪声生成 ---------
void get_noise(poly *r) {for (int i = 0; i < N; i++) {r->coeffs[i] = rand() % 10 - 5; // 简化为 [-5, 4] 区间的噪声}
}void polyvec_getnoise(polyvec *v) {for (int i = 0; i < KYBER_K; i++) {get_noise(&v->vec[i]);}
}// --------- 简化的矩阵 A 生成 ---------
void gen_matrix(polyvec A[KYBER_K], const uint8_t *seed) {srand(seed[0]); // 简化用种子第一个字节设置随机种子for (int i = 0; i < KYBER_K; i++) {for (int j = 0; j < KYBER_K; j++) {get_noise(&A[i].vec[j]); // 用噪声函数代替真实伪随机生成}}
}// --------- 多项式乘加运算:N = A * s + e ---------
void poly_muladd(polyvec *res, polyvec A[KYBER_K], polyvec *s, polyvec *e) {for (int i = 0; i < KYBER_K; i++) {for (int j = 0; j < N; j++) {res->vec[i].coeffs[j] = e->vec[i].coeffs[j];for (int k = 0; k < KYBER_K; k++) {res->vec[i].coeffs[j] += A[i].vec[k].coeffs[j] * s->vec[k].coeffs[j];res->vec[i].coeffs[j] %= Q;}}}
}// --------- 打包函数(这里只做打印模拟) ---------
void pack(polyvec *pk) {printf("Public Key:\n");for (int i = 0; i < KYBER_K; i++) {for (int j = 0; j < 8; j++) { // 只打印前8个系数printf("%d ", pk->vec[i].coeffs[j]);}printf("...\n");}
}// --------- 存储函数(这里也做打印) ---------
void store(polyvec *s, const char *name) {printf("Stored %s (first 8 coeffs):\n", name);for (int j = 0; j < 8; j++) {printf("%d ", s->vec[0].coeffs[j]);}printf("...\n");
}// --------- 主函数:执行密钥生成 ---------
int main() {polyvec s, e, pk;polyvec A[KYBER_K];uint8_t seed[32] = {42}; // 模拟种子值gen_matrix(A, seed);             // 生成公共矩阵 Apolyvec_getnoise(&s);            // 私钥 s 加噪声polyvec_getnoise(&e);            // 误差项 e 加噪声poly_muladd(&pk, A, &s, &e);     // pk = A * s + epack(&pk);                       // 打包公钥(这里只是打印)store(&s, "sk");                 // 存储私钥(这里只是打印)return 0;
}

2)crypto_kem_enc

  • 输入公钥 pk

  • 生成临时随机密钥 m

  • 哈希 m 与 pk 得种子

  • 生成 ephemerals:sp, e1, e2

  • 计算密文:

    • $u = A^T · sp + e1$

    • $v = pk^T · sp + e2 + m·(q/2)$

  • 输出密文 + 哈希(m)

crypto_kem_enc 核心实现(对应 Kyber 规范):

#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "params.h"
#include "poly.h"
#include "polyvec.h"
#include "indcpa.h"
#include "symmetric.h"
#include "randombytes.h"
#include "hash.h"// 输出:ct = 密文,ss = 会话密钥,输入 pk
void crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk) {uint8_t buf[2 * KYBER_SYMB];   // 存放 m || H(pk)uint8_t kr[2 * KYBER_SYMB];    // 存放 H(m||pk) → kr[0:32]=K, kr[32:64]=coinspolyvec sp, pkpv, e1, at[KYBER_K];poly v, e2, m;uint8_t seed[KYBER_SYMB];// 1)生成临时密钥 mrandombytes(buf, KYBER_SYMB);               // 生成随机 m(长度32字节)hash_h(buf, buf, KYBER_SYMB);               // m ← H(m) 做 domain separation// 2)拼接 m || H(pk),用于生成加密种子 coinshash_h(buf + KYBER_SYMB, pk, KYBER_INDCPA_PUBLICKEYBYTES); hash_g(kr, buf, 2 * KYBER_SYMB);            // kr ← H(m || H(pk))// 3)解包公钥(提取多项式向量 pkpv)unpack_pk(&pkpv, seed, pk);                 // pk ← 多项式 pkpv + seed// 4)生成矩阵 A^Tgen_matrix(at, seed, 1);                    // A^T ← transpose(A)// 5)用 kr[32:64] 生成临时私钥 sp 与误差项 e1, e2polyvec_getnoise_eta1(&sp, kr + KYBER_SYMB, 0);polyvec_getnoise_eta1(&e1, kr + KYBER_SYMB, KYBER_K);get_noise_eta2(&e2, kr + KYBER_SYMB, 2 * KYBER_K);// NTT 变换polyvec_ntt(&sp);polyvec_ntt(&pkpv);// 6)计算 u = A^T · sp + e1polyvec_pointwise_acc_montgomery(&v, &pkpv, &sp); // v = pk^T * sppolyvec_frommont(&e1);polyvec_add(&e1, &e1, &at[0]); // 实际实现是循环内完成 A^T·sp + e1polyvec_reduce(&e1); // 模 Q 归约pack_ciphertext(ct, &e1, &v);  // u 部分// 7)v = pk^T·sp + e2 + m*(q/2)poly_frommsg(&m, buf);                // m → 多项式 m(位乘 q/2)poly_add(&v, &v, &e2);                // v += e2poly_add(&v, &v, &m);                 // v += m·(q/2)poly_reduce(&v);pack_ciphertext(ct, &e1, &v);         // v 部分合并进 ct// 8)会话密钥 ss = H(K || H(ciphertext))hash_h(kr + KYBER_SYMB, ct, KYBER_CIPHERTEXTBYTES); // kr[32:64] = H(ct)kdf(ss, kr, 2 * KYBER_SYMB);                        // ss = KDF(K || H(ct))
}

3)crypto_kem_dec

  • 输入密文 + sk,恢复 s

  • 解密计算:

    • 计算 $m' = v - u·s$

  • 从 $m'$ 派生共享密钥 ss'

crypto_kem_dec() 的核心解密代码:

void crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk) {uint8_t buf[2 * KYBER_SYMB];   // 临时缓冲区,存储 m' || H(c)uint8_t kr[2 * KYBER_SYMB];    // kr = K || H(c)polyvec sp, bp, skpv;poly v, mp;const uint8_t *pk = sk + KYBER_INDCPA_SECRETKEYBYTES; // 从 sk 中提取出 pkconst uint8_t *hpk = pk + KYBER_INDCPA_PUBLICKEYBYTES;// 1)从 sk 解包私钥 s 向量unpack_sk(&skpv, sk); // 恢复 polyvec s ← sk// 2)解包密文 ct 得到 u、vunpack_ciphertext(&bp, &v, ct); // u = bp, v = v// 3)NTT 变换polyvec_ntt(&bp);// 4)m' = v - (u ⋅ s)polyvec_pointwise_acc_montgomery(&mp, &skpv, &bp); // mp = u ⋅ spoly_invntt_tomont(&mp);                           // 逆NTTpoly_sub(&mp, &v, &mp);                            // m' = v - u·spoly_reduce(&mp);                                  // 模Q规约poly_tomsg(buf, &mp);                              // 提取消息 m' → buf[0:32]// 5)拼接 m' || H(pk)memcpy(buf + KYBER_SYMB, hpk, KYBER_SYMB);         // 拼接 H(pk)// 6)哈希派生 kr = H(m' || H(pk))hash_g(kr, buf, 2 * KYBER_SYMB);                   // kr = K || coins// 7)计算 H(ct) 加入 kr 中hash_h(kr + KYBER_SYMB, ct, KYBER_CIPHERTEXTBYTES); // kr[32:64] = H(c)// 8)派生共享密钥 ss = KDF(kr)kdf(ss, kr, 2 * KYBER_SYMB);                       // ss ← H(K || H(c))
}

五、源码结构分析(以 PQClean 为例)

路径

PQClean/crypto_kem/kyber768/clean/
├── api.h                // 接口声明
├── kem.c                // 封装主流程(keypair, enc, dec)
├── indcpa.c / .h        // CPA-secure加密流程(核心)
├── poly.c / .h          // 多项式运算实现
├── ntt.c                // 快速傅里叶变换(NTT)
├── randombytes.c        // 随机数生成
├── verify.c             // 常量时间比较等

六、逆向分析建议

目标识别

项目逆向技巧
crypto_kem_keypairGhidra 查找调用伪随机函数,识别 spk 生成
crypto_kem_enc重点分析 polyvec 结构、模运算、hash 种子生成
crypto_kem_dec跟踪 v - u·s 运算,是否有解密中间态泄露
随机数源Hook randombytes,可伪造 predictable key

Frida 示例:Hook 密钥生成

Interceptor.attach(Module.findExportByName(null, "crypto_kem_keypair"), { // Hook 到导出函数 crypto_kem_keypair 的地址onEnter(args) { // 函数执行前触发,args 是参数数组console.log("keypair called"); // 输出日志,表示函数开始执行},onLeave(retval) { // 函数执行结束后触发,retval 是返回值console.log("keypair done"); // 输出日志,表示函数执行完毕}
});

IDA/Ghidra 静态分析:

  • 搜索 CRYPTO_PUBLICKEYBYTES,定位缓冲区分配

  • 查找 NTT 函数(多使用查表或优化运算)


七、实现中可能存在的风险点

风险类型描述
随机数问题伪随机数不安全可被预测
缓冲区未擦除私钥残留在内存中
错误信息可侧信道攻击不同错误路径返回不同信息量
非常量时间操作对输入密文不同响应时间,导致 side-channel 攻击
缓存攻击模式化访存、FFT变换泄露私钥结构

八、总结重点

解释
算法分类Kyber 是 lattice-based,加密目标是密钥,不是数据
模数操作所有乘法/加法在模 q = 3329 上进行
多项式向量核心运算单位是 polyvec,即多个多项式组成的向量
安全来源基于 Module-LWE 难题,不怕量子算法(Shor/Grover)
实战方向TLS握手、Frida hook、NTT逆向、种子分析、内存提取
http://www.lryc.cn/news/573470.html

相关文章:

  • 【软考高级系统架构论文】论多源数据集成及应用
  • 组件之间的双向绑定:v-model
  • GitHub OAuth 认证示例
  • 闲庭信步使用SV进行图像处理系列教程介绍
  • 2025年- H83-Lc191--139.单词拆分(动态规划)--Java版
  • 吴恩达:从斯坦福到 Coursera,他的深度学习布道之路
  • C++基础练习-二维数组
  • C++ 文件读写
  • GPT-1 与 BERT 架构
  • 开源项目分析:EDoRA | 了解如何基于peft实现EDoRA方法
  • 【软考高级系统架构论文】论无服务器架构及其应用
  • 博图SCL语言GOTO语句深度解析:精准跳转
  • 深入解析ID3算法:信息熵驱动的决策树构建基石
  • GO语言---数组
  • 基于Spring Boot瀚森健身房会员管理系统设计与实现【源码+文档】
  • 作为测试人员,平时用什么大模型?怎么用?
  • 《深入解析:如何通过CSS集成WebGPU实现高级图形效果》
  • 【软考高级系统架构论文】论企业应用系统的数据持久层架构设计
  • 【FineDance】舞蹈多样性的得来
  • RocketMQ--为什么性能不如Kafka?
  • verilog HDLBits刷题“Module cseladd”--模块 cseladd---Carry-select adder 进位选择adder
  • 为车辆提供路径规划解决方案:技术演进、挑战与未来蓝图
  • 【appium】2.初始连接脚本配置
  • C++模板基础
  • 【AGI】突破感知-决策边界:VLA-具身智能2.0
  • 用OBS Studio录制WAV音频,玩转语音克隆和文本转语音!
  • 《揭开CSS渲染的隐秘角落:重排与重绘的深度博弈》
  • 【StarRocks系列】查询优化
  • 操作系统进程与线程核心知识全览
  • 前端开发面试题总结-vue3框架篇(二)