-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Description
User may supply overlapping spans as arguments info
and output
to the method HKDF.Expand
. They may do so inadvertently or on purpose (e.g., if info
will be no longer needed, they may decide to write the output directly into info
to avoid unnecessary memory allocation for the output and reduce memory footprint). The method won't throw ArgumentException
.
Expand
writes output block-by-block, each block is generated by running the info
through HMAC. If spans output
and info
overlap, writing one of the output blocks will modify the info
and cause all the following output blocks (if any) to be invalid (computed for different info
).
DeriveKey
method uses Expand
under the hood, so it is subjected to this problem too.
Illustration
Example 1:
byte[] prk = new byte[32];
byte[] info = new byte[64];
byte[] output = info;
HKDF.Expand(HashAlgorithmName.SHA256, prk, output, info);
// Expected value of 'output':
// 224, 85, 77, 187, 82, 30, 209, 96, 139, 180, 92, 98, 118, 111, 136, 68, 14, 47, 58, 228, 103, 215, 77, 186, 31, 211, 151, 244, 164, 46, 152, 253, 22, 124, 57, 137, 118, 144, 212, 164, 130, 145, 153, 172, 244, 110, 232, 164, 185, 232, 55, 182, 160, 145, 30, 122, 59, 192, 132, 49, 71, 152, 88, 179
// Actual value of 'output':
// 224, 85, 77, 187, 82, 30, 209, 96, 139, 180, 92, 98, 118, 111, 136, 68, 14, 47, 58, 228, 103, 215, 77, 186, 31, 211, 151, 244, 164, 46, 152, 253, 28, 152, 182, 90, 167, 151, 73, 167, 4, 223, 241, 200, 117, 212, 10, 138, 15, 233, 197, 158, 185, 124, 47, 216, 204, 204, 129, 232, 30, 186, 204, 65
Example 2:
var ikm = new byte[32];
var salt = new byte[32];
var buffer = new byte[128];
var info = buffer.AsSpan().Slice(0, 64);
var output = buffer.AsSpan().Slice(60, 64);
HKDF.DeriveKey(HashAlgorithmName.SHA256, ikm, output, salt, info);
// Expected value of 'output':
// 172, 123, 193, 152, 101, 162, 17, 66, 171, 216, 98, 225, 37, 223, 75, 218, 132, 136, 71, 80, 12, 22, 125, 64, 63, 27, 212, 255, 132, 8, 36, 105, 171, 126, 54, 101, 167, 164, 84, 70, 178, 14, 209, 132, 190, 173, 9, 22, 29, 248, 138, 190, 251, 103, 106, 197, 210, 193, 39, 96, 213, 148, 221, 10
// Actual value of 'output':
// 172, 123, 193, 152, 101, 162, 17, 66, 171, 216, 98, 225, 37, 223, 75, 218, 132, 136, 71, 80, 12, 22, 125, 64, 63, 27, 212, 255, 132, 8, 36, 105, 183, 96, 0, 94, 58, 127, 93, 192, 187, 170, 243, 216, 48, 149, 108, 144, 141, 5, 245, 16, 12, 186, 172, 48, 12, 194, 237, 63, 200, 37, 231, 109
Suggested Solution
Suggestion 1:
Check whether the spans info
and output
overlap, and if they do, throw exception:
if (output.Overlaps(info))
throw new ArgumentException(...);
Suggestion 2:
Maybe it's a good idea to check all pairs of input and output spans in HKDF and throw exception if there's an overlap in any of them:
- In
Extract
-ikm
andprk
,salt
andprk
- In
Expand
-prk
andoutput
,info
andoutput
- In
DeriveKey
-ikm
andoutput
,salt
andoutput
,info
andoutput
This would make the API style more consistent and potentially safer, than if implementing only the info
-output
overlap check from the Suggestion 1.
I wasn't able to reproduce this issue with span pairs other than info
-output
, but I think it may be possible given different HMAC implementation.