20231326《密码系统设计》第三周预习报告

20231326《密码系统设计》第三周预习报告

学习内容

《Head First C 嗨翻 C 语言》第4章

  • 数据类型
    • char
    • short
    • int
    • float
    • double
    • long
    • unsigned
  • 数据类型强制转换
    • float z = (float)x / y;
  • 函数的调用
    • 要想调用某个函数,该函数定义必须写在当前位置之前
    • 相互调用的两个函数
  • 声明与定义分离
    • 函数声明只是一个函数签名
      • 函数名
      • 形参类型
      • 返回类型
    • 头文件
      • 以文件形式独立存在的函数声明
      • 引用方法
        • <>引用标准库头文件
        • ""引用本地库头文件
      • 优点
        • 简化主代码
        • 函数代码共享
  • gcc编译main.c
    • 预处理
      • gcc -E main.c -o main.i
    • 编译
      • gcc -S main.i -o main.s
    • 汇编
      • gcc -c main.s -o main.o
        链接
      • gcc main.o -o main
  • make自动化构建
    • makefile
    targets: prerequisites
        command
        command
        command 
    

《Windows C/C++加密解密实战》第4章

  • 杂凑函数
    • Hash
    • 将任长的输入消息串变化为固定长的输出串的函数
    • 公开
    • 满足条件(理想性质)
      • 输入长度任意长
      • 输出长度固定,现阶段至少128b(抵抗生日攻击)
      • 单向性
      • 强碰撞性
      • 弱碰撞性
    • 用途
      • 消息的认证性
      • 实现完整性校验
      • 提高数字签名有效性
      • 口令安全
      • 构造高效加密算法
      • ……
    • 发展历程
    • 分类
      • 不带密钥
        • 不具备身份认证功能
        • MDC
          • OWHF
          • CRHF
      • 带密钥
        • MAC
    • 设计
      • 基于分组密码的hash
        • Rabin提出
        • 分组迭代单项杂凑算法
          • 消息分段
          • 迭代映射
          • 末段填充
      • 直接构造的hash
    • hash碰撞
      • 对于n bit的hash,有\(2^n\)种组合,计算量庞大
      • SHA1已经不安全
  • SM3杂凑算法
    • 消息分组:512b
    • 输出长度:256b
    • 常量
      • \(IV\)
      • \(T_j\)
      • 布尔函数
      • 置换函数
    • 填充
    • 迭代压缩
      • 迭代
      • 消息扩展
      • 压缩函数
    • 杂凑值输出
  • HMAC
    • 密钥相关的哈希运算消息认证码
    • \(HMAC(K,M) = H(K \oplus opad | H(K \oplus ipad |M))\)
    • ipad: 0x36重复B次
    • opad: 0x5c重复B次
  • SHA系列
    • NIST和NSA设计
    • 发展史
      • 1993 SHA-0
      • 1995 SHA-1
      • 2002 SHA-256 SHA-384 SHA-512
      • 2008 SHA-224
    • 主要用途
      • 消息摘要
      • 口令保密
    • 原理
      • 初始化常量
      • 信息预处理
      • 逻辑运算
      • 消息映射
      • 迭代循环
      • 摘要输出

AI 对学习内容的总结

《Head First C 嗨翻 C语言》第4章

数据类型

  • 不同类型控制数据范围和精度:char, short, int, long, float, double, unsigned
  • 强制类型转换 (type)变量:让编译器把一个值“视为”另一种类型,例如 (float)x / y 避免整除。

函数与头文件

  • 函数声明:提供函数名、参数类型、返回类型,让编译器知道如何调用。
  • 函数定义:包含具体实现。
  • 头文件:集中存放声明,#include <...> 用标准库,#include "..." 用本地文件。
  • 好处:代码更简洁、函数可复用、多人协作更方便。

编译流程(GCC)

  1. 预处理:展开宏、引入头文件 → .i
  2. 编译:翻译为汇编 → .s
  3. 汇编:生成目标文件 → .o
  4. 链接:合并目标文件与库 → 可执行文件

