转自:
本文介绍目前现代密码学的最先进技术,
前半部分主要翻译自 《Cryptographic Right Answers》 https://gist.github.com/tqbf/be58d2d39690c3b366ad , 附上收集的资料, 和 byron 个人的理解.
密码学理论艰深, 概念繁多, 本人知识水平有限, 错误难免, 如果您发现错误, 请务必指出, 非常感谢!
下文分类介绍在各种适用场景下, 你应该使用的现代密码学算法
1. 加密数据 :
按照优先级, 应该选择:
(1) 首选 NaCl 库, 或者 libsodium 库, 使用里面的 crypto_secretbox()/crypto_secretbox_open() 函数
(2) Chacha20-Poly1305 算法
(3) AES-GCM 算法
适用场景: 当你需要避免把明文数据在网络上传输的时候.
以上 3 种算法, 都是 AEAD 类的算法, AEAD 是 2015 年最好的选择.
其中的 (2) 和(3)在结构上类似: 一个流加密模式的算法, 配合一个多项式结构的 Mac.
(2)是一个流加密算法, 配合一个为通用 CPU 优化的 Mac 算法,
对密码学库的实现者来说, Poly1305 也比 GCM 更容易安全地实现.
AES-GCM 是工业标准 (TLS 目前主要用的就是 AES-GCM), 现代 CPU 通常都有专门为 AES-GCM 设计的硬件指令, 但是在没有硬件指令支持的 CPU 上(比如 32 位的 ARM),(3) 性能低于(2).
此外, 应该
避免 AES-CBC(说来话长, 后文有解释)
避免 AES-CTR
避免 64bit 块大小的块加密算法 --(说的就是你 --BlowFish)
避免 OFB 模式
不要使用 RC4,RC4 已经被攻破
2. 对称密钥长度 :
选择使用 256bit 长度的密钥
适用场景: 只要你在使用密码学, 你就应该注意对称密钥长度
请记住: 不要把对称加密 (如 AES) 的 key 长度, 和非对称加密 (如 RSA) 的 key 长度搞混淆了, 对称加密的 key 通常比非对称加密的 key 短多了.
下表对比了相同安全程度时, 不同算法的密钥长度, 单位: bit
Symmetric | ECC | DH/DSA/RSA |
---|---|---|
80 | 163 | 1024 |
112 | 233 | 2048 |
128 | 283 | 3072 |
192 | 409 | 7680 |
256 | 571 | 15360 |
此外, 应该
避免使用巨大 key 的算法(使用远大于 256 的 key, 只能说明使用者没有安全概念)
避免把多个加密算法串联叠加起来使用, 这并没有什么卵用
避免 128bit 以下的 key 长度(比如, 哥们求你别再提 DES 这种 56bit 密钥的古董了)
3. 对称签名:
应该选择 HMAC 类的算法
适用场景: 安全加固一个 API, 如各种开放 API 的调用方认证
如果对一个 API, 你需要做认证(authenticating), 但是不需要做加密(encrypting), 记得千万不要自己发明算法, 你自己发明的 Mac 算法基本都有安全漏洞, 如果不信, 请 Google 一下 "长度扩展攻击"
长度扩展攻击
Flickr 的漏洞案例
同时, 必须要注意的是, 要使用一个常数时间字符串对比算法(这个地方和码农的常识完全相反, 请务必留意)
此外, 应该
避免自行设计的 "带密码的 hash" 结构, 你的设计基本都是有安全漏洞的
避免 HMAC-MD5, 避免 HMAC-SHA1, 使用 HMAC-SHA256, HMAC-SHA512 等
避免复杂的多项式 Mac
避免加密 hash 值的结构
避免 CRC
4. Hashing/HMAC 算法
应该选择 SHA2 http://en.wikipedia.org/wiki/SHA-2 类的算法:: SHA-256, SHA-384, SHA-512, SHA-512/256
优先使用 SHA-512/256,SHA-512/256 这个算法把 SHA-512 的 512bit 输出截短到 256bit, 避开了 length extension 攻击.
同时, 目前 SHA-2 是很安全可靠的, 你不需要升级到 SHA-3.
此外, 应该
避免 SHA-1
避免 MD5
避免 MD6
5. 随机 ID
应该使用 256 bit 的随机值
一定要使用 /dev/urandom, 请认准这个
此外, 应该
避免用户空间的随机数生成器如: havaged,prngs,egd, 等
避免 / dev/random
6. 密码处理
按照优先级顺序, 选择:
scrypt
bcrypt
如果以上 2 个都没有, 那就用 PBKDF2
此外, 应该
避免直接 SHA-2
避免直接 SHA-1
避免直接 MD5
7. 非对称加密
应该使用 NaCl 库
适用场景: 当你需要加密消息, 发给陌生人, 并且对方异步接收消息, 做离线解密时. 这是一个很窄的应用案例, 这种用法有个名字叫电子信封(digital envelope), 典型比如 gpg 加密文件后发送.
这条是几条之中最难做正确的, 不要使用底层的密码学库, 比如 OpenSSL 或者 BouncyCastle.
你应该停止使用 RSA, 并且切换到椭圆曲线类体制, 原因是:
对 RSA 的攻击能力的进步 --- 定义在传统质数域上的乘法运算 (应用包括 DH,DSA,ElGamal 等), 要比椭圆曲线域上的乘法运算快得多. 这是由于质数域上数域筛法(number field sieve,NFS) 的进展, 而在椭圆曲线域上, 没有 NFS 这类算法.
RSA (和 DH) 或迫使你考虑 "向后兼容性", 而椭圆曲线体制没有这种兼容性包袱. TLS 最近的几个安全漏洞, 部分愿意也是由于这种向后兼容性, 导致已经被破解的陈旧算法存在
RSA 在一般场景中, 都是直接用公钥做非对称加密, 这种用法丧失了前向安全性(Perfect Forward Secrecy). 而椭圆曲线就不提倡, 也很难这样使用, 这样你就不会害死自己了.
在椭圆曲线体制下, 保证正确性和安全性的重任, 主要由密码学家承担, 密码学家会提供一组曲线参数, 在某一性能水平下, 针对安全性和性能做优化. 这样程序员不容易误用而害死自己. 在 RSA 体制下, 正好相反, 程序员必须提供参数来保证正确性和安全性, 就算是 RSA-OAEP 这种很好的设计, 程序员也必须知道怎么提供参数, 这样程序员很容易搞错.
如果你必须使用 RSA, 一定要使用 RSA-OAEP with SHA256, 指数使用 65537
避免 RSA-PKCS1v15
避免 ElGamal
避免 RSA
8. 非对称签名
应该使用 NaCl,Ed25519, 或者 RFC6979
应用场景: 如果你在设计一种新的比特币, 或者一个给 Ruby Gems 或者 Vagrant imges 文件签名的系统, 或者数字版权保护系统(DRM), 其中一系列的文件需要离线做认证;
或者你在设计一个加密消息传输层
上一条的内容在此处全部适用.
在 10 + 年做付费软件安全评估的工作经历中, 我只有屈指可数的几次, 遇到使用 RSA-PSS 的用户, RSA-PSS 是一个学术界的推荐算法.
过去 10 年, 非对称签名最主要的应用场景是比特币, 和前向安全的密钥协商(TLS 协议里面的 ECDHE).
其中最主要的算法全都是基于椭圆曲线体制的. 务必警惕新出现的使用 RSA 签名的系统, 很有可能有问题.
在过去几年中, 业界有一种趋势: 放弃传统 DSA 签名, 改为难以误用的确定性签名体制, 其中的 EdDSA(不要和 ECDSA 搞混了喂!)和 RFC6979 是最好的例子. 这种趋势的主要是受到 2010 年索尼 PlayStation 3 的 ECDSA 私钥被破解事件的影响, 在这个案例中, 索尼公司的码农错误地把一个随机数重复使用来做 ECDSA 签名, 形成了漏洞, 使得破解者据此直接把私钥算出来了. 确定性签名体制在设计中不再依赖随机数生成器, 因此彻底避开此类误用. 所以你应该优先使用确定性签名体制.
避免 RSA-PKCS1v15, 避免 RSA, 避免 ECDSA, 避免 DSA
特别要避免常规的 DSA 和 ECDSA
9. Diffie-Hellman 密钥交换
应该使用 NaCl,Curve25519, 或者 DH-2048
适用场景: 如果你在设计加密消息传输系统, 并且无法使用固定对称密码
这是很棘手的一条, 主要考量如下:
如果你能使用 NaCl 库, 那就使用 NaCl 库. 你甚至不需要管 NaCl 是什么.
如果你能使用一个可信赖的第三方库, 那就使用 Curve25519, 这是一条现代的 ECDH 曲线, 有丰富的开源代码, 性能经过高度优化, 被彻底地安全分析过. 并且 Curve25519 即将进入 TLS 1.3 版本标准.
但是绝对不要自己实现 Curve25519, 也绝对不要自己移植 Curve25519 的 C 代码
如果你不能使用第三方 ECDH 库, 但是可以使用 DH 库, 那就使用 DH-2048, 使用 1 个标准的 2048 bit 的群.
但是不要使用传统的 DH, 如果你需要协商 DH 参数, 或者和其他实现互操作
如果你一定要做握手协商, 或者和旧软件互操作, 那么考虑使用 NIST P-256, NIST P-256 有广泛的软件支持.
写死在代码里的 DH-2048 参数, 比 NIST P-256 更安全. NIST P-256 比协商出来的 DH 更安全.
但是, 由于 NIST P-256 的实现有一些陷阱, 所以一定要谨慎选择可信赖的, 广泛使用使的第三方库
P-256 可能是 NIST 曲线中最安全的, 不要使用 P-224.
DH(密钥协商)算法确实很难用, 但是它很重要.
避免, 传统常规的 DH, SRP, J-PAKE 握手和协商
避开任何只使用了块加密算法和 srand(time())的密钥协商模式(肯定有漏洞)
10. 网站安全
应该使用 OpenSSL, 或者 Google 的 BoringSSL, 或者直接使用 AWS 的 ELB
此处网站安全, 指的是让网站支持 HTTPS 协议.
如果你不能把这个任务交给 Amazon 的云服务去做, 把难题留给 Amazon 去解决, 那么 OpenSSL 目前仍然是正确选择.
避免不常见的 TLS 库, 例如 polarssl,GnuTLS,MatrixSSL 等
11. 客户端 - 服务器结构的应用程序的安全:
应该使用 TLS
适用场景: 如果你以为自己理解了前面关于公钥加密的介绍...
通常, 在你设计了自己的 RSA 协议之后的 1 至 18 个月, 你肯定会发现, 你犯了某个错误, 使你的协议没有任何安全性.
比如 Salt Stack,Salt Stack 的协议使用了 e=1 的 RSA 公钥...
听起来, TLS 有下面这些黑历史:
- The Logjam DH negotiation attack
- The FREAK export cipher attack
- The POODLE CBC oracle attack
- The RC4 fiasco
- The CRIME compression attack
- The Lucky13 CBC padding oracle timing attack
- The BEAST CBC chained IV attack
- Heartbleed
- Renegotiation
- Triple Handshakes
- Compromised CAs
但是, 你仍然应该使用 TLS 做传输协议, 因为:
这些漏洞中的大部分, 仅仅是针对浏览器的, 因为他们依赖受害者执行攻击者控制的 JavaScript 脚本, 这些 JavaScript 脚本生成重复的明文, 或特定的明文.
这些漏洞中的大部分, 其影响都可以被减轻, 只需要你在代码和配置里面写死 TLS v1.2, ECDHE, 和 AES-GCM 就行. 这听起来很棘手, 但是这远远没有你自己设计使用 ECDHE 和 AES-GCM 的传输协议棘手.
在一个自定义的传输协议的场景中, 你并不需要依赖 CA, 你可以用一个自签名证书, 嵌入到你的客户端里面.
不要自己设计加密传输协议, 这是极其困难而易错的工程难题
使用 TLS, 但是不要使用默认配置
12. 在线备份
应该使用 Tarsnap
名词解释
本文的内容比较新, 相关中文资料极少, 因此文中的名词对读者可能有点陌生, 故 byron 这里介绍一下文中提到的一些名词:
1. NaCl 库:
http://nacl.cr.yp.to/
是密码学学术权威 Daniel J. Bernstein 教授 设计的一个密码学算法库, 2008 年发开始公布. NaCl 的特点是: API 简洁而易用, 高性能, 高安全性, 主要用于网络通信, 加密, 解密, 签名等, NaCl 提供了构建高层密码学工具的核心功能.
2. libsodium 库:
https://download.libsodium.org/doc/
libsodium 是对 NaCl 库的一个分支, 进一步改进接口易用性, 和可移植性.
3. AEAD:
AEAD 的概念:
在通常的密码学应用中, Confidentiality (保密) 用加密实现, Message authentication (消息认证) 用 Mac 实现. 这两种算法的配合方式, 引发了很多安全漏洞, 过去曾经有 3 种方法: 1. Encrypt-and-Mac 2.Mac-then-Encrypt 3.Encrypt-then-Mac , 后来发现, 1 和 2 都是有安全问题的, 所以, 2008 年起,
逐渐提出了 "用一个算法在内部同时实现 cipher+MAC" 的 idea, 称为 AEAD(Authenticated encryption with additional data).
在 AEAD 这种概念里, cipher+Mac 被 一个 AEAD 算法替换.
4. ChaCha20-poly1305
ChaCha20-poly1305 是一种 AEAD, 提出者是 Daniel J. Bernstein 教授, 针对移动互联网优化, 目前 Google 对移动客户端的所有流量都使用 ChaCha20-Poly1305
5. AES-GCM
AES-GCM 是一种 AEAD, 是目前 TLS 的主力算法, 互联网上 https 流量的大部分依赖使用 AES-GCM.
6. AES-GCM 和 ChaCha20-Poly1305 的性能对比测试结果:
Chip | AES-128-GCM speed | ChaCha20-Poly1305 speed |
---|---|---|
OMAP 4460 | 24.1 MB/s | 75.3 MB/s |
Snapdragon S4 Pro | 41.5 MB/s | 130.9 MB/s |
Sandy Bridge Xeon (AESNI) | 900 MB/s | 500 MB/s |
7. AES-CBC
关于 AES-CBC, 在 AES-GCM 流行之前, TLS 主要依赖 AES-CBC, 而由于历史原因, TLS 在设计之初固定选择了 Mac-then-Encrypt 结构, AES-CBC 和 Mac-then-encrypt 结合, 为选择密文攻击 (CCA) 创造了便利条件, TLS 历史上有多个漏洞都和 CBC 模式有关:
The POODLE CBC oracle attack: 参考:
1.POODLE 的一个分析
2.openssl 的分析 https://www.openssl.org/~bodo/tls-cbc.txt
3. 乌云的文章 http://drops.wooyun.org/papers/3194
- The CRIME compression attack:
- The Lucky13 CBC padding oracle timing attack:
- The BEAST CBC chained IV attack:
- 8. SHA2
- http://en.wikipedia.org/wiki/SHA-2
- 9. Curve25519
- http://cr.yp.to/ecdh.html
Curve25519 是目前最高水平的 Diffie-Hellman 函数, 适用于广泛的场景, 由 Daniel J. Bernstein 教授设计. 由于 NIST P-256 的设计过程不透明, 有来历不明的参数, 被广泛怀疑有后门, 所以设计了 Curve25519,Curve25519 的设计过程完全公开, 没有任何来历不明的参数.
部署情况: http://ianix.com/pub/curve25519-deployment.html
- 10. Ed25519
- http://ed25519.cr.yp.to/
Ed25519 是一个数字签名算法,
签名和验证的性能都极高, 一个 4 核 2.4GHz 的 Westmere CPU, 每秒可以验证 71000 个签名
安全性极高, 等价于 RSA 约 3000-bit
签名过程不依赖随机数生成器, 不依赖 hash 函数的防碰撞性, 没有时间通道攻击的问题
并且签名很小, 只有 64 字节, 公钥也很小, 只有 32 字节.
部署情况: http://ianix.com/pub/ed25519-deployment.html
11. 前向安全性
前向安全性( Perfect Forward Secrecy )
前向安全性指的是, 如果攻击者抓取并保存流量, 那么将来私钥泄露后, 攻击者也无法利用泄露的私钥解密这些流量.
12. Diffie-Hellman 密钥交换
在任何一本密码学教材里面都会重点介绍的
13. constant time compare
针对 Timing attack, http://en.wikipedia.org/wiki/Timing_attack (这种攻击真是脑洞大开!)
当一个算法的运行时间和输入数据有关的时候, 可以根据运行时间这一信息, 破解出密钥等.
典型的, 比如要验证一个对称签名, 如果你用了 C 库里面的 memcpy(), 那你就会被 timing attack 方式攻击.
因此, 涉及到密码学数据的 memcpy, 必须要用运行时间和输入无关的函数, 比如 OpenSSL 库里面的 CRYPTO_memcmp()
[转]现代密码学实践指南
来源: http://www.bubuko.com/infodetail-3025180.html