开发者的密码学快速指南
密码学中的哈希(Hash)
哈希可以把任意给定的输入(任意长度的文本、数字)映射成为固定长度的输出(这个输出称作消息摘要,Message Digest)。
推荐的Hash
基于构造方法的不同,我们推荐开发者常用的哈希:
基于Merkle-Damgard构造的哈希
- SHA-2一族哈希函数:SHA-256,SHA-512
- 国密SM3
基于sponge构造的哈希
Keccak一族哈希函数:Keccak-256,SHA3一族哈希函数(SHA3-256,SHA3-512),SHAKE一族哈希函数(SHAKE128,SHAKE256)
其他
BLAKE2一族哈希函数:BLAKE2s,BLAKE2b,强度和SHA3类似
注意:SHA3被认为是比SHA2更安全的一族哈希函数
消息认证码(MAC)
消息认证码(MAC,Message Authentication Code),也叫做带有密钥的哈希,把给定的输入(任意长度的文本、数字)和一个密钥映射成固定长度的输出。
注意:这里的密钥往往是提前共享的,并不是在应用之前生成的。
推荐的MAC
- HMAC(Hash-based Message Authentication Code):HMAC-SHA256等
- KMAC(Keccak-based MAC)
- CMAC(Cipher-based MAC)
密钥衍生函数(KDF)
密钥衍生函数(KDF,Key Derivation Function)用来把一个长度任意的密码(Password)转换为顶长度的密钥(Key)。
密钥衍生函数算法往往通过一个随机数,盐(Salt)和很多轮的迭代计算,key stretching来生成一个密钥。这个盐值将会和最终生成的密钥共同存储。
推荐的KDF
Argon2:Argon2d,Argon2i,Argon2id(推荐这个),其相关参数包含使用内存大小m,并行因子p
注意:PBKDF2会受到GPU和ASIC攻击,因此被认为是老一代的KDF,不过在很多场合仍然会被使用。Bcrypt和Scrypt也可以使用,不过不如直接使用Argon2好。
伪随机数发生器(CSPRNG)
所有的伪随机数发生器都是从一个初始的随机数,叫做熵(entropy)作为初始种子开始的,经过高质量的随机数发生器(譬如AES,)不断产生随机数。产生一段时间会不停的更新种子,这个过程叫做reseed。
推荐的CSPRNG
Entropy的获得可以通过/dev/random(阻塞式,如果没有新的熵,则会等待)和/dev/urandom(非阻塞式,会通过secure entropy streching算法根据以前获得的entropy拓展)获取。
- Python用os.urandom()或者secrets
- Java用java.security.SecureRandom
对称加密(块加密算法)
这里的对称加密需要注意的地方主要包括算法,初始化向量(IV,Initialization Vector)和加密模式。其中,IV是不需要加密存储的,但每次要不一样。加密模式里面,有些需要填充算法(padding),有些不需要。有些有认证(Authenticated Encryption或者Authenticated Encryption with Associated Data),有些没有。
推荐的Block Cipher
- 无认证的:AES+CTR+NoPadding,SM4+CTR+NoPadding
- 有认证的:AES+GCM+NoPadding,ChaCha20+Poly1305+NoPadding(性能好于AES+GCM+NoPadding)
非对称加密
现在的非对称加密的使用方法一般是集成加密(IES,Integrated Encryption Scheme),包含了KEM(Key Encapsulation Mechanisms)和DEM(Data Encapsulation Mechanisms)。说的直白一些,非对称加密对称密钥,对称密钥加密数据。
RSA加密
基于质因子分解难题的加密系统,系统秘密参数p,q,系统公开参数n,公钥为随机数e,私钥为d。
ECC加密
椭圆曲线:一个函数定义的一条曲线,其定义域范围为有限域(所以曲线上的点都是离散的),曲线上的点关于x轴对称。因此,对于一个离散点P,可以压缩其坐标为x向量和一个比特(这个比特表示的是x轴之上的那个y坐标或者x轴之下的y坐标)。另外,对于公开的曲线,往往都有一个公开的基点G。
点和点之间可以做加法运算(点加运算)或点和整数之间做乘法运算(点乘运算)。0乘以一个点会得到一个特殊点叫做无穷远点。一条曲线上的所有点的个数叫做这条曲线的阶(order),order的计算包含无穷远点。有些曲线构成一个循环群,有些曲线有多个循环子群。对于循环子群,用曲线的公因子(cofactor)表示循环子群的个数。
常见的secp256k1就是单循环子群曲线,Curve25519有8个循环子群。
系统公开参数为椭圆曲线的系数,密钥为定义域内随机选取的整数k,公钥为EC上的点K=k*G。一般选择256比特的私钥,例如常见的曲线secp256k1(y^2 = x^3 + 7 mod p)和Curve25519。
曲线的参数列表一般包括:
- p(modulus)
- n(order)
- a(x的一次项系数)
- b(x的常数项系数)
- g(基点)
- h(cofactor)