漫谈网络通讯加密(3)HKDF

Tags:

本文将简单介绍rfc5869提出的HKDF。

HKDF = HMAC + KDF

HMAC,基于Hash的MAC算法

HMAC是指Hash-based的MAC算法,hash函数是可选的,例如存在这些HMAC实现:

  • HMAC_MD5
  • HMAC_SHA1
  • HMAC_SHA256

虽然hash函数可选,但HMAC是有严格的定义的:

\[ HMAC(k, m) = H ( (k \oplus opad) || H( (k \oplus ipad) || m) ) \]

伪代码:

function hmac (key, message)
    opad = [0x5c * blocksize] // Where blocksize is that of the underlying hash function
    ipad = [0x36 * blocksize]

    if (length(key) > blocksize) then
        key = hash(key) // Where 'hash' is the underlying hash function
    end if

    for i from 0 to length(key) - 1
        ipad[i] = ipad[i] XOR key[i]
        opad[i] = opad[i] XOR key[i]
    end for

    return hash(opad || hash(ipad || message)) // Where || is concatenation
end function

代码逻辑和上面的公式是一致的,一共调用了2次hash函数,2次异或操作,2次concat操作。

唯一特别的是多了一个if的判断:如果key的长度比要求的blocksize还长,那么需要缩短,方法是用hash函数hash一下这个key,从而变成blocksize长度。

HMAC的图解如下(from wiki):

1.png

KDF, key derivation function, 密钥导出函数

KDF是加密系统中十分基本和必要的组件。KDF的任务是,给定某初始密钥材料(IKM,initial keying material),以及可选的salt,导出1或多个密码级强度的密钥

HKDF

HKDF是基于HMAC的KDF,功能上和其他KDF没什么区别。

HKDF分两个步骤:

  1. extract
  2. expand

extract

接口定义:

HKDF_Extract(salt, IKM) -> PRK

Options: Hash a hash function; HashLen denotes the length of the hash function output in octets

输入:

  • salt: 可选的“盐”,如果不提供,则默认为0串
  • IKM: 初始密钥材料

输出:

  • PRK: 定长的伪随机密钥

用HMAC_Hash(key, message)实现HKDF_Extract:

HMAC_Hash(salt, IKM) -> PRK

expand

接口定义:

HKDF_Expand(PRK, info, L) -> OKM

输入:

  • PRK:HKDF_Extract的输出
  • info:可选的上下文信息,默认是空字符串“”,当IKM被用于多种业务时,就可以用info来保证导出不一样的OKM
  • L:指定输出的OKM的字节长度,不能超过255*HashLen

输出:

  • OKM: 输出密钥材料

HKDF_Expand的伪代码:

   N = ceil(L/HashLen) // 向上取整,保证T的长度大于等于L
   T = T(1) | T(2) | T(3) | ... | T(N)
   OKM = first L octets of T // 裁剪成L个字节

   where:
   T(0) = empty string (zero length)
   T(1) = HMAC_Hash(PRK, T(0) || info || 0x01)
   T(2) = HMAC_Hash(PRK, T(1) || info || 0x02)
   T(3) = HMAC_Hash(PRK, T(2) || info || 0x03)
   ...

   // 0x01 0x02 0x03是递增的单字节常量

python实现HKDF

#!/usr/bin/env python3
import hashlib
import hmac
from math import ceil

hash_len = 32
def hmac_sha256(key, data):
    return hmac.new(key, data, hashlib.sha256).digest()

def hkdf(length, ikm, salt=b"", info=b""):
    prk = hmac_sha256(salt, ikm)
    t = b""
    okm = b""
    for i in range(ceil(length / hash_len)):
        t = hmac_sha256(prk, t + info + bytes([1+i]))
        okm += t
    return okm[:length]
(未经授权禁止转载)
Written on July 17, 2018

写作不易,您的支持是我写作的动力!