一、密码学基础:对称加密与非对称加密概述、哈希函数、C语言中的大数运算库简介
各位同学,欢迎来到《C语言加密解密与安全编程实战》的第一章。我是你们这门课的老朋友,一个在安全领域摸爬滚打多年的工程师。今天咱们不聊虚的,直接切入正题——密码学基础。
很多人一听到「密码学」三个字就头大,觉得那是数学家干的事。其实不然。你想想看,我们每天都在用密码学:微信聊天、网上银行、甚至你登录这台电脑的密码验证,背后都离不开它。作为C语言开发者,我们不仅要会用,还得知道它为什么安全、又可能在哪儿翻车。
核心观点:密码学的本质,是在不安全的信道上实现安全通信。说白了,就是让该看的人看懂,不该看的人看不懂。
1.1 对称加密:一把钥匙开一把锁
对称加密,顾名思义,加密和解密用的是同一把密钥。就像你家的门锁,用同一把钥匙锁门和开门。
常见的对称加密算法有:AES、DES、3DES、SM4(国密标准)。其中AES是目前应用最广泛的,我个人习惯在项目里优先选用AES-256。
对称加密的工作流程:
- 发送方用密钥K对明文P加密,得到密文C
- 密文C通过网络传输给接收方
- 接收方用同样的密钥K对密文C解密,还原出明文P
我的经验:我在项目中遇到过一个问题——密钥怎么安全地传给对方?如果网络本身不安全,你传密钥的过程就可能被截获。这就是对称加密最大的痛点:密钥分发问题。后来我改用非对称加密来传对称密钥,才彻底解决。
对称加密的优缺点:
| 优点 | 缺点 |
|---|---|
| 加解密速度快,适合大数据量 | 密钥分发困难,需要安全通道 |
| 算法成熟,硬件支持好 | 密钥数量爆炸(n个人需要n(n-1)/2个密钥) |
| 实现相对简单 | 无法提供数字签名功能 |
1.2 非对称加密:公钥私钥,各司其职
非对称加密的出现,解决了对称加密的密钥分发难题。它使用一对密钥:公钥(公开)和私钥(保密)。公钥加密的数据只能用私钥解密,私钥加密的数据只能用公钥解密。
常见的非对称加密算法:RSA、ECC(椭圆曲线)、SM2(国密)。RSA是最经典的,但ECC在同等安全强度下密钥更短、性能更好。
非对称加密的核心流程:
- 接收方生成密钥对(公钥PK,私钥SK),把公钥公开
- 发送方用公钥PK加密明文P,得到密文C
- 接收方用私钥SK解密密文C,还原出明文P
避坑指南:我曾经犯过一个低级错误——直接用RSA加密大文件。结果呢?RSA有长度限制,1024位密钥最多只能加密117字节。超过这个长度,要么报错,要么数据被截断。正确的做法是:用非对称加密传对称密钥,用对称密钥加密实际数据。这叫「混合加密」,HTTPS就是这么干的。
1.3 哈希函数:数据的「指纹」
哈希函数,也叫散列函数。它能把任意长度的输入,变成固定长度的输出(哈希值)。而且这个输出是不可逆的——你没法从哈希值反推出原始数据。
常见的哈希算法:MD5(已不安全)、SHA-1(已不安全)、SHA-256、SHA-3、SM3(国密)。
哈希函数的三大特性:
- 抗原像性:给定哈希值H,找不到任何消息M使得Hash(M)=H
- 抗第二原像性:给定消息M1,找不到另一个消息M2使得Hash(M1)=Hash(M2)
- 抗碰撞性:找不到任意两个不同的消息M1和M2使得Hash(M1)=Hash(M2)
实际应用场景:
- 密码存储:不存明文密码,只存哈希值。即使用户数据库泄露,攻击者也拿不到原始密码。
- 文件完整性校验:下载文件后比对哈希值,看文件是否被篡改。
- 数字签名:先对消息哈希,再对哈希值签名,效率更高。
嗯,这里要注意一点:哈希不是加密。加密是可逆的,哈希是不可逆的。千万别搞混了。
1.4 C语言中的大数运算库简介
密码学离不开大数运算。RSA的密钥动辄2048位,ECC的曲线参数也是几百位的大整数。C语言自带的int、long根本装不下。怎么办?得用大数运算库。
主流的大数运算库:
| 库名 | 特点 | 适用场景 |
|---|---|---|
| OpenSSL (BN) | 功能最全,性能好,跨平台 | 生产环境,商业项目 |
| GMP | 性能极致,但API较底层 | 科研计算,高性能需求 |
| libtommath | 轻量级,代码清晰,适合学习 | 嵌入式系统,教学演示 |
| Miracl | 专为密码学设计,支持椭圆曲线 | 密码学算法实现 |
我个人习惯用OpenSSL的BN库。它封装得比较好,加减乘除、模幂、求逆这些操作都有现成函数。而且OpenSSL几乎成了Linux系统的标配,省去了额外安装的麻烦。
一个简单的BN使用示例:
#include <openssl/bn.h>
#include <stdio.h>
int main() {
BIGNUM *a, *b, *c;
BN_CTX *ctx;
// 初始化
ctx = BN_CTX_new();
a = BN_new();
b = BN_new();
c = BN_new();
// 赋值:a = 12345678901234567890
BN_dec2bn(&a, "12345678901234567890");
// 赋值:b = 98765432109876543210
BN_dec2bn(&b, "98765432109876543210");
// 计算 c = a + b
BN_add(c, a, b);
// 打印结果
char *result = BN_bn2dec(c);
printf("a + b = %s\n", result);
OPENSSL_free(result);
// 清理
BN_free(a);
BN_free(b);
BN_free(c);
BN_CTX_free(ctx);
return 0;
}
编译提示:编译时记得链接OpenSSL库:gcc -o test test.c -lssl -lcrypto
你可能会问:为什么需要BN_CTX?说白了,大数运算过程中会产生很多临时变量,BN_CTX就是用来管理这些临时变量的内存池,避免频繁申请释放内存,提高性能。
本章知识体系总览
下面这张图,把本章的核心知识点串起来了。你可以把它当作一张「密码学基础地图」,以后学新内容时随时回来对照。
好了,第一章的内容就到这里。对称加密、非对称加密、哈希函数、大数运算库——这四个概念是后面所有章节的基石。你可能会觉得哈希函数有点抽象,没关系,后面讲到数字签名和证书时,你会看到它到底有多重要。
记住一句话:密码学不是魔法,它只是把数学问题变成了工程问题。而我们要做的,就是用好C语言这把手术刀,把这些数学原理变成可靠的代码。