make 自动化构建

  • Makefile 规则:目标 = 依赖 + 命令
  • 检测变动,只编译必要部分,减少重复劳动。

《Windows C/C++ 加密解密实战》第4章

杂凑函数(Hash)

  • 把任意长度输入映射为固定长度输出(数据“指纹”)。
  • 性质:单向性、抗碰撞、雪崩效应。
  • 应用:文件校验、数字签名、密码存储、加密算法设计。

SM3 算法

  • 我国标准 Hash 算法,输出 256 位。
  • 过程:消息填充 → 分组 → 扩展 → 压缩迭代。
  • 使用布尔函数与常量保证扩散性和安全性。

HMAC

  • 在 Hash 基础上加入密钥,使结果与发送方身份绑定。
  • 公式:HMAC(K, M) = H((K ⊕ opad) || H((K ⊕ ipad) || M))
  • 常用在认证和安全通信协议中。

SHA 系列

  • SHA-1:已不安全。
  • SHA-256/512:目前主流安全算法。
  • SHA-3:结构完全不同(海绵结构)。

总结联系

  • C 语言章节偏重 工程实现:如何组织代码、理解编译流程、工具链使用。
  • 密码学章节偏重 安全原理:如何通过 Hash 保证完整性、认证和抗攻击。
  • 结合应用:实现加密算法或协议时,需要既懂 C 的底层工程方法,又懂 Hash 的安全设计。

对 AI 总结的反思与补充

《Head First C 嗨翻 C 语言》第4章

你总结得不错的地方

  • 把数据类型、强制转换、函数调用规则、声明与定义、gcc 编译流程、makefile 都记录下来了,基本涵盖了教材的知识框架。

可以补充/反思的地方

  • 数据类型的范围和平台差异

    • 不同编译器/平台上 intlonglong long 的位数不完全相同。例如在 Windows (MSVC) 和 Linux (GCC) 上 long 的长度可能不一致。
    • 这点和写跨平台 C 程序密切相关。
  • 函数声明与定义的本质

    • 声明是接口,定义是实现,这和头文件分离的意义相关。
    • 头文件应避免放函数实现,以免多重定义。
  • gcc 流程更细节的理解

    • 预处理(-E)的结果里可以看到 #define 展开、#include 替换。
    • 链接阶段除了 .o 文件,还需要把标准库函数的目标代码合并,例如 printf 来自 libc。
  • make 的价值

    • 不只是自动化编译,还能通过依赖检测避免全量编译。
    • 反思点:为什么大型项目离不开构建工具(比如 cmakeninja)?这与软件工程规模化有直接关系。

《Windows C/C++ 加密解密实战》第4章

你总结得不错的地方

  • 系统性地整理了 Hash 的性质、用途、分类(MDC/MAC)、以及 SM3、HMAC、SHA 系列的原理与发展史。

可以补充/反思的地方

  • Hash 与加密的根本区别

    • Hash 是不可逆的,而对称/非对称加密是可逆的。
    • 补充:很多初学者容易混淆 Hash 与加密的应用场景。
    • 思考:为什么存储密码时用 Hash(加盐),而不是直接加密?
  • 碰撞复杂度

    • 你提到 “\(2^n\) 种组合”,可以进一步明确:
      • 任意碰撞复杂度:\(2^{n/2}\)(生日攻击原理)
      • 强碰撞复杂度:\(2^n\)
    • 反思:为什么 SHA-1 在 160 位输出长度下,实用攻击出现后就被废弃?
  • HMAC 的安全性来源

    • 关键是避免了长度扩展攻击,而普通的 hash(key||msg) 就会受攻击。
    • 思考:在实际系统中,如果你使用了 HMAC 来保证消息完整性,但消息传输时使用了 HTTP(明文传输),即便 HMAC 本身安全,也可能出现被篡改或被重放的风险。请分析为什么 HMAC 在这种情况下不能完全保证安全,并提出改进措施。
  • SM3 的定位

    • SM3 属于国家密码算法标准,主要用于国产密码体系。
    • 补充:学习时可以思考它和 SHA-256 的结构差异。
  • SHA 系列的延伸

    • 你总结到 SHA-224,但没有涉及 SHA-3(基于 Keccak 的海绵结构)。

