密码学入门:从对称加密到哈希,一文掌握核心概念
2026/9/7 1:42:28 网站建设 项目流程

简介:《密码学基础核心精讲》是一份以PDF形式整理的密码学理论经典资料,面向具备算法设计与分析基础、希望深入理解安全计算原理的研究生及专业人士。内容依托Oded Goldreich的权威著作,系统阐述密码学三大基石:计算困难性(单向函数)、伪随机性与零知识证明,并通过严格数学定义与构造实例,揭示加密、签名和安全协议背后的核心原理。资源共1个文件,整体压缩包4.85MB,便于下载后离线阅读。已有157人学习,适合用于研究生课程参考、自学提升及安全研发中的理论查证,能帮助读者建立从基础假设到复杂协议的系统认知。

1. 学密码学之前,先搞懂它在解决什么问题

每次有人问我“密码学是不是就是教你怎么设一个复杂密码”,我都想先纠正这个误区。密码学确实管密码,但它管的是更底层的东西——你手机里的聊天记录为什么只有你和对方能看,你在网上转账时怎么确认收到钱的是本人,甚至你下载的软件更新包有没有被人动过手脚,这些统统是密码学在背后撑着。现代密码学不是一群数学家关在实验室里的纸上谈兵,它早就渗透到了每一个网络协议、每一次身份认证、每一条加密消息里,没有密码学,整个互联网的安全地基就是空的。

想入门的同学,很容易一上来就被各种名词劝退:算法、密钥、分组模式、数字签名、哈希碰撞……但我的建议是,别急着背术语。先建立一个大框架:密码学这门学科,说到底只做四件事——机密性、完整性、认证性、不可否认性。你之后接触到的任何一个算法、任何一种协议,都能归到这四类里。把框架立住了,再往里填细节,会轻松非常多。

1.1 机密性、完整性、认证,一个都不能少

先说说机密性。这个最好理解,就是“除了接收方,谁都不能看懂消息内容”。经典的对称加密和非对称加密都是为了解决机密性,但机密性只是最基础的第一层。很多人以为加密了就万事大吉,完全不是这样。

举个例子,你和朋友约定把消息里的每个字母向后移三位,这是凯撒密码,能实现机密性。但如果一个中间人截获了密文,把密文改了一个字符再转发出去,接收方解密出来就是错误消息。更麻烦的是,接收方可能根本发现不了消息被篡改过——这就引出了第二个目标:完整性。完整性要保证的是“消息在传输过程中没有被改动”。注意,完整性和机密性是两码事,一个加密算法做得再好,也不代表它能防篡改。

第三个目标是认证性,也就是“你收到的消息确实来自声称的那个人”。加密只保证内容保密,不保证发送方身份。中间人可以扮演你的朋友发送一条加密消息,只要你不知道对方的密钥,你就无法判断真假。认证性通常靠消息认证码(MAC)或者数字签名来实现。

最后一个不可否认性,侧重于“做过的事甩不掉”。比如你在网上签了一份电子合同,事后不能反悔说“这不是我签的”。数字签名天然具备这种特性,因为私钥只有你自己有,签出来的东西就是你的凭证,这个逻辑稍后展开。

1.2 别急着选算法,先模拟威胁模型

很多初学者会纠结“到底选AES还是RSA”,但正确的姿势是先问自己:我要防谁?攻击者有多强?如果只是防止邻居偷看Wi-Fi,和防止国家级对手窃听,方案完全不可能是同一个级别。这个“先想清楚敌人是谁”的步骤,在专业领域叫威胁建模。

我见过不少团队,一上来就上了各种高大上的加密方案,结果发现性能撑不住,或者密钥管理混乱,最后还是退回明文。原因就出在没想清楚到底要保护什么。密码学永远是在安全、性能、便利性之间做权衡,没有一种算法是万能的。先明确边界,再选工具,这才是老手的做法。

2. 对称加密:速度快,但“送钥匙”是个难题

对称加密是整个密码学的基石。它的特点是加密和解密用同一把密钥,所以速度飞快,特别适合加密大块数据。你在浏览器里看到的HTTPS,握手之后传输数据用的就是对称加密。大家耳熟能详的AES(高级加密标准)就是典型代表,目前全球没有公开的攻击方法能真正威胁到它,工程师可以放心用。

