哈希算法
Hash
| 算法 | 分组长度Byte | 摘要长度Byte | 中间迭代值byte | 支持消息最大长度比特 | 填充方式 | 参考标准 |
|---|---|---|---|---|---|---|
| SM3 | 64 | 8*4=32 | 32 | 64/32*32 | GB/T 32905-2016 | |
| MD5 | 64 | 4*4=16 | 16 | 64/32*32 | RFC 1321 | |
| SHA1 | 64 | 5*4=20 | 20 | 64/32*32 | NIST SP 800-57 | |
| SHA256 | 64 | 8*4=32 | 32 | 64/32*32 | 先添加1比特1,再填充k个比特0,使得消息比特长度对512去摸后的余数是448,再填充64位数据代表原始消息的比特长度 | FIPS PUB 180-4 FIPS PUB 202 |
| SHA224 | 64 | 7*4=28 | 32 | 64/32*32 | 同上 | 同上 |
| SHA384 | 32*4=128 | 12*4=48 | 64 | 64/32*32 | 先添加1比特1,再填充k个比特0,使得消息比特长度对1024去摸后的余数是896,再填充128位数据代表原始消息的比特长度 | 同上 |
| SHA512 | 32*4=128 | 16*4=64 | 64 | 128/32*32 | 同上 | 同上 |
| SHA512_224 | 32*4=128 | 7*4=28 | 64 | 128/32*32 | 同上 | 同上 |
| SHA512_256 | 32*4=128 | 8*4=32 | 64 | 128/32*32 | 同上 | 同上 |
| SHA3_224 | 36*4=144 | 7*4=28 | 200 | 64 | FIPS PUB 202 NIST SP 800-185 |
|
| SHA3_256 | 34*4=136 | 8*4=32 | 200 | 64 | 同上 | |
| SHA3_384 | 26*4=104 | 12*4=48 | 200 | 64 | 同上 | |
| SHA3_512 | 18*4=72 | 16*4=64 | 200 | 64 | 同上 | |
| SHAKE128 | 168 | 任意长度 | 200 | b=r+c=2000=1744+256 | FIPS 202 | |
| SHAKE256 | 同SHA3_256 | 任意长度 | 200 | b=r+c=2000=1488+512 | FIPS 202 |
注:
- 以上hash都有起始IV(迭代值),其中sha3 iv是1600bit的0,摘要结果取最后迭代值最高有效位长度byte
- SHAKE(Secure HASH Algorithm and KECCAK),是Keccak哈希函数家族成员,属于可拓展输出函数(XOF,Extendable Output Function),源自NIST SHA-3标准,FIPS 202
在 SHA-3 中,c 表示容量(capacity),b 表示中间状态位宽。具体介绍如下:
-
c(容量):它是 SHA-3 算法海绵结构中的一个重要参数,其长度通常为输出长度的两倍。例如对于 SHA3-256,输出长度是 256 位,那么 c 通常为 512 位。c 的主要作用是增强算法的安全性,防止碰撞等攻击,容量越大,安全性理论上越高。
-
b(中间状态位宽):b=r+c,其中 r 是消息分组长度,也称为比特率。b 代表了轮函数 f 的输入输出位宽,在 SHA-3 标准中,b 的长度固定为 1600 位。无论具体的 SHA-3 变体(如 SHA3-224、SHA3-256 等)或可扩展输出函数(如 SHAKE128、SHAKE256)如何,其内部运算时的状态大小均为 1600 位,即 b 的值是固定的,通过调整 r 和 c 的值来适应不同的安全需求和输出要求。
第一原像攻击(First-Preimage Attack):给定一个哈希值 h,找到任意一个消息 m,使得哈希函数 H(m)=h。
第二原像攻击(Second-Preimage Attack):给定一个消息 m1,找到另一个不同的消息 m2(即 m2 != m1),使得 H(m1)=H(m2)。
碰撞攻击:找任意两个不同消息 m1 != m2 使 H(m1)=H(m2)(无前提的碰撞寻找)
PBKDF
《RFC7914》
《RFC 2898》——已废除
cryptolib pbkdf2:由RFC8018定义的一种基于口令的密钥派生算法
Password-Base Key Derivation Function 基于密码的密钥派生函数
原理:通过一个伪随机函数(例如HMAC函数),把明文和一个盐值作为输入参数,然后重复运算,并最终产生密钥。
//函数定义
DK = PBKDF(PRF, Password, Password_Len, Salt, Salt_Len, iter_num, DKLen)
DK //PBKDF算法产生的密钥
PRF //伪随机数,例如HASH_HMAC,输出长度为hLen结果
Password //原文密码
Salt //用于生成密钥加盐的盐值
iter_num //迭代运算次数
DKLen //期望得到的密钥的长度
具体流程:https://blog.csdn.net/HORHEART/article/details/119968850
公式:
PRF取自hmac
2.DK=T1||T2||...||Tdklen/hlen
3.Ti=F(Password,salt,c,i)
4.F(Password,salt,c,i)=U1⊕U2⊕...⊕Uc
5.Ui=PRF(Password, Salt||INT_32_BE(i))
KDF(ANSI X9-63-2011(R2017))
Key Derivation Function(kdf)
Input:
1.secret value, of bit length at most maxlength-32
2.keydatalen, bit len shall be less than(2^32-1)hashlen
3.(optional) A bit string ShareInfo that consists of some data shared by two entities
the total bit length of Z and ShareInfo must be at most maxhashlen-32
Actions:
1.Initiate a 32-bit, big endian bit string counter as 0x00000001
2.for i=1 to j=integer_up(keydatalen/hashlen):
2.1 Compute Hash_i = H(Z||counter||Shareinfo)
2.2 Increment counter
2.3 Increment i
3. Let HHash_j denote Hash_j if keydatalen/hashlen is an integer, and let it denote the (keydatalen-(hashlen)_j) leftmost bits of Hash_j otherwise
4.Set KeyData = Hash_1||Hash_2||Hash_3||...||Hash_j
Output: The bit string KeyData of length keydatalen bits
X9.63 KDF-SHA256
计算流程示例
[SHA-256]
[shared secret length = 192]
[SharedInfo length = 128]
[key data length = 1024]
COUNT = 0
Z = 22518b10e70f2a3f243810ae3254139efbee04aa57c7af7d
SharedInfo = 75eef81aa3041e33b80971203d2c0c52
Counter = 00000001
Hash input 1 = 22518b10e70f2a3f243810ae3254139efbee04aa57c7af7d0000000175eef81aa3041e33b80971203d2c0c52 //Z||Counter||ShareInfo
K1 = c498af77161cc59f2962b9a713e2b215152d139766ce34a776df11866a69bf2e
Counter = 00000002
Hash input 2 = 22518b10e70f2a3f243810ae3254139efbee04aa57c7af7d0000000275eef81aa3041e33b80971203d2c0c52
K2 = 52a13d9c7c6fc878c50c5ea0bc7b00e0da2447cfd874f6cf92f30d0097111485
Counter = 00000003
Hash input 3 = 22518b10e70f2a3f243810ae3254139efbee04aa57c7af7d0000000375eef81aa3041e33b80971203d2c0c52
K3 = 500c90c3af8b487872d04685d14c8d1dc8d7fa08beb0ce0ababc11f0bd496269
Counter = 00000004
Hash input 4 = 22518b10e70f2a3f243810ae3254139efbee04aa57c7af7d0000000475eef81aa3041e33b80971203d2c0c52
K4 = 142d43525a78e5bc79a17f59676a5706dc54d54d4d1f0bd7e386128ec26afc21
key_data = c498af77161cc59f2962b9a713e2b215152d139766ce34a776df11866a69bf2e52a13d9c7c6fc878c50c5ea0bc7b00e0da2447cfd874f6cf92f30d0097111485500c90c3af8b487872d04685d14c8d1dc8d7fa08beb0ce0ababc11f0bd496269142d43525a78e5bc79a17f59676a5706dc54d54d4d1f0bd7e386128ec26afc21
PBKDF2
由RFC8018定义的一种基于口令的密钥派生算法.
公式:
PRF取自hmac
2.DK=T1||T2||...||Tdklen/hlen
3.Ti=F(Password,salt,c,i) //c为迭代次数,i为块索引号,F为密钥派生使用的方式,在此为hmac
4.F(Password,salt,c,i)=U1⊕U2⊕...⊕Uc //每轮迭代值进行异或,异或c轮
5.其中,U1=PRF(Password, Salt||INT_32_BE(i)) //INT_32_BE占用4字节,即最多2^32-1个分组
6.其中,U2=PRF(Password, U1) ... Uc=PRF(Password, Uc-1)
//demo pbkdf2-sha256-hmac
//key-password-16Byte
2C66FFF7B11A80DEA2F6B40C195D5004
//salt-4Byte
73616C74
//iter-4Byte
1
//keybytes-Byte
32
//pbkdf2-sha256-hmac
2221967a15e14c16e45f6334fcd5058f4698eed1b137a30029b92428c21301e4
//result
=hmac(key, Salt||INT_32_BE(i))
=hmac(2C66FFF7B11A80DEA2F6B40C195D5004,73616C7400000001)
=2221967A15E14C16E45F6334FCD5058F4698EED1B137A30029B92428C21301E4
//demo pbkdf2-sha256-hmac
//key-password-16Byte
2C66FFF7B11A80DEA2F6B40C195D5004
//salt-4Byte
73616C74
//iter-4Byte
2
//keybytes-Byte
32
//pbkdf2-sha256-hmac
2221967a15e14c16e45f6334fcd5058f4698eed1b137a30029b92428c21301e4
//result
U1=hmac(key, Salt||INT_32_BE(i))
=hmac(2C66FFF7B11A80DEA2F6B40C195D5004,73616C7400000001)
=2221967A15E14C16E45F6334FCD5058F4698EED1B137A30029B92428C21301E4
U2=hmac(key, U1)
=hmac(2C66FFF7B11A80DEA2F6B40C195D5004, 2221967A15E14C16E45F6334FCD5058F4698EED1B137A30029B92428C21301E4)
=FF3F55577345ABEC90C5D7B9A151AC0B3E7363CC89FE893E533F172F0C36E4B2
result=U1 xor U2
=2221967A15E14C16E45F6334FCD5058F4698EED1B137A30029B92428C21301E4 xor FF3F55577345ABEC90C5D7B9A151AC0B3E7363CC89FE893E533F172F0C36E4B2
=DD1EC32D66A4E7FA749AB48D5D84A98478EB8D1D38C92A3E7A863307CE25E556
SipHash
没有被制定为NIST标准,被业界广泛认可和采纳的事实标准,学术论文链接:https://www.aumasson.jp/siphash/siphash.pdf
Siphash是一系列针对短消息输入的为随机函数,主要应用程序包括网络身份校验和哈希表查询,抵抗哈希洪泛拒绝服务攻击
SipHash-c-d
含义:
c = 每处理一个 8 字节消息块时执行的压缩轮数
d = 最终输出 MAC 前执行的 finalization 轮数
SipHash_4_8
输入:
密钥:16字节
消息:任意长度消息(含空消息)
输出:
mac:8字节
特点:较慢(约为SipHash_2_4的50%),更高安全性(对安全性要求更高的场景)
SipHash_2_4
输入:
密钥:16字节
消息:任意长度消息(含空消息)
输出:
mac:8字节
特点:性能最快,足够安全(大多数hash表场景使用)
总结:
- siphash输入无消息长度限制,支持空消息,设计初衷为短输入
HKDF
HKDF 全称 HMAC-based Extract-and-Expand Key Derivation Function,由 RFC 5869 定义
设计背景
提取:在许多应用中,输入的密钥材料不一定均匀分布,攻击者可嫩掌握部分信息,提取阶段的目的是将输入密钥材料可能分散的熵,集中到一个短的、但加密性强的伪随机密钥中。
拓展:将伪随机密钥拓展到指定的长度
输入:
hash,哈希算法(SHA256/384/512)
salt,可选的随机盐(不提供默认为全0字符串,长度等于hash的输出长度)
info,上下文,可为空
ikm,密钥材料,非hmac key
输出:
PRK,长度等于hash的输出长度
注:
- 对于salt,理想情况下是长度为HashLen的随机(或伪随机)字符串,即使质量较低salt,也可能对安全性做出重大贡献
- 对于info,可以是算法标识符,使用者标识符,协议编号等等,可以容纳密钥拓展部分的额外输入比如长度信息L
Extract
输入:
salt,【optional】盐值,optinal,为空时,默认为Hash摘要长度的零字符串
IKM,密钥材料
输出:
PRK,伪随机密钥,Hash摘要长度,PRK=HMAC(salt, IKM)
【Extract】
PRK = HMAC-Hash(salt, IKM)
Expand
输入:
PRK,伪随机密钥,至少是Hash摘要长度,通常取Extract的输出
info,【optional】上下文和应用程序指定的信息(可以是零长度字符串)
L,输出密钥的字节长度,<=255*Hash摘要长度,即最大255个分组长度
输出:
OKM,输出密钥材料(L字节)
【Expand】
N=ceil(L/HashLen)
T = T(1) || T(2) || ... || T(N)
OKM = first L Bytes of T
T(0) = 空字符串,长度为0
T(1) = HMAC-Hash(PRK, T(0) || info || 0x01)
T(2) = HMAC-Hash(PRK, T(1) || info || 0x02)
...
T(N) = HMAC-Hash(PRK, T(N-1) || info || N)
示例Demo
//IKM
0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
//salt
000102030405060708090a0b0c
//info
f0f1f2f3f4f5f6f7f8f9
//Extract: PRK = HMAC-Hash(salt, IKM)
HMAC-Sha256(key,msg)=(000102030405060708090a0b0c, 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b)
=077709362C2E32DF0DDC3F0DC47BBA6390B6C73BB50F9C3122EC844AD7C2B3E5
//Expand: OKM=42B
T(0) = NULL
T(1) = HMAC-Sha256(PRK, T(0) || info || 0x01)=(077709362C2E32DF0DDC3F0DC47BBA6390B6C73BB50F9C3122EC844AD7C2B3E5,f0f1f2f3f4f5f6f7f8f9||01)
=3CB25F25FAACD57A90434F64D0362F2A2D2D0A90CF1A5A4C5DB02D56ECC4C5BF
T(2) = HMAC-Sha256(PRK, T(1) || info || 0x02)=(077709362C2E32DF0DDC3F0DC47BBA6390B6C73BB50F9C3122EC844AD7C2B3E5,3CB25F25FAACD57A90434F64D0362F2A2D2D0A90CF1A5A4C5DB02D56ECC4C5BF||f0f1f2f3f4f5f6f7f8f9||01)
=34007208D5B887185865B4B0A85A993B89B9B65683D60F0106D28FFF039D0B6F //左边截取(42-32)=10B
//OKM
=T(1)||T(2)
=3CB25F25FAACD57A90434F64D0362F2A2D2D0A90CF1A5A4C5DB02D56ECC4C5BF||34007208D5B887185865
注:标准中未提及HKDF限定在哪些hash算法上,从标准协议上看,适用于md5/sha1/sha2/sha3这类有固定输出长度的hash算法,不适用于shake128/256这类任意长度输出的算法上