学习思维导图

mindmap root((C语言与加密解密)) C基础((《Head First C》第4章)) 数据类型 强制转换 函数 调用规则 声明与定义 头文件 编译流程 预处理 编译 汇编 链接 自动化构建 makefile 加密哈希((《Windows C/C++加密解密实战》第4章)) Hash 特性 用途 分类 碰撞 SM3 分组 输出 常量 填充 压缩 HMAC 公式 ipad opad SHA 发展史 用途 原理

基于 AI 的学习

2025年09月24日
本次对话主题为:C语言与加密算法学习情况分析。
对话链接:https://chatgpt.com/share/68d3e94e-1780-800b-b055-2b149077a28a


[20:36:12] Gisli: 这是我最近一周学习的内容,请根据学习的笔记,对我进行苏格拉底式提问,以检验我的学习成果并指出你的缺乏点。一次一个问题

[20:36:30] AI: 好,哥们 😎,我们先从基础开始:
你说过 C 语言有 char, short, int, float, double, long, unsigned 等数据类型。
问题 1: 如果你有一个 int x = 5; int y = 2;,你写了 float z = (float)x / y;,这个 (float) 强制转换具体做了什么?为什么不加 (float) 得到的结果会不一样?

[20:37:05] Gisli: 将y强制转换成浮点型,这样由整型/浮点型,结果就是浮点型的正确答案;如果没有强制转换,则认为是int的除法,实际上是取整数商

[20:37:20] AI: 完全正确,哥们!👍
你的回答显示你理解了整型除法与浮点除法的区别以及强制类型转换的作用
接下来的问题,我们来考函数调用:
问题 2: 如果你有两个函数 foo()bar(),它们需要互相调用,你在源文件中应该怎么写?为什么直接按顺序定义可能会报错?

[20:37:40] Gisli: main.c
void foo();
void bar();

#此处调用

在源文件中是这样吗?我不太确定
直接调用,第一个调用的函数永远不知道第二个函数的定义。

[20:38:05] AI: 差不多对了,哥们,但我帮你梳理一下更准确的写法:

// 声明函数原型
void foo();
void bar();

int main() {
    foo();  // 调用 foo
    return 0;
}

// 定义函数
void foo() {
    bar();  // foo 调用 bar
}

void bar() {
    foo();  // bar 调用 foo
}

✅ 核心点:声明函数原型解决相互调用的顺序问题
❌ 直接调用而没有声明就会报错,因为编译器当时不知道函数的返回类型和参数。

问题 3: 你知道 gcc -E main.c -o main.igcc -S main.i -o main.sgcc -c main.s -o main.o 分别做什么吗?能用一句话说清楚每一步的作用吗?

[20:38:25] Gisli: 1.预处理:将代码调用的额外内容加入代码;将不必要的注释,或#ifndef等语句进行处理并移除;确保代码内容完全是可编译的
2.编译。用编译器将代码编译成汇编程序
3.汇编。将代码汇编成机器码

[20:38:55] AI: 不错,哥们,你对流程的理解基本到位,但我帮你稍微梳理得更精准一些:

  1. 预处理 (-E):处理 #include#define、条件编译指令等,把所有宏展开和头文件内容插入,生成纯 C 代码(.i 文件)。
  2. 编译 (-S):把 C 代码翻译成汇编语言(.s 文件),还不是机器码。
  3. 汇编 (-c):把汇编代码翻译成机器码,生成目标文件 .o,还不能直接运行。
  4. 链接 (gcc main.o -o main):把目标文件和库文件链接成可执行程序。

你的描述对汇编和机器码的关系理解稍微模糊,机器码是汇编生成的,而不是编译直接得到。

问题 4: 你说 hash 函数要满足“单向性、强碰撞性、弱碰撞性”。你能用自己的话解释一下 单向性强碰撞性 分别是什么意思吗?为什么 SHA-1 已经不安全了?

