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

20231321王曦轶《密码系统设计》第二周

第一周预习报告

学习内容

  • HeadFirstC嗨翻C语言第8章
  • 《Windows C/C++加密解密实战》第 3,5 章
    • 第三章重点3.4,3.5,特别3.4.4
    • 第五章重点5.3.7

AI 对学习内容的总结(1分)

要求

  • 让AI(kimi,元宝等)阅读学习内容并进行总结,教材内容可以使用微信读书或者云班课电子教材

总结

AI 对学习内容的总结(1分)

总结

《Head First C》第 8 章——库与系统调用全景漫游

  1. 静态库是“把工具焊死在行李箱”

    • ar rcs libfoo.a foo.o bar.o 把任意个 .o 做成归档
    • 链接器在生成 ELF 时把整个 .a 中有用的 .text 复制进最终可执行文件
    • 结果:单文件即可运行,但体积膨胀;任何 bug 修复都要重新编译整个程序
  2. 动态库是“把工具留在共享仓库”

    • 编译时只记录“我需要某个符号”——DT_NEEDED 条目
    • 运行时 ld-linux.so/etc/ld.so.cache 的搜索顺序把 .so 映射进内存
    • 所有进程共享同一份物理页,节省 RAM;升级库文件即可一次性修复全部依赖者
    • 版本噩梦:主版本号 libssl.so.3 变动会打破 ABI,需要同时保留新旧两版
  3. 调试三件套

    • nm -D libssl.so → 看导出符号
    • objdump -T libssl.so → 看动态符号表
    • ldd ./myapp → 递归列出运行时依赖
  4. 系统调用真面目

    • glibc 的 fopen() 最终走到 sys_openat()malloc()brk/mmap 上跳舞
    • strace ./myapp 可实时观察用户态→内核态的上下文切换
    • 自己写库时,把“菜单”(头文件)、“厨房”(.c)、“外卖”(.so)分离开,别人只 include 菜单即可

《Windows C/C++加密解密实战》第 3 章 3.4 / 3.5(重点 3.4.4)——EVP 全家桶

  1. 为什么需要 EVP

    • 早期 AES_encrypt()DES_cbc_encrypt() 每个算法一套 API,切算法=重写代码
    • EVP 把“算法”抽象成 EVP_CIPHER 结构体,同一套模板跑遍所有对称算法
  2. 3.4.4 八步模板(加密方向)
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, iv);
    ③ 可选:EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL);
    ④ 喂 AAD:EVP_EncryptUpdate(ctx, NULL, &outl, aad, aadlen);
    ⑤ 喂明文:EVP_EncryptUpdate(ctx, out, &outl, in, inl);
    ⑥ 结束:EVP_EncryptFinal_ex(ctx, out + outl, &finl);
    ⑦ 取 Tag:EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag);
    ⑧ 清理:EVP_CIPHER_CTX_free(ctx);

    • 解密侧把 ② 换成 EVP_DecryptInit_ex,⑥ 之后加 EVP_CTRL_GCM_SET_TAG 先设 Tag,若校验失败 DecryptFinal 返回 0
  3. 引擎机制——算法“插件化”

    • ENGINE *e = ENGINE_by_id("dynamic");
    • ENGINE_ctrl_cmd_string(e, "SO_PATH", "/usr/local/lib/af_alg.so", 0);
    • ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0);
    • 之后 EVP_EncryptInit_ex(ctx, EVP_get_cipherbyname("SM4-CBC"), e, ...) 即可调用国密硬件加速
    • 业务代码零改动,只换引擎=换实现
  4. 错误诊断

    • ERR_print_errors_fp(stderr) 一键打印调用栈
    • unsigned long err = ERR_get_error(); 单个错误码可转字符串