但对称加密有个绕不开的问题:既然加解密用同一把密钥,那你得先把密钥安全地送到对方手里。如果密钥在传输过程中被人截获,后续的所有加密都是摆设。这个“怎么把密钥安全送出去”的问题,困扰了密码学界几十年,最终催生了非对称加密。不过在讲非对称之前,我们得先把对称加密本身的门道说清楚,因为里面的坑一点也不少。

2.1 AES常见分组模式,CBC和GCM到底怎么选

AES是分组加密算法,意思是它把数据切成固定长度的块,一块一块地加密(AES的块大小是128位,也就是16字节)。如果你要加密的数据长度不是16的倍数,就得用到填充。常见的填充方案是PKCS7,缺几个字节就补几个相同值,这个细节在跨语言加解密时一定要对齐,不然两边算出来的结果永远对不上。

块加密本身只能处理固定长度的数据,实际操作中我们还要定义“怎么把一个个块串起来”,这就牵扯出分组模式。最早期的是ECB模式,直接把每个块独立加密,逻辑最简单,但也最容易出事——因为相同的明文块会得到相同的密文块,数据规律一目了然,所以现在所有正规场景都不建议使用ECB。CBC模式引入了一个随机初始化向量(IV),让每个明文块先和上一个密文块异或再加密,相当于打破了块之间的对应关系,安全性能大幅提升,也是历史上用得最广的模式。

但CBC有个麻烦:它不能提供完整性保护。你改了密文,解密后明文也会变,但你不知道是不是被改过。所以实际使用中,CBC一般要搭配HMAC一起用,这就是“先加密再MAC”的经典组合。到了现代,业界更推荐直接用GCM模式。GCM是一种AEAD(认证加密)模式,一条龙解决了机密性、完整性和认证性,密钥和初始向量也相对容易管理。我自己现在写新项目,默认就选AES-GCM,既少犯错又省心。

再补一个容易踩的坑:GCM的IV到底要随机还是唯一?答案是“必须唯一”。GCM安全性的前提是同一个密钥下IV绝不能复用,否则一旦复用,密文和认证标签都可能直接泄露。实际开发中我的习惯是用随机数,如果系统并发量大,就用计数器严格保证单调递增,反正就是不能偷懒。

2.2 一个真实例子:AES-GCM加密的极简代码

动手看代码最能理解。下面用Python配合pycryptodome库,演示一段AES-GCM加密解密流程。注意看IV的生成方式和tag的处理。

from Crypto.Cipher import AES from Crypto.Random import get_random_bytes # 生成随机的256位密钥(32字节) key = get_random_bytes(32) # AES-256 # 随机生成12字节的IV,GCM推荐12字节 iv = get_random_bytes(12) # 创建加密器 cipher = AES.new(key, AES.MODE_GCM, nonce=iv) plaintext = b"hello, crypto world" ciphertext, tag = cipher.encrypt_and_digest(plaintext) print("IV:", iv.hex()) print("密文:", ciphertext.hex()) print("认证标签:", tag.hex()) # 解密时,IV、密文、tag需要一起传输给接收方 decipher = AES.new(key, AES.MODE_GCM, nonce=iv) data = decipher.decrypt_and_verify(ciphertext, tag) print("解密结果:", data.decode())

这里面有个哲学:传输时IV、密文和tag是一并发送的,但IV在实际应用里并不算机密信息。既然不机密,为什么还要防止复用它?因为“唯一性”和“机密性”是两个不同的要求。IV就算公开,只要你保证同一个密钥下不重复使用,安全性就能维持住。这一点经常被误解,值得单独拎出来说。

3. 非对称加密:用数学解决“送钥匙”难题

非对称加密(也叫公钥密码)彻底改变了密码学的走向。它的思路是:生成一对密钥,一个是公钥,随便发给谁都可以;一个是私钥,必须自己藏好。公钥加密的消息只能用对应的私钥解密。这样一来,别人想给你发密文,直接用你的公钥加密就行,你不必再费尽心思把密钥“偷渡”给对方。

现代密码学里,非对称加密的另一大用途是数字签名,但方向是反过来的:私钥签名,公钥验签。这就同时解决了认证性和不可否认性。所以说到非对称算法,我们其实在讨论两类事:加密解密,以及签名验签。

3.1 RSA的原理与工程参数,别再用1024位了