[20:39:15] Gisli: 单向性:给定一个哈希值,不能反向计算出原始数据
强碰撞性:随机任意选取消息,使得有两个消息产生相同的hash是极其困难的

[20:39:35] AI: 完全正确,哥们!💪

至于 SHA-1 不安全的原因,就是强碰撞性被攻破了:研究者已经能在可行时间内找到不同消息产生相同 SHA-1 的 hash 值。

问题 5: SM3 的消息分组是 512bit,输出长度是 256bit。你能说一下 为什么要填充消息,填充的作用是什么吗?

[20:39:55] Gisli: SM3分组为512b,当消息最后一组不足512b时,必须进行填充以得到512的分组

[20:40:15] AI: 完全对,哥们👍
填充的作用就是 保证每个消息分组都是固定长度,这样迭代压缩函数才能正确处理每一组数据。

问题 6: HMAC 的公式是 HMAC(K,M) = H(K ⊕ opad | H(K ⊕ ipad | M))。你能解释一下 为什么要用两次哈希,第一次和第二次哈希分别起什么作用吗?

[20:40:35] Gisli: 这个我不清楚,请讲以下

[20:41:00] AI: HMAC 之所以要 两次哈希,是为了增强安全性,防止一些针对单次哈希的攻击,比如长度扩展攻击。

  1. 第一次哈希 H(K ⊕ ipad | M):把密钥 K 和消息 M 结合,生成中间哈希值,保证消息不可篡改。
  2. 第二次哈希 H(K ⊕ opad | …):用密钥与第一次哈希结果组合,再次哈希,防止攻击者通过分析第一次哈希结果推出密钥或消息。
    总结:两次哈希=先内层混合消息+密钥,再外层再次用密钥封装中间值

[20:41:35] Gisli: 原来如此。我懂了。那么接下来继续

问题 7: 你提到 SHA 系列算法中有“初始化常量、信息预处理、逻辑运算、消息映射、迭代循环、摘要输出”这些步骤。你能说一下 信息预处理 包含哪些操作,以及为什么要做这些操作吗?

[20:42:10] Gisli: 比特填充使得报文长度模512余数为448;附加长度,用一个8B数据补充填入以指示原始消息长度

[20:42:30] AI: 完全对,哥们!💪

  1. 比特填充(padding):保证消息长度 mod 512 = 448,留出最后 64 位存放长度信息。
  2. 附加长度(length appending):最后 64 位存入原始消息长度(bit 数)。
    好处:消息长度固定便于分组迭代处理,同时可以抵抗长度扩展攻击。

问题 8: 在 C 语言中,如果你想把一些函数声明放在头文件里,然后在多个源文件中共享,这样做有什么优点?

[20:42:50] Gisli: 使主代码短长度得到控制;利于其他代码调用函数

[20:43:10] AI: 对,哥们👍
优点:

  1. 简化主代码
  2. 函数共享
  3. 降低耦合(实现细节和接口分离)

问题 9: 你在笔记里提到 makefile 可以自动化构建,里面写了 targets: prerequisitescommand。你能解释一下 make 是如何判断哪些文件需要重新编译 吗?

[20:43:30] Gisli: 这个我忘了

[20:43:50] AI: 没问题,哥们,我帮你回顾一下:
make 判断是否需要重新编译的原理是 依赖关系 + 时间戳

  1. 每个 target 有依赖文件列表(prerequisites)
  2. 检查目标文件是否存在,或是否比依赖文件旧
  3. 若目标文件不存在或依赖文件更新,则重新编译

问题 10: 你学习了 SM3 算法的迭代压缩,知道它分组 512bit。你能解释一下 迭代压缩函数为什么要做消息扩展 吗?

[20:44:10] Gisli: 简单的来说,make通过存在性与时效性判断是否需要重新编译?一个文件如果依赖发生更新,该文件应该编译以保证功能正常与更新。如果没有目标文件,则认为没有编译过