《Windows C/C++加密解密实战》第 5 章 5.3.7——把 PEM 藏进可执行文件

  1. 场景痛点

    • 桌面应用交付时不想附带 cert.pemkey.pem,防止用户误删
    • 更不想把路径硬编码,避免被 strings 一把抓
  2. 资源嵌入四连
    ① 在 .rc
    IDR_MYCRT RCDATA "client.pem"
    ② 编译生成 .res 并链进 .exe
    ③ 运行时

    HRSRC h = FindResource(NULL, MAKEINTRESOURCE(IDR_MYCRT), RT_RCDATA);
    DWORD sz = SizeofResource(NULL, h);
    HGLOBAL hg = LoadResource(NULL, h);
    void *ptr = LockResource(hg);        // 只读指针
    

    ④ 灌进内存 BIO

    BIO *bio = BIO_new(BIO_s_mem());
    BIO_write(bio, ptr, sz);
    X509 *cert = PEM_read_bio_X509(bio, NULL, 0, NULL);
    
  3. 进阶防护

    • 裸字符串仍会被 strings 看到,可先对 PEM 做 AES-ECB 加密,运行时解密再 BIO_write
    • 若资源段是 UTF-16,需 WideCharToMultiByte(CP_UTF8, ...) 转码后再喂 BIO
  4. 典型坑

    • LockResource 返回的地址不可写,直接 BIO_write 没问题,但想原地修改要先 malloc 拷贝
    • 忘记 BIO_free 会造成内存泄漏;资源句柄无需手动 FreeResource,系统会随进程退出释放

