private byte[] CreateContextHeader() { var retVal = new byte[checked ( 1 /* KDF alg */ + 1 /* chaining mode */ + sizeof(uint) /* sym alg key size */ + sizeof(uint) /* sym alg block size */ + sizeof(uint) /* hmac alg key size */ + sizeof(uint) /* hmac alg digest size */ + _symmetricAlgorithmBlockSizeInBytes /* ciphertext of encrypted empty string */ + _hmacAlgorithmDigestLengthInBytes /* digest of HMACed empty string */)]; fixed(byte *pbRetVal = retVal) { byte *ptr = pbRetVal; // First is the two-byte header *(ptr++) = 0; // 0x00 = SP800-108 CTR KDF w/ HMACSHA512 PRF *(ptr++) = 0; // 0x00 = CBC encryption + HMAC authentication // Next is information about the symmetric algorithm (key size followed by block size) BitHelpers.WriteTo(ref ptr, _symmetricAlgorithmSubkeyLengthInBytes); BitHelpers.WriteTo(ref ptr, _symmetricAlgorithmBlockSizeInBytes); // Next is information about the HMAC algorithm (key size followed by digest size) BitHelpers.WriteTo(ref ptr, _hmacAlgorithmSubkeyLengthInBytes); BitHelpers.WriteTo(ref ptr, _hmacAlgorithmDigestLengthInBytes); // See the design document for an explanation of the following code. var tempKeys = new byte[_symmetricAlgorithmSubkeyLengthInBytes + _hmacAlgorithmSubkeyLengthInBytes]; fixed(byte *pbTempKeys = tempKeys) { byte dummy; // Derive temporary keys for encryption + HMAC. using (var provider = SP800_108_CTR_HMACSHA512Util.CreateEmptyProvider()) { provider.DeriveKey( pbLabel: &dummy, cbLabel: 0, pbContext: &dummy, cbContext: 0, pbDerivedKey: pbTempKeys, cbDerivedKey: (uint)tempKeys.Length); } // At this point, tempKeys := { K_E || K_H }. byte *pbSymmetricEncryptionSubkey = pbTempKeys; byte *pbHmacSubkey = &pbTempKeys[_symmetricAlgorithmSubkeyLengthInBytes]; // Encrypt a zero-length input string with an all-zero IV and copy the ciphertext to the return buffer. using (var symmetricKeyHandle = _symmetricAlgorithmHandle.GenerateSymmetricKey(pbSymmetricEncryptionSubkey, _symmetricAlgorithmSubkeyLengthInBytes)) { fixed(byte *pbIV = new byte[_symmetricAlgorithmBlockSizeInBytes] /* will be zero-initialized */) { DoCbcEncrypt( symmetricKeyHandle: symmetricKeyHandle, pbIV: pbIV, pbInput: &dummy, cbInput: 0, pbOutput: ptr, cbOutput: _symmetricAlgorithmBlockSizeInBytes); } } ptr += _symmetricAlgorithmBlockSizeInBytes; // MAC a zero-length input string and copy the digest to the return buffer. using (var hashHandle = _hmacAlgorithmHandle.CreateHmac(pbHmacSubkey, _hmacAlgorithmSubkeyLengthInBytes)) { hashHandle.HashData( pbInput: &dummy, cbInput: 0, pbHashDigest: ptr, cbHashDigest: _hmacAlgorithmDigestLengthInBytes); } ptr += _hmacAlgorithmDigestLengthInBytes; CryptoUtil.Assert(ptr - pbRetVal == retVal.Length, "ptr - pbRetVal == retVal.Length"); } } // retVal := { version || chainingMode || symAlgKeySize || symAlgBlockSize || hmacAlgKeySize || hmacAlgDigestSize || E("") || MAC("") }. return(retVal); }