* @v ikm Input keying material
* @v ikm_len Length of input keying material
* @v prk Pseudorandom key to fill in
+ *
+ * The salt and input keying material are allowed to overlap the
+ * buffer that will be filled in with the pseudorandom key.
*/
void hkdf_extract ( struct digest_algorithm *digest, const void *salt,
size_t salt_len, const void *ikm, size_t ikm_len,
void *prk ) {
uint8_t ctx[ hmac_ctxsize ( digest ) ];
+ uint8_t zero[ digest->digestsize ];
/* Use all-zero salt if not specified */
if ( ! salt ) {
assert ( salt_len == 0 );
- salt_len = digest->digestsize;
- memset ( prk, 0, salt_len );
- salt = prk;
+ memset ( zero, 0, sizeof ( zero ) );
+ salt = zero;
+ salt_len = sizeof ( zero );
}
/* Calculate pseudorandom key */
* @v info_len Length of additional information
* @v out Output keying material
* @v len Length of output keying material
+ *
+ * The pseudorandom key and additional information are allowed to
+ * overlap the buffer that will be filled in with the output keying
+ * material, provided that the length of the output keying material is
+ * less than or equal to the length of the pseudorandom key.
+ *
+ * In particular, this allows hkdf_expand() to be used to create a new
+ * generation of pseudorandom key (i.e. to have the output keying
+ * material overwrite the existing pseudorandom key).
*/
void hkdf_expand ( struct digest_algorithm *digest, const void *prk,
const void *info, size_t info_len, void *out, size_t len ) {
static void hkdf_okx ( struct hkdf_test *test, const char *file,
unsigned int line ) {
size_t digestsize = test->digest->digestsize;
+ union {
+ uint8_t ikm[test->ikm_len];
+ uint8_t salt[test->salt_len];
+ uint8_t info[test->info_len];
+ uint8_t prk[test->prk_len];
+ uint8_t okm[test->okm_len];
+ } overlap;
uint8_t prk[digestsize];
uint8_t okm[test->okm_len];
+ size_t check_len;
/* Sanity checks */
okx ( ( test->salt != NULL ) || ( test->salt_len == 0 ), file, line );
/* Test expansion */
hkdf_expand ( test->digest, test->prk, test->info, test->info_len,
- okm, sizeof ( okm ) );
+ okm, test->okm_len );
okx ( memcmp ( okm, test->okm, test->okm_len ) == 0, file, line );
+
+ /* Test overlap between salt and pseudorandom key */
+ if ( test->salt ) {
+ memcpy ( overlap.salt, test->salt, test->salt_len );
+ hkdf_extract ( test->digest, overlap.salt, test->salt_len,
+ test->ikm, test->ikm_len, overlap.prk );
+ okx ( memcmp ( overlap.prk, test->prk, digestsize ) == 0,
+ file, line );
+ }
+
+ /* Test overlap between input keying material and pseudorandom key */
+ memcpy ( overlap.ikm, test->ikm, test->ikm_len );
+ hkdf_extract ( test->digest, test->salt, test->salt_len, overlap.ikm,
+ test->ikm_len, overlap.prk );
+ okx ( memcmp ( overlap.prk, test->prk, digestsize ) == 0,
+ file, line );
+
+ /* Calculate length for expansion overlap tests */
+ check_len = test->okm_len;
+ if ( check_len > digestsize )
+ check_len = digestsize;
+
+ /* Test overlap between pseudorandom key and output */
+ memcpy ( overlap.prk, test->prk, test->prk_len );
+ hkdf_expand ( test->digest, overlap.prk, test->info, test->info_len,
+ overlap.okm, test->okm_len );
+ okx ( memcmp ( overlap.okm, test->okm, check_len ) == 0, file, line );
+
+ /* Test overlap between additional information and output */
+ memcpy ( overlap.info, test->info, test->info_len );
+ hkdf_expand ( test->digest, test->prk, overlap.info, test->info_len,
+ overlap.okm, test->okm_len );
+ okx ( memcmp ( overlap.okm, test->okm, check_len ) == 0, file, line );
}
#define hkdf_ok( test ) hkdf_okx ( test, __FILE__, __LINE__ )