Skip to content

Instantly share code, notes, and snippets.

@narfbg
Created February 3, 2014 22:09
Show Gist options
  • Save narfbg/8793435 to your computer and use it in GitHub Desktop.
Save narfbg/8793435 to your computer and use it in GitHub Desktop.
Experimental HKDF implementation for CodeIgniter's encryption class
/**
* HKDF
*
* @link https://tools.ietf.org/rfc/rfc5869.txt
* @param $key Input key
* @param $digest A SHA-2 hashing algorithm
* @param $salt Optional salt
* @param $length Output length (defaults to the selected digest size)
* @param $info Optional context/application-specific info
* @return string A pseudo-random key
*/
function hkdf($key, $digest = 'sha512', $salt = NULL, $length = NULL, $info = '')
{
if ( ! in_array($digest, array('sha224', 'sha256', 'sha384', 'sha512'), TRUE))
{
return FALSE;
}
$digest_length = substr($digest, 3) / 8;
if (empty($length) OR ! is_int($length))
{
$length = $digest_length;
}
elseif ($length > (255 * $digest_length))
{
return FALSE;
}
isset($salt) OR $salt = str_repeat("\0", substr($digest, 3) / 8);
$prk = hash_hmac($digest, $key, $salt, TRUE);
$key = '';
for ($key_block = '', $block_index = 1; strlen($key) < $length; $block_index++)
{
$key_block = hash_hmac($digest, $key_block.$info.chr($block_index), $prk, TRUE);
$key .= $key_block;
}
return substr($key, 0, $length);
}
@GDmac
Copy link

GDmac commented Feb 4, 2014

Test cases appendix A1 to A3 success (e.g. $R[1]==$OKM )

<?php
   // Appendix A1
   // Basic test case with SHA-256
   $hash = 'sha256';
   $IKM  = pack('H*','0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b'); // (22 octets)
   $salt = pack('H*','000102030405060708090a0b0c'); // (13 octets)
   $info = pack('H*','f0f1f2f3f4f5f6f7f8f9'); // (10 octets)
   $L    = 42;
   $PRK  = '077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5'; // (32 octets)
   $OKM  = '3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865'; // (42 octets)

   $R = hkdf($IKM, $hash, $salt, $L, $info);
   $R = unpack('H*', $R);   
   var_dump( $R[1], $OKM, $R[1]==$OKM );


   // Appendix A1
   // Test with SHA-256 and longer inputs/outputs
   $hash = 'sha256';
   $IKM  = pack('H*','000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f'); // (80 octets)
   $salt = pack('H*','606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf'); // (80 octets)
   $info = pack('H*','b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'); // (80 octets)
   $L    = 82;
   $PRK  = '06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244'; // (32 octets)
   $OKM  = 'b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87'; // (82 octets)

   $R = hkdf($IKM, $hash, $salt, $L, $info);
   $R = unpack('H*', $R);      
   var_dump( $R[1], $OKM, $R[1]==$OKM );


   // Appendix 3
   // Test with SHA-256 and zero-length salt/info
   $hash = 'sha256';
   $IKM  = pack('H*','0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b');// (22 octets)
   $salt = null; // (0 octets)
   $info = null; //(0 octets)
   $L    = 42;
   $PRK  = '19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04';// (32 octets)
   $OKM  = '8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8';// (42 octets)
   $R = hkdf($IKM, $hash, $salt, $L, $info);
   $R = unpack('H*', $R);   
   var_dump( $R[1], $OKM, $R[1]==$OKM );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment