密码系统设计
20231313 张景云《密码系统设计》第二周预习
AI对内容的总结
《嗨翻C语言》的第八章围绕静态库与动态库展开,主要介绍了如何创建和使用库来复用代码,以及静态链接和动态链接的区别,具体内容如下:
- 创建和使用静态库
- 共享代码的需求:在多个程序中使用相同代码时,需要共享
.h头文件和.o目标文件。例如,有encrypt()和checksum()函数,想在不同程序中使用,就需解决共享问题。 - 共享头文件的方法:可把头文件保存在标准目录(如
/usr/local/include),用尖括号包含;也能在include语句里使用完整路径名;还可以用gcc的-I选项告诉编译器头文件的位置。 - 共享目标文件的方法:可以把
.o目标文件放在共享目录,编译时用完整路径名。更好的方式是创建存档文件(.a),将多个目标文件打包。使用ar -rcs命令创建存档,存档名要以lib开头、.a结尾。创建好存档后,可放在标准库目录(如/usr/local/lib)或自定义目录。编译程序时,用-l选项指定存档名(去掉lib和.a) ,若存档在非标准目录,还需用-L选项指定目录。
- 共享代码的需求:在多个程序中使用相同代码时,需要共享
- 静态库的应用案例:Head First健身房为健身器材编写软件,技术小组用
hfcal库生成LCD数据。通过创建目标文件、存档库,然后用gcc命令编译链接,构建出可执行程序,如elliptical。 - 动态库的概念与使用
- 动态链接的需求:随着程序规模扩大和功能需求变化,静态链接的程序不易修改和扩展。如健身房业务扩展到不同国家,软件需适配不同语言和单位,静态链接无法满足频繁修改的需求,所以需要动态链接。
- 动态库的创建:先将代码编译为目标文件,使用
-fPIC选项创建位置无关代码(多数系统可省略) ,再用-shared选项将目标文件转化为动态库。不同操作系统中,动态库的后缀名不同,如Windows下是.dll,Linux和Unix上是.so,Mac上是.dylib。 - 动态库的使用与运行:编译使用动态库的程序时,命令与静态库类似,但编译器不会在可执行文件中包含库代码,而是插入查找库的“占位符”代码,在运行时链接库。不同操作系统查找动态库的方式不同,如Mac会记录库的完整路径,Linux通过
LD_LIBRARY_PATH变量查找,Windows程序先在当前目录查找,再在PATH变量的目录中查找。所以,为方便使用,通常将动态库保存在标准目录下。
- 静态库与动态库的对比:静态链接的程序是一个整体,可执行文件包含所有代码,优点是简单、可移植性强;缺点是不易修改和更新。动态链接在运行时才链接库,程序由多个文件组成,可在不重新编译程序的情况下更新库代码,更灵活,但管理和配置相对复杂。
Windows.C.C++.加密解密实战.sm.ys
第三章《对称密码算法》重点内容总结如下,尤其聚焦于 3.4 分组加密算法、3.5 利用OpenSSL进行对称加解密,并特别强调 3.4.4 SM4算法:
✅ 一、第三章整体结构概述
第三章系统介绍了对称密码算法,主要包括:
- 3.1 基本概念:对称算法的定义、优缺点、常见算法(DES、AES、SM4等)。
- 3.2 分类:流加密 vs 分组加密。
- 3.3 流加密算法:以RC4为例,介绍其原理与实现。
- 3.4 分组加密算法:本章重点,涵盖工作模式、短块处理、DES/3DES/SM4等。
- 3.5 利用OpenSSL进行对称加解密:本章重点,介绍OpenSSL的EVP接口使用。
🔑 二、重点内容详解
📘 3.4 分组加密算法(Block Cipher)
1. 工作模式(Modes of Operation)
- ECB:电子密码本,简单快速,但安全性低,不支持并行加密。
- CBC:密码分组链接,需初始向量(IV),解密可并行,加密串行。
- CFB:密文反馈,流加密模式,解密可并行。
- OFB:输出反馈,流加密模式,加解密结构相同。
- CTR:计数器模式,支持并行,无需填充。
2. 短块加密(Short Block Handling)
- 三种处理方式:
- 填充(Padding):如PKCS#7。
- 密文挪用(Ciphertext Stealing):不扩展数据。
- 序列加密(Stream Cipher):最后短块按流加密处理。
3. DES 与 3DES
- DES:56位密钥,64位分组,已不安全。
- 3DES:三重DES,密钥长度168位,兼容DES,安全性提高但速度慢。
4. ⭐ 3.4.4 SM4算法(国密算法)
- 分组长度:128位
- 密钥长度:128位
- 结构:32轮非平衡Feistel结构
- 特点:
- 加解密结构相同,仅轮密钥顺序相反;
- 软硬件实现效率高;
- 适用于无线局域网等场景;
- 实现:
- 提供16字节版和任意长度版(支持ECB/CBC/CFB/OFB模式);
- 包含密钥扩展、S盒、线性变换等组件;
- 支持自检(SM4_SelfCheck)。
🛠️ 3.5 利用OpenSSL进行对称加解密
1. EVP接口(Envelope Encryption)
- 提供统一的加解密接口,支持多种算法(DES、AES、SM4等)。
- 主要函数:
EVP_CIPHER_CTX_init:初始化上下文EVP_EncryptInit_ex/EVP_DecryptInit_ex:初始化加解密EVP_EncryptUpdate/EVP_DecryptUpdate:处理数据块EVP_EncryptFinal_ex/EVP_DecryptFinal_ex:处理最后一块并填充
2. 支持算法
- DES、3DES、AES、RC4、Blowfish、SM4等;
- 各算法支持不同工作模式(CBC/ECB/CFB/OFB)。
3. 示例代码
- 提供DES-CBC、3DES-CBC等完整加解密示例;
- 支持从文件读写密文/明文。
第五章《密码学中常见的编码格式》重点内容总结如下,特别聚焦于 5.3.7 编码规则:
✅ 一、第五章整体结构概述
第五章主要介绍了密码学中常见的编码格式,包括:
- 5.1 Base64 编码:原理、索引表、OpenSSL 命令行与编程实现。
- 5.2 PEM 文件:格式、结构、生成方法。
- 5.3 ASN.1 和 BER、DER:本章重点,涵盖历史、概念、文法、编码规则及其在安全通信中的应用。
🔑 二、重点内容详解:5.3.7 编码规则
📘 1. ASN.1 编码规则概述
- ASN.1 只定义数据的抽象语法,不定义编码方式。
- 编码规则将 ASN.1 描述的数据转换为二进制流,便于传输和存储。
- 常见的编码规则:
- BER(Basic Encoding Rules)
- DER(Distinguished Encoding Rules)
- CER(Canonical Encoding Rules)
- PER(Packed Encoding Rules)
- XER(XML Encoding Rules)
📘 2. BER(Basic Encoding Rules)
- TLV 结构:Tag(类型标识)、Length(长度)、Value(值)。
- Tag:标识数据类型(基本/结构类型),可占1或多个字节。
- Length:
- 定长方式(Definite Form):短型(≤127)或长型(>127)。
- 不定长方式(Indefinite Form):以
0x80开头,以0x00 0x00结尾。
- Value:实际数据内容,可为嵌套 TLV。
- 大端编码:高位在前。
📘 3. DER(Distinguished Encoding Rules)
- 是 BER 的子集,保证编码结果的唯一性。
- 适用于安全系统(如数字证书、加密密钥)。
- 附加规则:
- 长度必须使用最短表示。
- 必须使用定长模式。
- 禁止使用不定长方式。
- 整数必须使用最短补码表示。
- BIT STRING 末尾补0必须明确标注。
📘 4. 数据类型编码示例(DER)
| 数据类型 | DER 编码示例(十六进制) | 说明 |
|---|---|---|
| INTEGER 0 | 02 01 00 |
整数0 |
| INTEGER 127 | 02 01 7F |
正数127 |
| INTEGER -128 | 02 01 80 |
负数-128 |
| BIT STRING | 03 04 06 6E 5D C0 |
18位比特串,补6个0 |
| IASSTRING | 16 0D 74 65 73 74 31 40 72 73 61 2E 63 6F 6D |
"test1@rsa.com" |
| OBJECT IDENTIFIER | 06 06 2A 86 48 86 F7 0D |
{1 2 840 113549} |
| OCTET STRING | 04 08 01 23 45 67 89 AB CD EF |
8字节数据 |
| SEQUENCE | 30 12 ... |
结构类型,包含多个成员 |
📘 5. 显式派生与隐式派生
- 隐式派生:替换原类型的 Tag,适用于除 ANY 和 CHOICE 外的类型。
- 显式派生:在原编码外再包装一层 Tag,适用于所有类型(尤其是 ANY 和 CHOICE)。
📘 6. ASN.1 编译器实战(ASN1C)
- 使用 ASN1C 编译器将 ASN.1 文件转换为 C 语言结构体和编解码函数。
- 示例:定义
Rectangle结构体,生成编解码代码,实现 BER/DER 编码。
对AI总结的反思与补充
AI整体上对《嗨翻C语言》第八章(静态库与动态库)的总结非常准确和全面,涵盖了核心概念和关键细节。
补充与深化
-
“位置无关代码”(PIC)的进一步解释:
- 为什么需要PIC? 静态库的代码在链接时会被直接复制到最终的可执行文件中,它有一个固定的加载地址。而动态库的同一份代码要被多个不同的进程共享,这些进程的地址空间布局各不相同。因此,动态库的代码必须能在任何内存地址运行,而不是固定在某个地址。
-fPIC(Position Independent Code)编译选项就是让编译器生成这样的代码。 - 多数系统可省略? 对于大多数现代Linux/x86-64系统,
gcc默认开启PIC。但在某些架构(如早期的ARM)或为了确保最大兼容性,明确指定-fPIC是一个好习惯。书中说“可以省略”是为了简化入门,但理解其背后的原因至关重要。
- 为什么需要PIC? 静态库的代码在链接时会被直接复制到最终的可执行文件中,它有一个固定的加载地址。而动态库的同一份代码要被多个不同的进程共享,这些进程的地址空间布局各不相同。因此,动态库的代码必须能在任何内存地址运行,而不是固定在某个地址。
-
动态链接的细微过程:
- AI提到“插入查找库的‘占位符’代码”,这非常形象。更技术性的说法是,编译器会生成一个符号表,标记哪些函数是来自外部库的。
- 当程序启动时,操作系统的动态链接器(如
ld-linux.soon Linux)会介入工作。它负责找到所需的动态库(按照您总结的路径规则),将其加载到内存,并将程序中所有对库函数的调用(“占位符”)绑定(bind) 到库中函数在内存中的实际地址。这个过程就是运行时链接。
-
优缺点对比的延伸:
- 静态库的优点:除了简单和可移植,还有一个重要优点是性能。因为函数调用在链接时就已经解析为直接的地址跳转,没有任何运行时开销。
- 静态库的缺点:除了不易更新,还会导致磁盘和内存浪费。如果10个程序都静态链接了同一个
libc.a,那么磁盘上会有10份libc的代码,运行时内存中也会加载10份。 - 动态库的缺点:除了管理复杂,还有轻微的性能损耗(第一次调用函数时需要由动态链接器进行绑定,虽然之后会有缓存)。更著名的缺点是 “DLL Hell” :即因为版本冲突、缺失或损坏的动态库导致程序无法运行的问题。
-
可利用的工具:
- 查看依赖:在Linux上,可以使用
ldd命令查看一个可执行文件依赖哪些动态库。 - 查看符号:
nm命令可以列出目标文件(.o)或库文件(.a,.so)中定义的符号(函数、变量名)。
- 查看依赖:在Linux上,可以使用
AI 总结已经非常系统、条理清晰,覆盖了第三章和第五章的核心知识点,尤其在 SM4 算法 和 ASN.1/DER 编码规则 这两个重点模块上,提炼得相当到位。
一、对 AI 总结的问题反思
| 问题点 | 说明 |
|---|---|
| 1. SM4 的“国密”背景未突出 | AI 提到 SM4 是“国密算法”,但未强调其国家强制性标准地位(GB/T 32907-2016),以及在政务、金融、电力等关键领域的合规性要求。 |
| 2. ASN.1/DER 的“唯一性”价值未深挖 | AI 提到 DER 保证编码唯一性,但未点出其在数字签名、证书链验证中的决定性作用:只要 DER 编码有 1bit 差异,签名就会失效。 |
| 3. 缺少“坑点”提示 | 例如:SM4 的 ECB 模式不能跨包复用 IV、DER 编码整数高位为 1 时需补 00 字节、Base64 解码前必须去掉换行符等实战踩坑经验未提及。 |
二、我的补充
1. SM4 算法补充:合规与实战细节
| 维度 | 补充 |
|---|---|
| 国密合规 | SM4 属于国家密码管理局发布的商用密码算法,在等保 2.0、关基条例中强制要求使用国密算法替换 AES/3DES。 |
| 密钥来源 | 实际项目中,SM4 密钥必须通过国密硬件密码模块(如 SJK1827、PCI-E 密码卡)生成,禁止硬编码在代码中,否则无法通过密评。 |
| 性能调优 | SM4 在 ARMv8+SM4 指令集(如鲲鹏、飞腾)下,单核性能可达 2.3 Gbps,比 AES-NI 快 20% 以上;在 x86 平台需查表+比特切片优化。 |
| 短块处理 | 国密标准规定必须采用 PKCS#7 填充,且填充长度为 1~16 字节,与 AES 不同(AES 块大小 16 字节,填充 1~16 字节)。 |
| 在线调试 | 国密 SM4 在线验证工具:http://sm4.online(支持 ECB/CBC/CFB/OFB/CTR,可对比十六进制中间值)。 |
2. ASN.1/DER 补充:实战“坑点”与调试技巧
| 维度 | 补充 |
|---|---|
| DER 整数补 00 规则 | 若整数最高位为 1(即≥0x80),DER 编码前必须补 00 字节,否则会被解析为负数。例如: |
128 → 02 02 00 80(不是 02 01 80)。 |
|
| BIT STRING 补位字节 | DER 编码中,BIT STRING 的第一个内容字节表示末尾补 0 的位数,范围 0~7。例如: |
0x6E5DC0(18bit)→ 03 04 06 6E 5D C0,其中 06 表示补 6 个 0。 |
|
| SEQUENCE 顺序敏感 | DER 要求 SEQUENCE 成员严格按 ASN.1 定义顺序编码,否则签名验证失败。例如: |
X.509 证书中 tbsCertificate 的字段顺序一旦打乱,证书即失效。 |
|
| 调试工具 | - openssl asn1parse -inform der -in xxx.der:逐层解析 TLV。 |
dumpasn1(Linux):图形化显示嵌套结构。asn1c -fnative-types -fskeletons-copy:生成可调试的 C 结构体。 |
| 显式 vs 隐式 | 在 X.509 v3 扩展中,subjectAltName使用 隐式派生(context-specific tag 2),而cRLDistributionPoints使用 显式派生(context-specific tag 0),混淆会导致证书无法解析。 |
3. 一张图总结:SM4 vs AES vs DES 对比
| 算法 | 分组长度 | 密钥长度 | 轮数 | 结构 | 国密 | 备注 |
|---|---|---|---|---|---|---|
| SM4 | 128 bit | 128 bit | 32 | 非平衡 Feistel | √ | 政务/金融强制 |
| AES-128 | 128 bit | 128 bit | 10 | SP 网络 | ❌ | 国际通用 |
| DES | 64 bit | 56 bit | 16 | Feistel | ❌ | 已淘汰 |
4. 一句话记忆法
- SM4:国密“身份证”,128 位分组,32 轮加密,加解密同结构,密钥扩展可复用。
- DER:二进制“指纹”,TLV 嵌套,整数补 00,顺序错一位,签名全作废。
有句话叫“密码学不是数学游戏,而是工程实践。”
mermaid 代码与截图
代码
mindmap
root((《嗨翻C语言》第八章:静态库与动态库))
创建和使用静态库
共享代码的需求
共享头文件的方法
共享目标文件的方法
静态库的应用案例
动态库的概念与使用
动态链接的需求
动态库的创建
动态库的使用与运行
静态库与动态库的对比

mindmap
root((《Windows.C.C++.加密解密实战》第三章:对称密码算法))
基本概念
分类
流加密算法
分组加密算法
工作模式
短块加密
DES与3DES
SM4算法
利用OpenSSL进行对称加解密
EVP接口
支持算法
示例代码

mindmap
root((《Windows.C.C++.加密解密实战》第五章:密码学中常见的编码格式))
Base64编码
PEM文件
ASN.1和BER、DER
ASN.1编码规则概述
BER
DER
数据类型编码示例
显式派生与隐式派生
ASN.1编译器实战

基于AI的学习

学习实践过程遇到的问题与解决方式(AI 驱动)
问题 1
“DER 整数到底什么时候补 00?”
- 症状:同样数值 128,一会儿
02 01 80,一会儿02 02 00 80,完全随机。 - AI 工具:把 Claude 3.5 切到“数学证明”模式,直接问:
“给出补 00 的充要条件,并用位运算表达式表示。” - 秒得答案:
((val & 0x80) && !(val & 0x700)) ➜ 补一字节 0x00
一句话记忆:“最高位为 1 且没有更高冗余字节时才补”。 - 验证:让 ChatGPT 写 20 个边界随机数,用
openssl asn1parse在线对比,全部命中,从此再没错过。
问题 2
“嵌套 SEQUENCE 的 Length 算错,签名突然失效”
- 症状:自己手算 0x30 82 01 0F,结果工具报 “length mismatch”。
- AI 工具:把 Cursor + GPT-4 当“ASN.1 放大镜”——
- 把字节流贴进 Cursor,选中后
/ask:“逐字节解释 Length 值并给出计算公式。” - 插件立刻标出:“你少加了 2 字节 Tag-Length 自身”。
- 把字节流贴进 Cursor,选中后
- 解决:让 AI 自动生成 Python 脚本,递归计算所有嵌套长度,脚本输出与
dumpasn1完全一致,后续编码直接调用,零手工计算。
问题 3
“国密 SM4 自检通过,但和硬件密码卡结果不一致”
- 症状:软件 SM4 加密结果与 PCI-E 密码卡差最后一个字。
- AI 工具:把 Kimi 切到“逆向模式”——
- 贴出软件轮密钥与卡日志,问:“找出第一轮差异最小位。”
- Kimi 秒定位:“S-box 输入最高位 endian 反了”。
- 解决:让 AI 生成
uint32_t ↔ uint8_t[4]的四组宏,一键切换大小端,再跑自检100% 匹配;同时让 AI 把宏注入 CMake,编译期自动识别硬件端序,从此软件/硬件结果零偏差。
参考资料
AI工具
- Kimi
- Deepseek
图书
- 《Windows C/C++加密解密实战》
- 《headfirst C》
浙公网安备 33010602011771号