【密码学】一文读懂HKDF
HKDF
我这又来水一篇文章,来聊一下HKDF(基于HMAC的密钥导出函数)。密钥派生函数是密钥管理的组成部分,他的目标是通过一些初始的数据派生出来密码学安全的随机密钥。
前置知识
因为这个密钥导出函数是基于HMAC的,因此呢,需要先来回顾一下HMAC的先关知识。有关HMAC的详细知识,读者可以自行回顾一下我之前写过的HMAC的相关文章,这里贴一张之前文章当中出现的图。
HMAC结构
算法流程
对于HKDF算法主要分为如下两个步骤
Extract
对于Extract方法来说,他的输入实际上就是HMAC的输入,如果salt不传的话,默认是哈希长度相等的0字节序列。然后 PRK = HMAC(salt, IKM)
Expand
对于扩展算法来说,这个就是生成整个密钥流的关键函数了,如下图所示:
HKDF-Expand
最终输出 T(1) || T(2) ...
根据具体长度输出所需要生成的密钥。
代码实现
这里借鉴了Go的官方库的写法,感觉Go官方库实现的这些代码还是相当不错的。
package hkdf import ( "crypto/hmac" "hash" "io" ) type HKDF struct { hashFunc hash.Hash size int info []byte counter byte prev []byte buf []byte } // Extract HKDF-Extract(salt, IKM) -> PRK func Extract(hash func() hash.Hash, secret, salt []byte) []byte { if salt == nil { salt = make([]byte, hash().Size()) } hashFunc := hmac.New(hash, salt) hashFunc.Write(secret) return hashFunc.Sum(nil) } func (f *HKDF) Read(p []byte) (int, error) { need := len(p) n := copy(p, f.buf) p = p[n:] for len(p) > 0 { f.hashFunc.Reset() f.hashFunc.Write(f.prev) f.hashFunc.Write(f.info) f.hashFunc.Write([]byte{f.counter}) f.prev = f.hashFunc.Sum(f.prev[:0]) f.counter++ f.buf = f.prev n = copy(p, f.buf) p = p[n:] } f.buf = f.buf[n:] return need, nil } // Expand HKDF-Expand(PRK, info, L) -> OKM func Expand(hash func() hash.Hash, prk, info []byte) io.Reader { hashFunc := hmac.New(hash, prk) return &HKDF{hashFunc, hashFunc.Size(), info, 1, nil, nil} } func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader { prk := Extract(hash, secret, salt) return Expand(hash, prk, info) }