NAME

Crypt::Sodium::XS::OO::hkdf - HMAC-based Extract-and-Expand Key Derivation Function

SYNOPSIS

use Crypt::Sodium::XS;
my $hkdf = Crypt::Sodium::XS->hkdf(primitive => 'sha256');

my $ikm = "any source and length of data with reasonable entropy";
my $salt = "salt is optional.";

my $prk = $hkdf->extract($ikm, $salt);

my $application_key_1 = $hkdf->expand($prk, "application one");
my $application_key_2 = $hkdf->expand($prk, "application two");

my $multipart = $hkdf->extract_init($salt);
$multipart->update("initial");
$multipart->update(" key material", " added in parts");
$prk = $multipart->final;
...

DESCRIPTION

NOTE: Secret keys used to encrypt or sign confidential data have to be chosen from a very large keyspace. However, passwords are usually short, human-generated strings, making dictionary attacks practical. If you are intending to derive keys from a password, see Crypt::Sodium::XS::pwhash instead.

HKDF (HMAC-based Extract-and-Expand Key Derivation Function) is a key derivation function used by many standard protocols. It actually includes two operations:

extract

This operation absorbs an arbitrary-long sequence of bytes and outputs a fixed-size master key (also known as PRK), suitable for use with the second function (expand).

expand

This operation generates an variable size subkey given a master key (also known as PRK) and a description of a key (or "context") to derive from it. That operation can be repeated with different descriptions in order to derive as many keys as necessary.

The latter can be used without the former, if a randomly sampled key of the right size is already available (e.g., from "keygen").

CONSTRUCTOR

new

my $hkdf = Crypt::Sodium::XS::OO::hkdf->new(primitive => 'sha256');
my $hkdf = Crypt::Sodium::XS->hkdf(primitive => 'sha512');

Returns a new hkdf object for the given primitive. The primitive argument is required.

METHODS

BYTES_MAX

Maximum length of output from "expand" functions.

BYTES_MIN

Defined by libsodium to be 0.

KEYBYTES

Length in bytes of both master keys (PRK) and "keygen" function output.

available

my $has_hkdf = $hkdf->available;

Indicates the availability of HKDF in the linked version of libsodium. It is a good idea to test for availability, as at time of writing it is only available in the most recent library version and may not yet be widely deployed.

expand

my $subkey = $hkdf->expand($prk, $out_len);
my $subkey = $hkdf->expand($prk, $out_len, $context);

This function derives a subkey of length $out_len from a context/description $context and a master key $prk.

Up to "BYTES_MAX" bytes can be produced.

The generated keys satifsy the typical requirements of keys used for symmetric cryptography. In particular, they appear to be sampled from a uniform distribution over the entire range of possible keys. Contexts don’t have to secret. They just need to be distinct in order to produce distinct keys from the same master key.

Any "KEYBYTES" bytes key that appears to be sampled from a uniform distribution can be used for the prk. For example, the output of a key exchange mechanism (such as from Crypt::Sodium::XS::kx) can be used as a master key. For convenience, the "keygen" function creates a random prk. The master key should remain secret.

This function is effectively a standard alternative to Crypt::Sodium::XS::kdf::derive_from_key. It is slower, but the context can be of any size.

extract

my $prk = $hkdf->extract($ikm);
my $prk = $hkdf->extract($ikm, $salt);

Creates a master key (prk) given Input Keying Material (IKM) <$ikm> and $salt.

$salt is optional. It can be a public, unique identifier for a protocol or application. Its purpose is to ensure that distinct keys will be created even if the input keying material is accidentally reused across protocols.

A UUID is a decent example of a salt. There is no minimum length.

If input keying material cannot be accidentally reused, using an empty (undef or empty string) salt is perfectly acceptable. IKM is an arbitrary-long byte sequence. The bytes don’t have to be sampled from a uniform distribution. It can be any combination of text and binary data.

But the overall sequence needs to include some entropy.

The resulting PRK will roughly have the same entropy. The “extract” operation effectively extracts the entropy and packs it into a fixed-size key, but it doesn’t add any entropy.

extract_init

my $multipart = $hkdf->extract_init($salt);

$salt is optional. It can be a public, unique identifier for a protocol or application. Its purpose is to ensure that distinct keys will be created even if the input keying material is accidentally reused across protocols.

Returns a multipart hkdf object. See the notes in "extract" and "MULTI-PART INTERFACE".

keygen

my $ikm = $hkdf->keygen;

MULTI-PART INTERFACE

To extract a pseudorandom key from an arbitrary length of initial key material, you may wish to use the multi-part interface. A multipart hkdf object is created by calling the "extract_init" method with optional salt. Key material can be added by calling the </update> method of that object as many times as desired. An output master key (prk) is generated by calling its "final" method. Do not continue to use the object after calling "final".

The precalculated hkdf object is an opaque object which provides the following methods:

final

my $prk = $multipart->final;

update

$multipart->update($key_data);
$multipart->update(@key_data);

SEE ALSO

Crypt::Sodium::XS
Crypt::Sodium::XS::hkdf
https://doc.libsodium.org/key_derivation/hkdf

FEEDBACK

For reporting bugs, giving feedback, submitting patches, etc. please use the following:

AUTHOR

Brad Barden <perlmodules@5c30.org>

COPYRIGHT & LICENSE

Copyright (c) 2024 Brad Barden. All rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.