在写第一行加密代码之前,先想清楚一件事:我们到底在对抗谁,又想保护什么。
密码学不是"把字变乱"的技巧,而是一门关于在不可信环境里建立信任的科学。你的 App 每次连上服务器,数据都要穿过一堆你无法控制的路由器、Wi-Fi 热点和运营商网关。密码学的任务,就是让这段旅程即使在敌人眼皮底下也依然安全。
作为 Android 开发者,你其实每天都在用密码学:HTTPS、EncryptedSharedPreferences、APK 签名、支付 SDK、生物识别……只不过大多数时候它们藏在库背后。这本书的目标,是让这些"黑箱"变成你能看穿、能判断、必要时能亲手拆开的东西。
初学者常把"密码学"等同于"加密",但加密只是其中一个目标。现代密码学要同时回答四个独立的问题:
| 目标 | 回答的问题 | 典型手段 | 生活类比 |
|---|---|---|---|
| 机密性 Confidentiality | 除了收件人,别人能读到内容吗? | 加密(AES、ChaCha20) | 装进上锁的信封 |
| 完整性 Integrity | 内容在途中被改过吗? | 哈希、MAC | 火漆封印,一撕就露 |
| 认证 Authentication | 对方真的是他声称的那个人吗? | MAC、数字签名、证书 | 核对笔迹与印章 |
| 不可否认 Non-repudiation | 他事后能抵赖"这不是我发的"吗? | 数字签名 | 签了字画了押 |
这四点是正交的——满足一个不代表满足另一个。一个经典的血泪教训:很多人以为"加密了就安全了",结果攻击者虽然读不懂密文,却能翻转密文里的某些位,让解密后的明文发生可预测的变化(比如把转账金额 0001 改成 9999)。加密保护了机密性,却没保护完整性。第 9 章的 AEAD 就是为了同时解决这两件事而生的。
明文(plaintext)是你想保护的原始信息;密文(ciphertext)是加密后的乱码;密钥(key)是控制加密/解密的秘密参数。加密是一个函数 C = E(K, P),解密是它的逆 P = D(K, C)。整本书都在讨论:这个 E 怎么设计,才能让不知道 K 的人从 C 里得不到关于 P 的任何有用信息。
1883 年,荷兰语言学家 Auguste Kerckhoffs 提出了一条至今仍是密码学地基的原则:
一个密码系统应当即使其一切细节都被敌人知晓,只要密钥不泄露,就依然安全。
换句话说:安全性必须只依赖密钥,而不能依赖"算法保密"。这条原则的现代口号叫 "No security through obscurity"(隐藏不等于安全)。为什么这么重要?
永远不要自研加密算法,也不要依赖"把密钥藏得更深"来保证安全。用标准算法(AES-GCM、Ed25519……)、用平台密钥库(Android Keystore),把秘密收敛到一把真正随机、真正受硬件保护的密钥上。你的对手会拿到你的 APK 和全部源码——就当他们已经拿到了。
密码学有个可爱的传统:给角色起名字。发消息的叫 Alice,收消息的叫 Bob,而想搞破坏的坏人有两种性格:
密码学家评估一个算法时,会假设攻击者拥有相当强的能力,再看算法在这种"最坏情况"下是否还成立。几种由弱到强的标准模型:
| 模型 | 攻击者能做什么 |
|---|---|
| 唯密文攻击 (COA) | 只能看到密文 |
| 已知明文攻击 (KPA) | 能看到若干"明文—密文"对 |
| 选择明文攻击 (CPA) | 能让系统加密任意他挑选的明文(像有个"加密预言机") |
| 选择密文攻击 (CCA) | 还能让系统解密某些他挑选的密文,观察结果或报错 |
这看起来像是"给攻击者开挂",但正是这种偏执让现代密码算法如此结实。一个现代加密方案的合格标准是 IND-CPA / IND-CCA 安全:哪怕攻击者能任意加密、能看到大量密文,他也无法区分两条等长明文中到底加密了哪一条——密文看上去必须和随机噪声毫无二致。你会在第 5 章第一次严格地遇到这个思想。
密码学里的 oracle(预言机)指一个你可以查询、会给你答案、但你看不到内部的黑盒。这个词后来在第 8 章的 "padding oracle" 攻击里会以非常危险的面貌回归——一个仅仅告诉你"填充对不对"的服务器,就足以让攻击者逐字节解出整段密文。信息以各种意想不到的方式泄露,是密码学工程里永恒的主题。
在钻进细节之前,先把地图钉在墙上。密码学的工具大致分四类,本书的七个阶段正好覆盖它们:
加密和解密用同一把密钥。速度快、适合加密大量数据。问题只有一个,但很致命:Alice 和 Bob 得先共享那把密钥——可他们隔着不可信的网络,怎么把密钥安全送过去?这个"先有鸡还是先有蛋"的困境,直接催生了下一类。
每个人有一对钥匙:公钥可以公开(用来加密、验签),私钥自己藏好(用来解密、签名)。这解决了密钥分发难题,也带来了数字签名。代价是慢得多,所以现实中通常"用公钥协商出一把对称密钥,再用对称密码加密正文"——这正是 TLS 的核心套路(第 19 章)。
哈希函数把任意数据压成固定长度的"指纹",用于完整性校验、密码存储、区块链。它不是加密(没有密钥、不可逆)。加上密钥就成了 MAC,能同时保证完整性与认证。
把上面的积木拼成真正有用的系统:TLS 保护你的 HTTPS,Signal 协议保护你的聊天,区块链用哈希与签名构建"无需信任"的账本,而后量子密码则在为"量子计算机破解现有公钥"的那一天做准备。
留意"组合"这个动作。真实系统几乎从不用单一算法,而是把对称、公钥、哈希拼在一起——每一次拼接都是新的出错机会。本书后半部分的很多"翻车现场",错的不是算法本身,而是算法之间的接缝。学会看接缝,你就从"会调库"迈向了"懂密码学"。
七个阶段是一条精心铺设的路:古典密码(建立"什么是破解"的直觉)→ 对称 → 哈希 → 公钥 → Android 工程实战 → Web3 → 前沿。强烈建议按顺序读,因为后面的章节不断回收前面的概念——比如哈希(第 10 章)是签名(第 18 章)的零件,签名又是 TLS(第 19 章)和区块链(第 23 章)的零件。
每一章都尽量配一个可以亲手玩的 Demo。密码学是少数几个"亲手把它打破一次,胜过读十遍定义"的领域。下一章我们就从最古老的密码开始,并且——立刻把它破解掉。