HKDF(基于HMAC的密钥导出函数)

HKDF(基于HMAC的密钥导出函数)

1. 基础

HKDF叫HMAC-based KDF(key derivation function),基于HMAC的密钥推导函数。

基于一个共同密钥,在两个对端之间提供消息完整性确认的机制叫"message authentication codes(MAC),消息认证码"。其实就是将消息进行hash,得到的hash值附加到消息之后,随消息一起发送,对端接收后,同样进行hash,来验证消息是否被篡改——关键点在不同数据得到的hash值一定不同——其中得到的hash值就是MAC(在别的语境里边也叫消息摘要)。另外,为了避免使用同样的hash函数对相同数据进行操作总是得出同样的摘要,额外加入一个密钥,这样使用不同密钥就可以得出不同的MAC,当然,这个密钥是两个对端都知道的。这样,我们就得到了基于加密hash的消息完整性认证的算法——Hash-based MAC。

2. 什么是HKDF

HKDF是HMAC-based Extract-and-Expand Key Derivation Function的缩写,意为基于HMAC的提取和扩展密钥派生函数。它是一种密钥派生函数,用于从较短的输入密钥中派生出更长的输出密钥。

HKDF的主要目的使用原始的密钥材料,派生出一个或更多个能达到密码学强度的密钥(主要是保证随机性)——就是将较短的密钥材料扩展成较长的密钥材料,过程中需要保证随机性。

RFC 5869 定义了HKDF算法,以提供一种简单、安全的方法从主密钥或密码学上下文中导出一个或多个密钥。它利用HMAC作为伪随机函数,可以根据需要生成任意数目的密钥片段。

HKDF包含两个基本模块,或者说两个基本使用步骤:

  1. 提取 Extract,
  2. 扩展 Expand。

提取:HKDF-Extract就是HMAC。使用原始的密钥材料,派生出一个符合密码学强度的伪随机密钥。

扩展:HKDf-Expand就是将短密钥变长,同时保证随机性。使用第1步骤提取出来的伪随机密钥,扩展出指定长度的密钥(同时保证随机性)。

总结: HKDF包含两步:(1) 提取Extract, (2) 扩展Expand;

HKDF算法具有以下主要特点:

  1. 输入灵活:它可以接受任意长度的主密钥或共享密钥作为输入。这使它适用于各种应用场景。
  2. 任意输出长度:它可以生成任意长度的输出密钥片段。这使得它可以满足各种长度要求。
  3. 强前向保密性:后续生成的密钥片段无法由先前片段计算得出,这增加了安全性。
  4. 简单高效:HKDF利用HMAC,性能高且易于实现,这有利于安全性与可靠性。
  5. 标准化:HKDF已标准化,有明确的算法定义和测试向量,这有利于安全审计与验证。

对于同样的输入,HKDF算法生成的密钥必然相同。
因为HKDF算法是一种确定性算法,同样的输入将产生同样的输出。

HKDF-Extract

HKDf-Expand就是将短密钥变长,同时保证随机性

输入:

  1. HMAC使用的hash函数H,H输出长度是hashLen
  2. 原始密钥材料IKM(input keying material)
  3. 另外的随机源salt, 如果没有,默认是hashLen长度的0串

输出:
hashLen长度的伪随机密钥prk(pseudorandom key)

hkdf.Expand()原理

hkdf.Expand()函数将PRK(Pseudo-Random Key)展开为io.Reader,目的是生成输出密钥。

举例来说,如果我们的PRK是16字节,info是"hkdf info",我们要得到32字节输出密钥。那么:

  1. info_length是"hkdf info32"。
  2. 第一次HMAC(PRK, info_length) -> Block_1。取Block_1前16字节作为键。
  3. 第二次HMAC(Block_1前16字节, PRK, info_length) -> Block_2。取Block_2前16字节作为键。
  4. 第三次HMAC(Block_2前16字节, PRK, info_length) -> Block_3。
  5. Block_1 + Block_2 + Block_3 = 48字节,截取前32字节作为最终输出密钥。
  6. 封装在io.Reader中返回。
    这就是hkdf.Expand()函数的原理,使用迭代HMAC运算生成我们需要长度的输出密钥。这也是HMAC密钥派生函数HKDF的Expand阶段具体实现过程。

