Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Crypto.Protocol.KDF.HKDFExpand #808

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Doc/src/protocol/kdf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,24 @@ Example, for deriving two AES256 keys::

.. autofunction:: Crypto.Protocol.KDF.HKDF

.. _hkdfexpand:

HKDFExpand
+++++

HKDF consists of two stages, extract and expand. This class exposes an
expand only version of HKDF that is suitable when the key material is
already cryptographically strong.

Example, for deriving a key with context::

from Crypto.Protocol.KDF import HKDFExpand
from Crypto.Hash import SHA512

app_key = HKDFExpand(pseudorandom_key, 32, SHA512, context=b"app key")

.. autofunction:: Crypto.Protocol.KDF.HKDFExpand

.. _sp800-180-counter:

SP 800-180 Counter Mode
Expand Down
40 changes: 37 additions & 3 deletions lib/Crypto/Protocol/KDF.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,14 +315,49 @@ def HKDF(master, key_len, salt, hashmod, num_keys=1, context=None):
raise ValueError("Too much secret data to derive")
if not salt:
salt = b'\x00' * hashmod.digest_size
if context is None:
context = b""

# Step 1: extract
hmac = HMAC.new(salt, master, digestmod=hashmod)
prk = hmac.digest()

# Step 2: expand
return HKDFExpand(prk, key_len, hashmod, num_keys, context)


def HKDFExpand(prk, key_len, hashmod, num_keys=1, context=None):
"""HKDF consists of two stages, extract and expand.
This class exposes an expand only version of HKDF that
is suitable when the key material is already
cryptographically strong.

Args:
prk (byte string):
Short, cryptographically strong, pseudorandom key material.
It must not be a password.
key_len (integer):
The length in bytes of every derived key.
hashmod (module):
A cryptographic hash algorithm from :mod:`Crypto.Hash`.
:mod:`Crypto.Hash.SHA512` is a good choice.
num_keys (integer):
The number of keys to derive. Every key is :data:`key_len` bytes long.
The maximum cumulative length of all keys is
255 times the digest size.
context (byte string):
Optional identifier describing what the keys are used for.

Return:
A byte string or a tuple of byte strings.

.. _RFC5869: http://tools.ietf.org/html/rfc5869
"""

output_len = key_len * num_keys
if output_len > (255 * hashmod.digest_size):
raise ValueError("Too much secret data to derive")
if context is None:
context = b""

t = [ b"" ]
n = 1
tlen = 0
Expand All @@ -339,7 +374,6 @@ def HKDF(master, key_len, salt, hashmod, num_keys=1, context=None):
return list(kol[:num_keys])



def scrypt(password, salt, key_len, N, r, p, num_keys=1):
"""Derive one or more keys from a passphrase.

Expand Down
1 change: 1 addition & 0 deletions lib/Crypto/Protocol/KDF.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class _S2V(object):
def derive(self) -> bytes: ...

def HKDF(master: bytes, key_len: int, salt: bytes, hashmod: ModuleType, num_keys: Optional[int]=1, context: Optional[bytes]=None) -> Union[bytes, Tuple[bytes, ...]]: ...
def HKDFExpand(prk: bytes, key_len: int, hashmod: ModuleType, num_keys: Optional[int]=1, context: Optional[bytes]=None) -> Union[bytes, Tuple[bytes, ...]]: ...

def scrypt(password: str, salt: str, key_len: int, N: int, r: int, p: int, num_keys: Optional[int]=1) -> Union[bytes, Tuple[bytes, ...]]: ...

Expand Down
Loading