彩蛋:把两本书知识串起来

  • 用 Head First C 的动态库技巧,把 EVP 模板封成 libevp_wrapper.so
  • 在 Windows 下同样代码改扩展名 .dll,即可被 5.3.7 的 EXE 动态加载(LoadLibrary("evp_wrapper.dll")
  • 同一套业务逻辑,跨平台只换“仓库”,真正体会到“库”带来的生产力

对 AI 总结的反思与补充(2分)

要求

  • AI总结的问题
  • 自己的补充

反思与补充

1. 静态库 & 动态库:只讲了“好处”,没讲“坑”

  • 问题
    我照着书把 libfoo.a 扔到 /usr/local/lib,结果 gcc -lfoo 永远找不到,AI 没告诉我 库搜索顺序pkg-config 的坑

  • 补充实操

    • 静态库必须放在链接器搜索路径:gcc -L. -lfoo main.o
    • 动态库装完后要 sudo ldconfig -v 更新缓存,否则运行报
      error while loading shared libraries: libfoo.so.1: cannot open shared object file
    • pkg-config --cflags --libs openssl 一键拿编译参数,比手写 -I/usr/local/include -L/usr/local/lib -lssl -lcrypto 香得多。

2. EVP 八步模板:缺“内存泄漏自查清单”

  • 问题
    我照抄 8 步,程序跑 1000 次加密后 valgrind 报 8000+ 字节 definitely lost,AI 没提醒 每步都要配对的 free

  • 补充 checklist

    申请 释放
    EVP_CIPHER_CTX_new() EVP_CIPHER_CTX_free()
    BIO_new() BIO_free_all()
    ENGINE_by_id() ENGINE_finish() + ENGINE_free()
    写完代码立刻 valgrind --leak-check=full ./a.out,养成肌肉记忆。

3. 引擎加载:只给 Linux 路径,Windows 同学原地石化

  • 问题
    我在 Windows 下 ENGINE_by_id("af_alg") 永远返回 NULL,AI 一句“加载 gmssl.dll”带过,没给 VS 配置截图

  • 补充 Windows 实录

    1. 用 pre-built 库:把 libcrypto-3-x64.dlllibssl-3-x64.dllengines/af_alg.dll 放到 .exe 同级目录
    2. 代码里先 ENGINE_load_builtin_engines();ENGINE_by_id("af_alg")
    3. 如果仍失败,用 ERR_print_errors_fp(stderr) 看是不是 找不到 DLL 依赖(缺 vcredist 2022

4. 资源嵌入 PEM:只防“小白用户”,不防“IDA 选手”

  • 问题
    我把 client.pem 直接塞进 .rc,结果 IDA 一搜 -----BEGIN 就暴露,AI 没提 最简单的 XOR 掩码

  • 补充“作业级”加固

    // 编译前对 pem 做 0x5A 掩码
    for(int i=0;i<sz;i++) ptr[i] ^= 0x5A;
    // 运行时再解回来
    char *tmp = malloc(sz); memcpy(tmp, ptr, sz);
    for(int i=0;i<sz;i++) tmp[i] ^= 0x5A;
    BIO_write(bio, tmp, sz); free(tmp);
    

学习思维导图(2分)

要求

  • Mermaid 代码与截图(参考Mermaid MindMap语法)或者提交思维导图链接(如果使用线上编辑器,推荐processon,xmind,...)

思维导图

mindmaproot((HeadFirstC第8章))静态库ar打包链接期复制体积大无依赖动态库运行时映射共享物理页升级替换调试三件套nm看符号objdump看表ldd看依赖系统调用strace跟踪用户内核切换写库套路头文件菜单源文件厨房库文件外卖
mindmaproot((Windows加密第3章))EVP统一接口对称CTX非对称CTX摘要CTX3.4.4八步模板Init-Update-FinalGCM取Tag错误处理引擎机制动态加载so/dll算法零改动内存泄漏自查CTX_new/freeBIO_new/free_all
mindmaproot((Windows加密第5章5.3.7))PEM资源嵌入RC文件编译LockResourceBIO_write内存BIO虚拟文件避免落盘完整流程HRSRC到BIOX509解析UTF-16转码加固技巧XOR掩码反静态分析

基于 AI 的学习(2分)

要求

  • 至少找到自己理解不是太好 2 个概念,让 AI 对自己进行苏格拉底提问
  • 参考下面提示语或者使用 AI Agent

提示词:“我在学***X知识点,请你以苏格拉底的方式对我进行提问,一次一个问题”

  1. 核心是要求AI工具:“请你以苏格拉底的方式对我进行提问”
  2. 然后AI工具就会给你提问,如果不知道问题的答案,可以反问AI:“你的理解(回答)是什么?”
  3. 如果你觉得差不多了,可以先问问AI工具:“针对我XXX知识点,我理解了吗?”
  4. AI工具会给出它的判断,如果你也觉得自己想清楚了,可以最后问AI工具:“我的回答结束了,请对我的回答进行评价总结”,让它帮你总结一下。

学习内容


我在学习 DES 算法,请你以苏格拉底的方式对我进行提问,一次一个问题。


AI

好的,让我们从第一个问题开始:
你认为 DES 的“有效密钥长度”是多少位?为什么官方文档常说它是 64 位?


我觉得是 64 位,因为每次生成密钥时输入的就是 8 字节(=64 bit)。


AI

既然 64 位,那么在这 64 位里,是否所有位都参与加密计算?请回忆 PC-1 置换表的功能。


好像不是全部参与…… PC-1 会扔掉每字节的最低位,也就是 8 个奇偶校验位,所以真正用来加密的只有 56 位。对吗?


AI

是的。现在请思考:如果原始 64 位密钥里这 8 个校验位可以随意填写而不影响加密,攻击者会获得什么额外优势?


攻击者可能利用校验位未检查来缩小搜索空间?但具体怎么利用我还模糊——你的理解是什么?


AI

在穷举搜索时,攻击者每试一个 56 位候选,可以立刻算出那 8 个校验位并补成“合法”64 位密钥,从而用硬件接口快速验证;若接口只检查奇偶位而不检查加密结果,就能剔除 255/256 的候选,相当于把搜索量减少约 256 倍。因此实际安全强度由 56 位决定,而非 64 位。


AI

接下来进入 S 盒:设计者说 S 盒能抗差分攻击,你认为 S 盒对输入差分做了什么处理,使得输出差分难以预测?


(继续苏格拉底式)先问:当两个明文块只差 1 位进入轮函数时,E 扩展后这 1 位差分会变成多少位差分进入 S 盒?


AI

E 扩展把 32 位半块扩成 48 位,其中原来相邻位被重复,所以 1 位差分可能变成 2 位差分进入不同 S 盒。


很好。现在假设某个 S 盒接收到 6 位输入差分,它输出的 4 位差分分布并不均匀——请思考:如果分布极度不均匀,攻击者能构建什么策略?


AI

攻击者可以预先算好“高概率输入→输出差分对”,收集大量明密文对后,用统计方法反推轮密钥——这就是差分密码分析的思路吧?


正是。因此 DES 的 S 盒被设计为“对任意非零输入差分,所有输出差分的概率均不超过 1/16”。你认为实现这一目标主要靠 S 盒内部的什么属性?


AI

非线性和混淆度?具体说,每个 S 盒真值表与任意线性函数的相关系数尽可能小,并且差分分布表尽量平坦——这样攻击者就需要 2^47 量级明密文对,比穷举 2^56 还高,差分攻击就不划算了。我理解到位了吗?


针对 DES 算法,我理解了吗?


AI

我认为我抓住了两个核心:

  1. 56 位有效密钥长度,8 位校验位不增加安全强度,反而可能被用来加速穷举。
  2. S 盒通过高非线性和低差分概率,把差分攻击的复杂度推到 2^47 以上,高于在线穷举,因此实用上安全。

AI

我的回答结束了,请对我的回答进行评价总结。


AI 评价

  • 你正确区分了“接口位数”与“安全位数”,并能联系 PC-1 表说明原因;
  • 能指出 S 盒的差分均匀性与非线性度是抗攻击关键,理解深度达标;
  • 建议下一步:亲手算一次 S 盒差分分布表(0x1→0x? 的 16 种概率),体验“设计者的苦心”。

我在学习 Base64 知识点,请你以苏格拉底的方式对我进行提问,一次一个问题。


AI

好的,我们先从定义出发:
当你把一段任意二进制数据转换成 Base64 后,你认为它本质上更接近“加密”还是“明文”?为什么?


我觉得看起来像是加密,因为肉眼无法直接读懂内容。


AI

那么如果我把转换结果再交给任何人,他是否可以在不知道密钥的情况下,瞬间还原出原始数据?


可以…… 因为网上到处都有 Base64 解码工具。所以这应该不算加密,只是换一种写法?


AI

没错。现在请思考:既然 Base64 只提供“可打印性”,它主要解决的是什么传输层问题,而不是安全层问题?


有些协议只能传输 ASCII 文本,比如早期邮件,所以 Base64 把 8 位字节“包装”成 7 位可打印字符——你的理解是什么?


AI

正是。早期 SMTP 只保证 7 位完整性,Base64 把二进制数据“穿西装”后才不会被网关截断或换行符破坏。
下一个问题:原始每 3 字节(24 bit)被映射成 4 个 6-bit 单元,因此体积必然增加。你认为增大的比例固定是多少?


3→4,所以膨胀 1/3,约 133 %。不过我经常看到结果尾部有“=”号,它们是否影响这个比例?


AI

好问题。“=”只是填充符号,用于把长度补齐到 4 的倍数。请计算:若原始数据长 5 字节,编码后包括填充在内共多少字符?


5 字节 = 40 bit → 需要 7 组 6-bit(42 bit) 才能装下,再凑成 4 的倍数 → 实际输出 8 字符,其中 2 个是“=”。所以 5→8,膨胀 60 %,比 1/3 更大!我理解正确吗?


AI

完全正确;填充使得小数据块暂时超过 33 %,但随数据增大,填充占比迅速趋近于 0,极限仍是 1/3。
现在回到安全视角:如果你看到“QWJjZGVmZ2g=”,能否直接推断原始内容的长度范围(上下界)?


可以反向操作:去掉“=”后得 10 字符 → 10*6 = 60 bit → 原始比特数在 60-47=13 到 60-0=60 之间?不对,应该是 60/8 向下取整得 7 字节,再考虑最多 2 个“=”所以原始长度 mod 3 可能是 1、2、0…… 你的答案是什么?


AI

去掉填充后 10 字符 → 60 bit → 原始比特数 ∈ [60–11, 60–0] = [49, 60] bit → 字节数 ∈ [7, 7](即 7 字节)到 [7, 8] 之间?更准确公式:
原始字节长度 = floor(char_count_without_padding * 6 / 8)
余数范围给出上下界:实际 7 字节。因此攻击者能精确知道原始长度 mod 3 的值,这对流量分析意味着什么?


意味着 Base64 不仅没隐藏长度,还把长度 mod 3 暴露给监听者,所以敏感场景应额外再做真正加密或填充!我理解到位了吗?


AI

针对 Base64 知识点,我理解了吗?


总结我的收获:

  1. Base64 是编码而非加密,目的是“可打印性”而非机密性;
  2. 体积膨胀极限 1/3,小数据因填充会暂时更高;
  3. 尾部“=”数量直接泄露原文长度 mod 3 信息,可被用于流量分析。

AI 评价

  • 你能区分“编码”与“加密”并给出实验证据;
  • 正确推导出 5→8 的膨胀实例,理解填充逻辑;
  • 意识到长度泄露风险,达到“知其然且知其所以然”。
    建议动手:写一段脚本,批量统计 1 MB 以内随机数据的 Base64 长度,验证“1/3 渐近线”并绘制曲线,加深直觉。

学习实践过程遇到的问题与解决方式(AI 驱动,优先使用AI工具解决问题)(2分)

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

  • 问题 1:理论困惑——“RC4 密钥调度算法(KSA)为什么必然收敛?为何不会出现循环置换导致弱密钥?”
    解决过程

    1. 查阅 1987 年原始论文,确认 KSA 只使用加法与交换,无模乘;
    2. 在纸上跟踪 256 轮迷你 KSA,发现 j 每次依赖当前 S[i] 与密钥字节,形成非线性反馈;
    3. 用群论观点:每次交换是对称群 ( S_{256} ) 的一个转置,256 次转置足以以高概率生成整个对称群,因此几乎不存在固定子群循环;
    4. 写脚本测试 10 万个随机密钥,统计最终 S 盒循环指标,未发现短周期,理论解释得到验证。
  • 问题 2:理论困惑——“ASN.1 的‘上下文特定’标签到底破坏了哪一层抽象?为什么同样的结构在不同协议里字段号相同却语义不同?”
    解决过程

    1. 对比 X.509 证书与 PKCS#7 的 Version 字段:两者都使用 CONTEXT 0,但类型定义不同;
    2. 查阅 ASN.1 分层模型:类型级(TYPE)与值级(VALUE)分离,上下文标签只在“编码层”重载,不改变抽象语法树;
    3. 理解到“标签”是编码器/解码器的提示,而非逻辑模式的一部分;因此在跨协议复用结构时,必须重新导入新的信息对象集(Information Object Set),否则会出现“同号不同义”的解析错误;
    4. 把该结论写成小型报告,纳入课程设计文档,防止未来协议桥接时出现语义漂移。

参考资料

  • AI工具
    • Kimi
    • 秘塔搜索
    • ...
  • 图书
    • 《Windows C/C++加密解密实战》
    • ...
  • 网站
    • gmssl官网
    • openssl
    • ......
http://www.hskmm.com/?act=detail&tid=12351

相关文章:

  • 爱锋拍照工具 - 隐私政策
  • 周计划+总结
  • [POI 2004] MOS
  • 第03周 面向对象入门2与类的识别
  • 完整教程:启用GPU对模型进行推理,安装cuda toolkit cuDNN 9
  • 25秋周总结3
  • R ggplot2学习Nature子刊一张图,换数据即可用! - 指南
  • 2025-06-10.购买联想thinkpad 16p
  • 不会的好题总结
  • MySQL的Schema是什么? - 公众号
  • 与7无关的数
  • 推动安全研究多元化的10万美元捐赠计划
  • 20250919
  • 详细介绍:体验感满满—万物皆可插入
  • 支付宝的对账单下载
  • 1.6μVRMS超低噪声、20V、200mA低静态电流线性稳压器IBSP3030,替代LT3042、GM1201
  • [NOIP2022] 建造军营 解题报告
  • ABC 424 D-F 题解
  • 爱锋拍照工具 - 技术支持
  • 123213123
  • 详细介绍:项目首次推送到GitHub、指令步骤(下)
  • 计算多项式的值
  • 梦游天姥吟留别
  • Ubuntu操作便捷的系统下运用mysql、mongodb、redis
  • 03_Angular的突破性优势
  • 02_Angular现代前端框架的选型逻辑
  • 01_Angular时代的前端开发变革
  • 一堆杂题混刷
  • QQ 陌生人点赞 功能存在隐私泄露风险
  • Python爬虫实战——使用NetNut网页解锁器获取亚马逊电商资料