Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Changelog
:class:`~cryptography.hazmat.primitives.kdf.concatkdf.ConcatKDFHMAC`,
:class:`~cryptography.hazmat.primitives.kdf.argon2.Argon2id`,
:class:`~cryptography.hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC`,
:class:`~cryptography.hazmat.primitives.kdf.kbkdf.KBKDFHMAC`,
:class:`~cryptography.hazmat.primitives.kdf.scrypt.Scrypt`, and
:class:`~cryptography.hazmat.primitives.kdf.x963kdf.X963KDF` to allow
deriving keys directly into pre-allocated buffers.
Expand Down
32 changes: 30 additions & 2 deletions docs/hazmat/primitives/key-derivation-functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1090,13 +1090,40 @@ KBKDF
:raises TypeError: This exception is raised if ``key_material`` is
not ``bytes``.
:raises cryptography.exceptions.AlreadyFinalized: This is raised when
:meth:`derive` or
:meth:`derive`,
:meth:`derive_into`, or
:meth:`verify` is
called more than
once.

Derives a new key from the input key material.

.. method:: derive_into(key_material, buffer)

.. versionadded:: 47.0.0

:param key_material: The input key material.
:type key_material: :term:`bytes-like`
:param buffer: A writable buffer to write the derived key into. The
buffer must be equal to the length supplied in the
constructor.
:type buffer: :term:`bytes-like`
:return int: the number of bytes written to the buffer.
:raises ValueError: This exception is raised if the buffer length does
not match the specified ``length``.
:raises TypeError: This exception is raised if ``key_material`` or
``buffer`` is not ``bytes``.
:raises cryptography.exceptions.AlreadyFinalized: This is raised when
:meth:`derive`,
:meth:`derive_into`, or
:meth:`verify` is
called more than
once.

Derives a new key from the input key material and writes it into
the provided buffer. This is useful when you want to avoid allocating
new memory for the derived key.

.. method:: verify(key_material, expected_key)

:param bytes key_material: The input key material. This is the same as
Expand All @@ -1108,7 +1135,8 @@ KBKDF
derived key does not match
the expected key.
:raises cryptography.exceptions.AlreadyFinalized: This is raised when
:meth:`derive` or
:meth:`derive`,
:meth:`derive_into`, or
:meth:`verify` is
called more than
once.
Expand Down
21 changes: 21 additions & 0 deletions src/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import typing

from cryptography.hazmat.primitives.hashes import HashAlgorithm
from cryptography.hazmat.primitives.kdf.kbkdf import CounterLocation, Mode
from cryptography.utils import Buffer

class PBKDF2HMAC:
Expand Down Expand Up @@ -162,3 +163,23 @@ class ConcatKDFHMAC:
def derive(self, key_material: Buffer) -> bytes: ...
def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ...
def verify(self, key_material: bytes, expected_key: bytes) -> None: ...

class KBKDFHMAC:
def __init__(
self,
algorithm: HashAlgorithm,
mode: Mode,
length: int,
rlen: int,
llen: int | None,
location: CounterLocation,
label: bytes | None,
context: bytes | None,
fixed: bytes | None,
backend: typing.Any = None,
*,
break_location: int | None = None,
) -> None: ...
def derive(self, key_material: Buffer) -> bytes: ...
def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ...
def verify(self, key_material: bytes, expected_key: bytes) -> None: ...
67 changes: 4 additions & 63 deletions src/cryptography/hazmat/primitives/kdf/kbkdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,8 @@
UnsupportedAlgorithm,
_Reasons,
)
from cryptography.hazmat.primitives import (
ciphers,
cmac,
constant_time,
hashes,
hmac,
)
from cryptography.hazmat.bindings._rust import openssl as rust_openssl
from cryptography.hazmat.primitives import ciphers, cmac, constant_time
from cryptography.hazmat.primitives.kdf import KeyDerivationFunction


Expand Down Expand Up @@ -178,62 +173,8 @@ def _generate_fixed_input(self) -> bytes:
return b"".join([self._label, b"\x00", self._context, l_val])


class KBKDFHMAC(KeyDerivationFunction):
def __init__(
self,
algorithm: hashes.HashAlgorithm,
mode: Mode,
length: int,
rlen: int,
llen: int | None,
location: CounterLocation,
label: bytes | None,
context: bytes | None,
fixed: bytes | None,
backend: typing.Any = None,
*,
break_location: int | None = None,
):
if not isinstance(algorithm, hashes.HashAlgorithm):
raise UnsupportedAlgorithm(
"Algorithm supplied is not a supported hash algorithm.",
_Reasons.UNSUPPORTED_HASH,
)

from cryptography.hazmat.backends.openssl.backend import (
backend as ossl,
)

if not ossl.hmac_supported(algorithm):
raise UnsupportedAlgorithm(
"Algorithm supplied is not a supported hmac algorithm.",
_Reasons.UNSUPPORTED_HASH,
)

self._algorithm = algorithm

self._deriver = _KBKDFDeriver(
self._prf,
mode,
length,
rlen,
llen,
location,
break_location,
label,
context,
fixed,
)

def _prf(self, key_material: bytes) -> hmac.HMAC:
return hmac.HMAC(key_material, self._algorithm)

def derive(self, key_material: utils.Buffer) -> bytes:
return self._deriver.derive(key_material, self._algorithm.digest_size)

def verify(self, key_material: bytes, expected_key: bytes) -> None:
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
raise InvalidKey
KBKDFHMAC = rust_openssl.kdf.KBKDFHMAC
KeyDerivationFunction.register(KBKDFHMAC)


class KBKDFCMAC(KeyDerivationFunction):
Expand Down
Loading
Loading