Python code using HMAC library

Asked

Viewed 251 times

2

I’m doing a paper on cryptography for college using HMAC along with SHA256, and I’d like to understand what this code does on each line, I’m a little confused.

#!/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]

2 answers

0


Although the reply of @Marcelo Uchimura answers the question, I think it does not answer what the code is for, even mentions that this would be for messages, where it is not a point.


HKDF is a KDF using HMAC, there’s a definition of it here. Well, a KDF has as input a data "not so random" and another data, this is uniformly random. A good example of use is when a key is awakened via ECDH, since the key is "mathematical answer", so it is not indistinguishable from completely random data, so the use of KDF is necessary. Similarly, you may want to have multiple keys using only one, so HKDF can also be used, *even if the key needs to more bytes than the original value.*


The HKDF is divided into two parts, one the extractor and the other the expander. This is the extractor:

prk = hmac_sha256(salt, ikm)

The idea here is to include the salt and the ikm. Presumes that the salt is distinguishable from a uniformly random datum, whereas the ikm maybe it is, but it doesn’t have to be.

Its result, the prk, is a uniformly random datum, assuming that the hmac_sha256 is a safe PRF, or that at least the SHA256 compression is a PRF.

After that we have the expander, that consumes the prk, he’s in:

for i in range(ceil(length / hash_len)):

    t = hmac_sha256(prk, t + info + bytes([1+i]))

Note that the prk is used as a key in this step. That is, the key generated by the extractor is used in the expander. The expander will create n required bytes, so there is the range to repeat the process until it reaches the required amount of bytes.

This process is formally described as:

K(1) = HMAC(PRK, CTXinfo || 0),
K(i + 1) = HMAC(PRK, K(i) || CTXinfo || i), 1 ≤ i < t,

The CTXinfo is additional information, may be omitted. So basically the input of HMAC is: the previous result (if i > 1) concatenated with the information added and concatenated with i, being i a single byte, sequential.

In the case of this implementation, as defined in t = b"", there will be no difference between the first or last execution.

Finally the okm[:length] will only cut the output, since the hash has fixed size (in the case of SHA-256), so if you want nonmultiple values of 256, for example, you won’t be able to without truncating.

0

If I’m right, this is how it works:

# Comentários na linha de cima à linha comentada.

import hashlib
import hmac
from math import ceil

# As palavras vão ter 32 bytes.
hash_len = 32

# Define um método que aplica SHA256 com a key e os data informados.
def hmac_sha256(key, data):
    return hmac.new(key, data, hashlib.sha256).digest()

# Cria um HMAC do tamanho length, com a chave ikm, o sal salt e uma informação, também usada para a criação do HMAC, info.
def hkdf(length, ikm, salt=b"", info=b""):

    # Gera uma chave preliminar com o salt e o ikm informados.
    prk = hmac_sha256(salt, ikm)

    # Declara um espaçador t.
    t = b""

    # Declara o HMAC final okm.
    okm = b""

    # Laço para gerar o HMAC; itera-se sobre um vetor [0..ceil(length / 32)]
    for i in range(ceil(length / hash_len)):
        # O espaçador guarda o resultado do algoritmo de hashing
        # a cada iteração, usando como base para tal a si próprio,
        # a info e um vetor de zeros de tamanho variável, apenas
        # como preenchedor (para que t não fique viciado).
        t = hmac_sha256(prk, t + info + bytes([1+i]))

        # Concatena t em okm
        okm += t

    # Recorta okm do tamanho length informado.
    return okm[:length]

As HMAC accompanies the signed message at all times of the message exchange, the fact that HMAC is truncated is not significant, because it can be checked at any time if the receiver of the message has the same length, ikm, salt and info passed as a parameter of hkdf(), which must also be known by the receiving side.

  • Thank you very much! Now I understand!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.