Go语言的crypto/hkdf包

func HKDF(hash crypto.Hash, salt, ikm, info []byte, size int) []byte
  • hash:哈希函数,可以是SHA1、SHA256、SHA512等。
  • salt:随机数,可选,为空时会使用默认随机数。
  • ikm:输入密钥材料,可以是任意长度的数据。(ikm是input keying material的缩写)
  • info:可选的上下文与应用相关信息,可为空。(用于区分不同的密钥)
  • size:要生成的伪随机密钥的长度。
    它会根据输入的参数,使用HKDF算法生成指定长度的伪随机密钥输出。

hkdf示例

package main

import (
	"crypto/sha256"
	"encoding/hex"
	"golang.org/x/crypto/hkdf"
)

func main() {
    
    
	// 输入密钥材料
	ikm := []byte("input key material")

	// 信息
	info := []byte("hkdf info")

	// 提取PRK  PRK(Pseudo-Random Key)
	prk := hkdf.Extract(sha256.New, ikm, nil)

	// 扩展为io.Reader
	r := hkdf.Expand(sha256.New, prk, info)

	// 读取密钥
	key1 := make([]byte, 32)
	r.Read(key1)
	println(hex.EncodeToString(key1))

	// 重复读取得到相同密钥
	key2 := make([]byte, 32)
	r.Read(key2)
	println(hex.EncodeToString(key2))
}

在这个函数中,key1和key2不应该相等。原因是:
根据HKDF机制,从expander中多次读取应该得到不同的随机密钥。expander实际上是一个伪随机函数,每次读取会得到不同的值。

但是,使用相同的ikm、info、salt 重新生成新的密钥,多次生成的密钥是一样的,这样的场景下,读取相同位置的内容是一样的。

因为相同的输入ikm、info和salt,会产生相同的prk和相同的expander。所以读取相同位置的内容也相同。

总结: 相同的ikm、info和salt输入,会产生相同的密钥!

3. Argon2id

密钥衍生函数(KDF)使用Argon2id。
KDF的参数默认遵循RFC推荐

Argon2id是记忆硬密度函数Argon2的一种变体,用于密钥衍生和密码散列。
RFC是指相关的密码学标准文档,RFC推荐的参数可以确保KDF的安全强度和效率。

在生产环境下,生成X25519私钥最好不直接使用crypto/rand的随机字节。更好的方式是使用密码学上更加强大的函数,比如Argon2id、HKDF等。
Argon2id是当前被广泛认为是最安全的密码hash函数之一,它可以产生随机密码和密钥。HKDF是一种密钥生成函数,可以基于较短的输入密钥材料生成较长的密钥。
使用这些函数来生成X25519私钥,可以带来以下好处:

  1. 更高的抵抗暴力破解。这些函数将用户输入(密码) maps 到高熵随机输出,通过迭代运算和内存消耗提高破解难度。
  2. 更好的随机性。这些函数会利用密码和盐值生成高熵随机数据,随机性更强于简单读取系统熵。
  3. 对用户输入(如密码)进行处理。简单读取随机熵无法处理用户输入,而这些函数可以将用户输入 mappings 到强随机输出。
  4. 更容易 música 的后续处理。生成的密钥可以作为这些函数的输入密钥材料,进行下一步处理。
    所以,使用Argon2id或HKDF等函数生成X25519私钥,可以获得上述多方面好处。一个简单示例如下:
import "golang.org/x/crypto/argon2"

func GeneratePrivateKey(password string) []byte {
    
    
    // Generate salt
    salt := make([]byte, 16)
    if _, err := io.ReadFull(rand.Reader, salt); err != nil {
    
    
        panic(err)
    }

    // Derive key
    key := argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32) 

    // Return X25519 private key
    return key
}

这个函数使用Argon2id函数,基于用户输入的password和随机salt,派生出一个32字节X25519私钥

对生产环境,使用Argon2id、HKDF等密码学函数生成X25519私钥是一个非常好的选择,可以在安全性、随机性和可扩展性上获得大幅提升。

4. 参考

【密码学】一文读懂HKDF
参考URL: https://developer.aliyun.com/article/952966
RFC5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF)
RFC2104: HMAC: Keyed-Hashing for Message Authentication

猜你喜欢

转载自blog.csdn.net/inthat/article/details/130630997