RSA是目前知名度最高的公钥密码算法,它的核心思路建立在“大整数分解很难”这个数学假设上。简单说,生成两个大质数p和q,把它们相乘得到n,然后别人拿着n却很难反推出p和q。公钥公开的就是n,私钥则隐藏了p、q的信息。只要因子分解问题没有被突破,RSA就是安全的。

刚入门的人最容易犯的错,是生成了强度不够的密钥。RSA-512早就被业界宣告“可破解”,1024位在现实里也不推荐使用。现在的共识是至少要2048位,我更倾向直接上3072位或者4096位。不过要注意,RSA密钥越长,加解密越慢,而且因为要生成大素数,临时生成密钥会比较耗时。如果你只是自己测试,跑一次生成等个一两秒很正常。

实操中,用OpenSSL生成RSA密钥的常用命令是:

# 生成3072位RSA私钥 openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out rsa_private.pem # 从私钥导出公钥 openssl pkey -in rsa_private.pem -pubout -out rsa_public.pem

生成的PEM文件默认就是PKCS#8格式,跨平台兼容性很好。另外一个工程细节:RSA公钥指数(e)一般取65537,这个词你会在很多代码里看到。为什么选它?因为65537的二进制是100000000000000001,里面只有两个1,做模幂运算时能大幅减少计算量,同时又能保证足够的攻击门槛。这种“看着奇怪其实都是数学优化”的例子,在密码学里到处都是。

3.2 ECC:用更短的密钥达到更高安全性

这些年ECC(椭圆曲线密码)逐渐成为主流,IoT、区块链、移动端到处都在用。ECC的安全性建立在椭圆曲线离散对数问题的困难性上,一句话解释就是:知道点P和倍数k,算kP很容易,但知道P和kP反过来求k非常难。

ECC的优势在于密钥长度短。业界一个常用对比是:RSA-3072和ECC-256的安全强度大致相当,但前者需要3072位,后者只需要256位。这带来的直接影响是计算负载更低、传输数据更小,特别适合资源受限的场景。日常开发中最常见的ECC曲线是prime256v1,也叫P-256,另外Curve25519也因设计上的抗侧信道特性变得越来越流行。

ECC的问题在于标准比RSA复杂,参数和曲线的选择都可能埋坑。如果自己写底层实现,稍有不慎就会翻车。我的建议是:能用现成库里封装好的高级API,就别自己拼原始运算。做技术的都容易高估自己的实现能力,但在密码学这个领域,老老实实站在前人肩膀上才是正路。

4. 哈希函数:不是加密,却比加密更常用

接下来聊哈希函数,这是另一个高频话题。很多新人会把“加密”和“哈希”混为一谈,虽然它们都是把数据变成不可读的“乱码”,但差别非常大:加密是对称可逆的,密文用密钥可以解回明文;哈希是单向的,一旦算出来就没人能倒推出原始输入。所以哈希不是加密,它提供的服务是“指纹”。

哈希函数是现代密码学里最趁手的工具。它用来验证数据完整性、构造数字签名、管理口令、做文件校验,甚至区块链里每个区块的链接都靠它。理解哈希的三大特性非常关键:一是确定性,同样输入永远得到同样输出;二是单向性,从输入算输出容易,从输出反推输入在计算上不可行;三是抗碰撞性,很难找到两个不同输入得到同一个哈希值。只要你打算用哈希,这三个性质就是一切的出发点。

4.1 从MD5到SHA-256:为什么越新的哈希越安全

刚入行时我用过一阵子MD5做文件校验,后来才知道它早就被打出“碰撞”了——早在2004年,学术界就公开了MD5碰撞的可行性,现在构造两个哈希值相同的不同文件,普通电脑都能轻松做到。你如果还在签名或完整性校验的场景里见到MD5,脑子里就要立刻拉响警报。SHA-1同理,也在2017年被Google成功构造出碰撞,属于被淘汰的选手。

现在的底线是SHA-256。它属于SHA-2家族,运算结果256位,目前没有公开有效的碰撞方法。如果是安全性要求更高的场景,还可以考虑SHA-3,它对底层结构和SHA-2完全不同,属于“万一SHA-2出现问题时”的后备力量。我自己的习惯是:新项目一律SHA-256起步,只有兼容老系统时才会向下兼容部分旧算法,但一定会做好紧急切换的准备。

