20231408徐钰涵《密码系统设计》
20231408徐钰涵《密码系统设计》
第四周预习报告
学习内容
- Head First C 嗨翻 C 语言 第5章
- 《Windows C/C++加密解密实战》第 6,8,13,14 章
- 重点第14 章,第 6 章了解 ,第 8,13 参考
- 课程 mindmap
AI对学习内容的总结
总结
《Head First C》第5章
- 结构体(structs)
- 什么是结构体?
- 结构体是一种自定义的数据类型,用于将多个不同类型的数据组合成一个整体。
- 示例:
struct fish {
const char *name;
const char *species;
int teeth;
int age;
};
- 结构体的优势:
- 代码更清晰:将相关数据打包成一个变量。
- 易于维护:修改结构体内容时,函数接口无需改变。
- 支持嵌套:结构体中可以包含其他结构体。
- 如何使用结构体?
- 定义变量:
struct fish snappy = {"Snappy", "Piranha", 69, 4}; - 访问成员:使用点运算符
.,如snappy.name - 结构体指针:使用
->运算符,如t->age
- 定义变量:
- 结构体与函数:
- 直接传递结构体会复制整个结构体,可能影响性能。
- 建议传递结构体指针,避免复制,并允许函数修改原数据。
- 联合体(unions)
- 什么是联合体?
联合体是一种共享内存的数据类型,同一时间只能存储其中一个成员。
示例:
c
typedef union {
short count;
float weight;
float volume;
} quantity;
- 如何使用联合体?
- C89方式:
quantity q = {4};// 初始化第一个成员 - 指定初始化:
quantity q = {.weight = 1.5}; - 单独赋值:
q.volume = 3.7;
- C89方式:
- 注意事项
- 联合体的大小等于其最大成员的大小。
- 没有机制记录当前使用的成员,容易误用。
- 常与
enum结合使用,以记录当前存储的类型。
- 枚举(enums)
- 什么是枚举?
枚举用于定义一组命名的整数常量,提高代码可读性。
示例:
c
enum colors { RED, GREEN, BLUE };
enum colors favorite = GREEN;
- 枚举与联合体的结合:
用枚举标记联合体当前使用的类型,避免误用。
- 位域(bitfields)
- 什么是位域?
位域允许在结构体中指定成员占用的位数,用于节省内存。
示例:
c
typedef struct {
unsigned int first_visit : 1;
unsigned int come_again : 1;
unsigned int fingers_lost : 4;
} survey;
- 使用场景:
- 存储布尔值(1位)
- 存储小范围整数(如月份:0–11,需4位)
- 注意事项:
- 位域成员应为
unsigned int。 - 位域通常应分组使用,避免编译器填充对齐浪费空间。
- 位域成员应为
- 其他重要语法
- typedef
- 用于为类型创建别名,简化代码:
c
typedef struct { ... } phone;
phone p = {...};
- 指定初始化(C99)
可指定初始化某个成员,其他成员默认为0:
c
bike b = {.gears = 21, .height = 17};
- 重点注意事项
- 结构体赋值是复制,包括指针成员(浅拷贝)。
- 联合体节省内存,但需小心类型混淆。
- 位域适用于硬件编程、协议解析等对内存布局有严格要求的场景。
《Windows C/C++加密解密实战》第6,8,13,14章
- 第6章:非对称算法RSA的加解密(了解)
- 非对称密码体制概述:对比对称加密与非对称加密,介绍RSA、SM2等算法。
- RSA算法详解:
- 数学基础:素数、模运算、欧拉函数、扩展欧几里得算法等。
- 算法步骤:密钥生成、加密、解密、分组加密等。
- 实际应用:使用OpenSSL生成密钥、加密文件、编程实现。
- RSA的安全性及攻击方式:因子分解、选择密文攻击、公共模数攻击、小指数攻击等。
- 第8章:椭圆曲线密码体制(参考)
- ECC概述:与RSA相比的优势(密钥短、安全性高、速度快)。
- 椭圆曲线数学基础:
- 无穷远点、射影坐标、有限域、逆元等概念。
- 椭圆曲线的定义及其在密码学中的应用。
- ECC算法体系:
- 点加、倍点、标量乘运算的实现。
- 数据加密与解密流程。
- ECC的快速实现与安全参数选择。
- 第13章:SM2算法的数学基础(参考)
- 素域与二元扩域:
- Fp与F2m的定义与运算
- 多项式基、三项式基、正规基等表示方法。
- 椭圆曲线在Fp与F2m上的定义与运算
- 椭圆曲线多倍点运算的算法与复杂度分析:
- 二进制展开法、加减法、滑动窗口法等。
- 第14章:SM2算法的实现
- SM2算法概述
- 定位:中国自主研发的国密非对称加密算法,基于椭圆曲线密码(ECC)体系。
- 目标:替代RSA,提升安全性和效率,尤其在签名、密钥交换方面采用更安全的机制。
- 优势:相比RSA,在相同安全强度下密钥更短、性能更高(签名/验签速度更快)。
- SM2与椭圆曲线密码(ECC)
- SM2本质上是ECC的一种实现,使用一条256位的标准椭圆曲线。
- 需要理解的基础概念:
- 椭圆曲线方程(有限域上的点构成群)
- 点加、倍点、点乘运算
- 椭圆曲线离散对数问题(ECDLP)
- SM2的核心用途
- 数字签名:验证消息完整性、来源可信和不可抵赖性。
- 加密解密:使用接收方公钥加密,私钥解密。
- 密钥交换:用于双方安全协商会话密钥。
- SM2算法的数学基础
- 有限域:
- 素域Fp
- 二元扩域F2m
- 域上运算(加、乘、求逆)
- 椭圆曲线方程:
- Fp上:y2=x3+ax+b
- F2m上:y2+xy=x3+ax2+b
- 有限域:
- SM2加解密算法流程
- 加密流程:
- 生成随机数k
- 计算C1=[k]G
- 计算S=[h]PB,判断是否无穷远点
- 计算[k]PB=(x2,y2)
- 用KDF派生密钥t
- 计算C2=M⊕t
- 计算C3=Hash(x2||M||y2)
- 输出密文C=C1||C2||C3
- 解密流程
- 提取C1,验证是否为有效点
- 计算S=[h]C1,判断是否无穷远点
- 计算[dB]C1=(x2,y2)
- 用KDF派生t
- 解密M'=C2⊕t
- 验证Hash(x2||M'||y2)=C3
- 加密流程:
- SM2数字签名与验签流程
- 签名流程:
- 计算ZA=Hash(ENTLA||IDA||a||b||xG||yG||xA||yA)
- 计算e=Hash(ZA||M)
- 生成随机数k
- 计算(x1,y1)=[k]G
- 计算r=(e+x1) mod n
- 计算s=((1+dA)-1·(k-r·dA)) mod n
- 输出签名(r,s)
- 验签流程:
- 验证r,s∈[1,n-1]
- 计算e'=Hash(ZA||M')
- 计算t=(r'+s') mod n
- 计算(x1',y1')=[s']G+[t]PA
- 计算R=(e'+x1') mod n
- 验证R=r'
- 签名流程:
- 代码实现要点
- 使用MIRACL库:
- 大数运算、椭圆曲线点运算的基础库。
- 提供SM2加解密、签名验签的完整示例代码。
- 关键文件:
SM2_ENC.h/c:加解密实现SM2_sv.h/c:签名验签实现kdf.h/c:密钥派生函数与SM3杂凑算法实现
- 自测函数:
SM2_ENC_SelfTest():测试加解密SM2_SelfCheck():测试签名验签
- 使用MIRACL库:
对AI总结的反思与补充
反思与补充
问题:
- 缺乏具体性
AI的总结过于泛泛,没有包含原书可能具有的具体代码文件名、函数名、项目结构或详细实现步骤。 - 缺失关键细节
- 没有具体代码片段:原书肯定有大量的
//示例代码...,我的总结里完全没有体现。 - 缺少编译构建细节:如Visual Studio中如何配置项目属性、解决平台工具集兼容性、处理字符集等实际问题。
- 没有调试案例:缺少对典型错误(如内存泄漏、数据对齐问题、线程安全)的具体分析和解决方法。
- 没有具体代码片段:原书肯定有大量的
补充:
- SM2与ECC的关系:SM2是采用更安全机制、并固定使用一条标准曲线的ECC。
- SM2在“同等安全下密钥短、签名快”,但验签可能较慢,且系统改造需兼容RSA接口,长期共存。
- 代码模块(
kdf,SM2_ENC,SM2_sv)与算法功能(KDF/Hash, 加解密, 签名验签)对应。 - 代码实现流程:
- 密钥生成与持久化:使用
EVP_PKEY_CTX_new_id(EVP_PKEY_EC)并设置参数为SN_sm2p256v1 - 签名与验证:
- 使用
EVP_DigestSignInit和EVP_PKEY_CTX_set1_id(设置SM2用户ID,如“1234567812345678”)。 - 签名结果的DER编码与解码过程。
- 使用
- 加密解密:将SM2用于加密一个对称密钥(如SM4密钥),再使用该对称密钥加密实际数据。
- 密钥生成与持久化:使用
思维导图
mindmap
root((加密解密实战))
第6章: RSA算法
概述
非对称密码体制
公钥密码体制特点
与对称加密对比
RSA发展历史
1977年Rivest等提出
第一个完善的公钥算法
数学基础
核心概念
素数与素性检测
模运算与同余
欧拉函数与欧拉定理
费马定理
扩展欧几里得算法
RSA依赖的数学问题
大整数分解困难性
单向函数特性
RSA算法描述
密钥生成
选择大素数p和q
计算N等于p乘q
选择公钥指数e
计算私钥d
加密过程
C等于M的e次方模N
分组加密规则
解密过程
M等于C的d次方模N
RSA实现
简易实现示例
查找法计算私钥d
简便法计算私钥d
扩展欧几里得法
OpenSSL集成
生成RSA密钥对
公钥加密文件
私钥解密文件
编程接口使用
安全性分析
攻击方式
因子分解攻击
选择密文攻击
公共模数攻击
小指数攻击
安全参数选择
密钥长度建议
填充模式PKCS1
第8章: 椭圆曲线密码ECC
概述
发展历史
1985年Miller和Koblitz提出
比特币与二代身份证应用
ECC优势
安全性更高
密钥更短
计算效率更高
数学基础
核心概念
射影平面与无穷远点
有限域与域运算
椭圆曲线定义
ECC数学原理
椭圆曲线方程
点加法运算
倍点运算
点乘运算
ECDLP困难性
ECC算法体系
层次结构
有限域层模运算
曲线层点加和倍点
群运算层标量乘
应用层协议实现
ECC加解密
密钥对生成
加密流程
解密流程
基点选择
实现与优化
点运算实现
仿射坐标运算
射影坐标优化
标量乘算法
二进制展开法
滑动窗口法
NAF优化算法
第13章: SM2数学基础
有限域基础
素域Fp
定义与运算
椭圆曲线在Fp上
二元扩域F2m
多项式基表示
正规基表示
三项式基与五项式基
椭圆曲线表示
仿射坐标表示
点加运算规则
倍点运算规则
射影坐标表示
标准射影坐标
Jacobian加重射影坐标
椭圆曲线多倍点运算
算法实现
二进制展开法
加减法
滑动窗法
复杂度分析
不同坐标系的运算代价
优化策略
第14章: SM2算法实现
概述
定位
国密非对称加密标准
基于椭圆曲线密码体系
目标
替代RSA算法
提升安全性和效率
优势
密钥更短256位
性能更高
中国自主研发
SM2与椭圆曲线密码
本质ECC的一种实现
曲线参数256位标准曲线
基础概念
椭圆曲线方程
点加倍点点乘运算
ECDLP困难性
核心用途
数字签名
完整性验证
身份认证
不可抵赖性
加密解密
公钥加密
私钥解密
密钥交换
安全协商会话密钥
数学基础
有限域
素域Fp
二元扩域F2m
域运算加减乘求逆
椭圆曲线方程
Fp域方程
F2m域方程
加解密算法流程
加密流程
1生成随机数k
2计算C1等于k乘G
3计算S等于h乘PB
4计算k乘PB得到x2y2
5KDF派生密钥t
6C2等于M异或t
7C3等于Hash连接运算
8输出C1C2C3
解密流程
1提取C1验证点
2计算S等于h乘C1
3计算dB乘C1得到x2y2
4KDF派生t
5M撇等于C2异或t
6验证Hash值
数字签名与验签
签名流程
1计算ZA等于Hash
2e等于Hash连接
3生成随机数k
4x1y1等于k乘G
5r等于e加x1模n
6s计算公式
7输出r和s
验签流程
1验证rs范围
2e撇等于Hash
3t等于r撇加s撇
4x1撇y1撇计算
5R等于e撇加x1撇
6验证R等于r撇
代码实现要点
使用MIRACL库
大数运算
椭圆曲线点运算
完整示例代码
关键文件
SM2_ENC加解密实现
SM2_sv签名验签实现
kdf文件KDF与SM3
自测函数
SM2_ENC_SelfTest加解密测试
SM2_SelfCheck签名验签测试

基于AI的学习
学习内容
- RSA加密时分组的原因(十进制下的分析)
我: 我在学习RSA加密时看到"明文分组",不太明白,请你以苏格拉底的方式对我进行提问,一次一个问题。
AI: 好的。我们先回到一个最基础的问题:RSA的加密公式是 C = M^e mod N。这里的 M 和 C 分别代表什么?它们是字符还是数字?
我: M是明文,C是密文。它们应该是数字吧,因为公式里在做乘方和取模。
AI: 没错,它们是整数。那么,如果我想用RSA加密一句话“HELLO”,这个英文字符串能直接代入 M 吗?
我: 不能。得先把字母变成数字。
AI: 正确,这个过程叫编码。假设我们把每个字母用它的序号(A=1, B=2...)编码,那么“HELLO”就变成了一串数字:8,5,12,12,15。现在,我们可以把这整个数字串“85121215”当作一个巨大的 M 代入公式吗?
我: 应该不行吧,这个数字可能太大了。
AI: 你的直觉很对。为什么“可能太大了”是个问题?公式里哪个参数限制了 M 的大小?
我: 是 N。因为最后要 mod N。
AI: 非常关键!确切地说,为了保证加密解密不出错,M 必须满足什么条件?(提示:M 是明文,解密后要变回 M)
我: M 必须比 N 小?
AI: 是的,必须 0 ≤ M < N。如果 M 大于或等于 N,取模后就会丢失信息,无法正确解密。所以,面对很长的明文数字“85121215”,我们该怎么办?
我: 把它切成几段小的数字,每段都小于 N。
AI: 这个过程就叫“分组”。那么,最后一个问题:假设 N=33,而我们的编码数字是8,5,12,12,15。你会怎么分组?为什么不能简单地把两个数字合一起,比如“85”?
我: 85比33大,不行。所以只能一个数字一个数字地加密。8一组,5一组,12一组,12一组,15一组。
AI: 你完全理解了。RSA是一个“块加密”或“分组加密”算法,它每次只能加密一个小于 N 的整数块。对文本加密时,需要先编码成数字,再根据 N 的大小决定如何将这个数字序列切割成合适的“块”。这就是“明文分组”的核心原因。
- 椭圆曲线的数学问题
我: 我在看椭圆曲线密码,不懂"点的阶"是什么意思,请你以苏格拉底的方式对我进行提问,一次一个问题。
AI: 我们先看一个简单的比喻。在钟表上,时针从12点开始走,走一圈会回到12点。如果我们把“向前走1小时”看作一种运算,12点经过这种运算12次后回到自身。我们可以说12点在这种运算下的“阶”是12。现在,在椭圆曲线上,我们有一种基础的运算,是什么?
我: 加法,点加。
AI: 很好。椭圆曲线上的点,可以自己加自己。一个点 P,加上自己得到 2P,再加上 P 得到 3P,以此类推。那么,你猜“一个点 P 的阶”指的是什么?
我: 一个点加了多少次以后,会变回原来的点?
AI: 方向对了,但不是变回“原来的点”。在钟表例子里,我们回到了12点。在椭圆曲线上,有一个点相当于“起点”或“零点”,任何点加它都不变,这个点叫什么?
我: 无穷远点。
AI: 正确。那么,请你用 P、n 和 O(无穷远点) 来定义一下“点 P 的阶是 n”。
我: P 自己加自己,加 n 次以后,结果等于 O。
AI: 非常好,写作 nP = O,并且 n 是最小的那个正整数。现在思考一个关键:为什么点的阶这个概念在密码学里很重要?它和密码的哪个部分有关?(提示:私钥是一个数字,公钥是一个点)
我: 私钥 k 是个大数,公钥是 [k]G。G 是基点。
AI: 对。如果我们知道基点 G 的阶是 n,这意味着 nG = O。那么,如果私钥 k 比 n 大,比如 k = n + 5,那么公钥 [k]G 会等于什么?
我: [n+5]G = [n]G + [5]G = O + [5]G = [5]G。公钥和私钥是5的时候一样了。
AI: 正是!这会导致什么问题?
我: 两个不同的私钥,对应了同一个公钥,这样就乱套了,不安全。
AI: 完美。所以你发现了,点的阶 n 定义了一个循环的周期。在密码学中,我们必须让私钥 k 在这个周期内取值(1 < k < n),才能保证每个私钥对应唯一的公钥。因此,“点的阶”是椭圆曲线密码系统的一个基本安全参数,它决定了私钥的取值范围。
学习实践过程遇到的问题与解决方式
- 在RSA算法中,为什么要对数据先填充再加密?
解决:
- 实验测试: 用小参数(p=11, q=17, N=187)进行直接加密测试。发现当明文M=100时,加密解密正常。但当M=0或M=1时,密文C=0或C=1,加密没有效果;M=2,密文C=128,M=128,也得到了密文C=128。不同的明文加密后得到了相同的密文。
- 数学分析: RSA加密函数E(M)=Me mod N并不是单射函数,而是一个多对一的映射。当明文空间是{0,1,...,N-1}时,由于模运算的特性,多个明文可能映射到同一个密文。并且,RSA加密函数存在不动点:满足Me ≡ M mod N的M不止0和1。
- 安全性思考: 即使不考虑不动点,直接加密也存在两个严重问题:
- 确定性加密:相同的明文每次加密得到相同的密文,攻击者可以通过观察密文模式推断信息。
- 可塑性攻击:假设攻击者截获了密文C = Me mod N,他可以构造C' = C * 2e mod N。由于同态性质,解密后得到M' = 2M mod N。攻击者不需要知道M就能有目的地修改密文对应的明文!
- 理解填充的作用:
- 随机化:通过添加随机字节,确保相同明文每次加密得到不同密文。
- 破坏同态性:填充后的消息结构使得乘性同态性质无法被利用。
- 防止小明文攻击:当明文M很小时,Me可能小于N,此时C=Me(不需要取模),攻击者可以直接开e次方恢复M。
- 标准化结构:填充后的数据具有特定格式,解密时可以验证格式是否正确,从而检测是否被篡改。
- 为什么RSA需要两个大素数p和q?直接用一个大素数N作为模数不行吗?
- 背景:在学习RSA密钥生成时,我看到算法要求选择两个大素数p和q,然后计算N=p×q作为模数。这让我产生疑问:如果直接选择一个超大的素数N作为模数,然后选择公钥指数e,再计算私钥d满足e×d ≡ 1 mod (N-1),这样不也能形成非对称加密吗?这样不是更简单吗?为什么要用两个素数的乘积呢?
- 解决过程:
- 数学分析:
- 假设选择一个大素数N作为模数,根据费马小定理,对于任意a不被N整除,有a^(N-1) ≡ 1 mod N,选择e满足1<e<N-1 且gcd(e,N-1)=1,计算d使得e×d ≡ 1 mod (N-1)。
- 加密:C ≡ M^e mod N
- 解密:M ≡ C^d mod N
- 验证:C^d ≡ (Me)d ≡ M^(e×d) ≡ M^(1+k(N-1)) ≡ M×(M(N-1))k ≡ M×1^k ≡ M mod N
- 似乎没什么问题
- 分析安全性
- 这个方案存在致命的欧拉函数泄露问题:φ(N) = N-1(因为N是素数),攻击者知道N就知道φ(N)=N-1,一旦知道φ(N),就可以直接计算私钥d:d ≡ e^(-1) mod (N-1),这样公钥(N,e)直接就暴露了私钥d,毫无安全性了
- 对比现在的RSA算法
- 在标准RSA中,N=p×q,φ(N)=(p-1)(q-1)
- 从N难以分解出p和q,因此难以计算φ(N)
- 私钥d的计算需要φ(N),所以安全性基于大整数分解的困难性
- 在"单素数RSA"中,φ(N)=N-1是公开的,没有分解困难问题
- 如果用三个素数?
- 能不能用三个素数p,q,r,计算N=p×q×r,这样φ(N)=(p-1)(q-1)(r-1)?
- 虽然增加素数个数提高了分解难度,但研究表明RSA模数通常只用两个素数,因为:
- 更多素数会使φ(N)更接近N,可能降低安全性
- 两个足够大的素数已经提供足够安全性
- 密钥生成时找三个大素数更耗时
- 再次思考
- RSA的安全性不基于"离散对数问题",而是基于"大整数分解问题"
- 使用两个素数的乘积N,使得:
- 从N计算φ(N)等价于分解N
- 从公钥(N,e)计算私钥d需要φ(N),因此等价于分解N
- 如果使用素数N,则φ(N)=N-1是平凡的,没有计算困难性
- 数学分析:
参考资料
- AI工具:deepseek
- 图书
- 《Head First C》
- 《Windows C/C++加密解密实战》
浙公网安备 33010602011771号