[20:44:30] AI: 完全对,哥们!👍
消息扩展的作用:把每个 512bit 的原始消息分组扩展成更多“工作变量”,使迭代压缩函数每轮能利用更多比特位,提高混合性和抗碰撞性


学习总结与分析

一、回答总结

  1. 强制类型转换:理解整型除法与浮点除法区别,知道 (float)x / y 可以得到浮点结果。 ✅
  2. 函数调用与声明:知道函数需要声明才能调用,尤其是相互调用时需函数原型;对函数声明与定义分离理解稍粗。
  3. GCC 编译流程:对预处理、编译、汇编、链接概念理解较好,但对编译生成汇编 vs 汇编生成机器码的细节稍模糊。
  4. Hash 与 SM3:单向性和强碰撞性理解清晰;消息分组、填充、迭代压缩基本理解正确;HMAC 两次哈希原理初次不清楚,通过解释理解。
  5. SHA 系列:信息预处理(填充 + 附加长度)理解准确;对 SHA-1 不安全原因有认知,但对 SHA-256 的差异和优势尚需掌握。
  6. C 语言头文件:能指出优点(简化主代码、函数共享),对“降低耦合”可进一步理解。
  7. Makefile 自动化构建:目标文件重编译判断逻辑理解较好(存在性 + 时效性)。

二、学习情况分析

  • 优点:基础知识反应快,概念性问题能用自己的话解释;数据类型、强制类型转换、Hash 概念掌握良好;makefile 逻辑清晰。

  • 不足 / 需要加强

    1. 函数声明与定义、头文件机制
    2. 编译与汇编细节
    3. HMAC 两次哈希原理
    4. SHA 系列安全性对比
    5. 工程实践:makefile 编写、依赖关系管理

三、改进建议

  1. 复习头文件与函数声明:写一个小项目练习多源文件互相调用函数,练习函数声明和头文件引用。
  2. 深化加密算法原理:理解 HMAC 内外层哈希作用,手算小消息 HMAC;学习 SHA-256 迭代结构及安全性。
  3. 实践编译流程:用 gcc -E/-S/-c 分步骤生成中间文件,观察每阶段输出。
  4. Makefile 实战:写包含多个源文件的小项目,修改部分文件测试 make 是否正确重编译。

总的来说,你的基础扎实,概念理解清楚,但一些加密算法细节和工程实践需要进一步动手和深入理解。

学习实践过程遇到的问题与解决方式

问题1: 为什么存储密码时用 Hash(加盐),而不是直接加密?

  1. Hash 不可逆:存储密码时,用 Hash 可以避免数据库泄露时,攻击者直接拿到明文密码。加密虽然能保护密码,但加密算法是可逆的,只要拿到密钥就能解密。
  2. 加盐防彩虹表攻击:如果多个用户使用相同密码,加盐(salt)能保证每个密码 Hash 不同,防止攻击者通过预先计算好的彩虹表快速破解密码。
  3. 安全性提升:结合 Hash + Salt,可以阻止暴力破解和重复使用密码攻击,比单纯加密更安全。

问题2: 为什么在已有 SHA-2 的情况下,还需要完全不同的 SHA-3?

AI解答:

  1. 设计差异:SHA-2 是基于 Merkle–Damgård 构造的迭代压缩函数,而 SHA-3 使用 Keccak 的 sponge 结构,结构完全不同。
  2. 防止潜在攻击:虽然目前 SHA-2 仍安全,但不同构造可以避免同类攻击(如长度扩展攻击或未来发现的结构性弱点),提高多样性和冗余性。
  3. 安全冗余和标准化:在关键领域(如政府、金融、区块链),标准化算法多样化可以降低单一算法失效带来的风险。
  4. 性能与特性:SHA-3 在某些硬件上更适合并行实现,还能直接生成任意长度输出,比 SHA-2 更灵活。

本文链接

参考资料


本文为作业内容,禁止转载在非【博客园】(域名cnblogs.com)以外,违者必究!!!

posted @ 2025-09-24 21:05  GisliW  阅读(29)  评论(0)    收藏  举报