4.2 密码存储别用裸哈希,加盐和慢哈希才是正解

聊到用户密码存储,这是个雷区。很多系统早期直接把用户密码做一次SHA-256就存进数据库,只要数据库泄露,黑客就能拿常见密码的哈希值一个个比对,这种攻击叫脱库后的离线撞库,纯粹靠预计算就能打穿。正确做法至少要做两件事:加盐和慢哈希。

所谓加盐,就是给每个用户的密码拼上一段随机字符串再算哈希。每个人的盐都不同,相当于把“同一密码的哈希必然一样”这个规律打破,黑客没法用一张预计算表批量破解。所谓慢哈希,是刻意让哈希过程变慢,比如花费几百毫秒甚至更久才算出结果,这样黑客即使拿到库,也破解不了几个。推荐用的算法有bcrypt、scrypt和Argon2。下面是一个用PBKDF2实现的示意,关键是它支持自定义迭代次数:

import hashlib import secrets password = b"user_passwd" salt = secrets.token_bytes(16) # 每个用户随机生成 # 建议迭代次数至少60万+,按环境调优 dk = hashlib.pbkdf2_hmac("sha256", password, salt, 600000, dklen=32) print("salt:", salt.hex()) print("派生密钥:", dk.hex())

这里面的核心是“时间即成本”。攻击者破解一个密码的时间是用户的几千倍甚至更多时,这个系统就是相对稳妥的。别心疼那几百毫秒的登录延迟,这点开销换取的口令安全非常划算。我在实际项目里,会把盐和派生密钥一起存进数据库,一个字段存盐、一个字段存结果,登录时取出盐重新计算再比对,流程简单又有效。

5. 避坑指南:密码学落地时的常见问题

理论讲完,落到工程上,坑其实比想象中多。很多人以为只要用了AES、用了RSA,数据就固若金汤了,但密码学最大的弱点往往不是算法本身,而是实现方式和使用逻辑。我整理几个最常见的坑,都是平时做项目真真切切遇到过的问题。

5.1 算法安全不等于实现安全

第一类坑常见于“算法选对了,用错了场景”。比如ECB模式的电子密码本问题,密文会保留明文的格式规律,加密一张图片后肉眼都能看出轮廓,这就是为什么ECB被普遍否定。又如CBC模式如果IV固定不变,同样明文会生成同样密文,攻击者能借此推断消息重复性,IV必须随机生成且每次不同。再如GCM模式下IV重用,前面提过,一旦撞上,认证密钥都可能被泄露。

再有就是编码问题。加解密里最常见的就是base64、hex、UTF-8之间来回转换没对齐,导致密文标签对不上。出现这类问题时先别怀疑算法,先检查一下两端各自用的编码和填充,八成能解决。别问我怎么知道的,我在联调时被这种问题折磨过不止一次。

5.2 密钥管理:密码学的“最后一公里”

算法再强,密钥一旦泄露,一切都归零。密钥管理听起来是个运维活,却是整个密码体系中真正的命门。最常见的问题是开发人员把密钥写死在代码里,甚至提交到代码仓库,这是最要命的。密钥出现过的任何地方,都应该视为泄露,必须轮换,不能心存侥幸。

生产环境里,密钥应该交给专门的密钥管理系统,比如云厂商的KMS或者自建的Vault。用KMS最大的好处是密钥以密文形式存储在HSM中,应用侧只调用解密接口,根本没有机会直接接触明文密钥。如果项目实在很小,至少也要把密钥放到环境变量里,配合严格的权限管理,显著降低泄露面。

另外一个经常被忽略的点是密钥轮换。同一把密钥用太长时间,积累的密文样本越多,风险越高;更关键的是万一某一把密钥泄露,影响范围会扩大到所有历史数据。我的习惯是:核心服务至少每年轮换一次密钥,迁移数据时提前用新密钥重加密。写入不可变日志或备份文件里的历史密钥,也要单独列一张表,方便审计和追溯。

最后再分享一个小技巧:无论你做的是加密、签名还是哈希验证,一定要把完整的加解密流程写成自动化测试,把向量、填充、标签、异常分支、篡改场景全部覆盖住。密码学的理论可以慢慢啃,但工程的底线得靠这些测试兜住。真等到线上数据出问题再排查,就真的晚了。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询