465 lines
17 KiB
C++
465 lines
17 KiB
C++
// Copyright (c) 1996-2020, Live Networks, Inc. All rights reserved
|
|
// This code may not be copied or used in any form without permission from Live Networks, Inc.
|
|
//
|
|
// The SRTP 'Cryptographic Context', used in all of our uses of SRTP.
|
|
// Implementation
|
|
|
|
#include "SRTPCryptographicContext.hh"
|
|
#ifndef NO_OPENSSL
|
|
#include "HMAC_SHA1.hh"
|
|
#include <openssl/aes.h>
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
SRTPCryptographicContext
|
|
::SRTPCryptographicContext(MIKEYState const& mikeyState)
|
|
#ifndef NO_OPENSSL
|
|
: fMIKEYState(mikeyState),
|
|
fHaveReceivedSRTPPackets(False), fSRTCPIndex(0) {
|
|
// Begin by doing a key derivation, to generate the keying data that we need:
|
|
performKeyDerivation();
|
|
#else
|
|
{
|
|
#endif
|
|
}
|
|
|
|
SRTPCryptographicContext::~SRTPCryptographicContext() {
|
|
}
|
|
|
|
Boolean SRTPCryptographicContext
|
|
::processIncomingSRTPPacket(u_int8_t* buffer, unsigned inPacketSize,
|
|
unsigned& outPacketSize) {
|
|
#ifndef NO_OPENSSL
|
|
do {
|
|
if (inPacketSize < 12) { // For SRTP, 12 is the minimum packet size (if unauthenticated)
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "SRTPCryptographicContext::processIncomingSRTPPacket(): Error: Packet size %d is too short for SRTP!\n", inPacketSize);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
unsigned const numBytesPastEncryption
|
|
= SRTP_MKI_LENGTH + (weAuthenticate() ? SRTP_AUTH_TAG_LENGTH : 0);
|
|
if (inPacketSize <= numBytesPastEncryption) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "SRTPCryptographicContext::processIncomingSRTPPacket(): Error: Packet size %d is too short for encrpytion and/or authentication!\n", inPacketSize);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
// Begin by figuring out this packet's 'index' (ROC and RTP sequence number),
|
|
// and the ROC and RTP sequence number that will be used subsequently, provided that
|
|
// this packet authenticates OK:
|
|
u_int16_t const rtpSeqNum = (buffer[2]<<8)|buffer[3];
|
|
u_int32_t nextROC, thisPacketsROC;
|
|
u_int16_t nextHighRTPSeqNum;
|
|
|
|
if (!fHaveReceivedSRTPPackets) {
|
|
// First time:
|
|
nextROC = thisPacketsROC = fROC = 0;
|
|
nextHighRTPSeqNum = rtpSeqNum;
|
|
} else {
|
|
// Check whether the sequence number has rolled over, or is out-of-order:
|
|
u_int16_t const SEQ_NUM_THRESHOLD = 0x1000;
|
|
if (rtpSeqNum >= fPreviousHighRTPSeqNum) {
|
|
// normal case, or out-of-order packet that crosses a rollover:
|
|
if (rtpSeqNum - fPreviousHighRTPSeqNum < SEQ_NUM_THRESHOLD) {
|
|
// normal case:
|
|
nextROC = thisPacketsROC = fROC;
|
|
nextHighRTPSeqNum = rtpSeqNum;
|
|
} else {
|
|
// out-of-order packet that crosses rollover:
|
|
nextROC = fROC;
|
|
thisPacketsROC = fROC-1;
|
|
nextHighRTPSeqNum = fPreviousHighRTPSeqNum;
|
|
}
|
|
} else {
|
|
// rollover, or out-of-order packet that crosses a rollover:
|
|
if (fPreviousHighRTPSeqNum - rtpSeqNum > SEQ_NUM_THRESHOLD) {
|
|
// rollover:
|
|
nextROC = thisPacketsROC = fROC+1;
|
|
nextHighRTPSeqNum = rtpSeqNum;
|
|
} else {
|
|
// out-of-order packet (that doesn't cross a rollover):
|
|
nextROC = thisPacketsROC = fROC;
|
|
nextHighRTPSeqNum = fPreviousHighRTPSeqNum;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (weAuthenticate()) {
|
|
// Authenticate the packet.
|
|
unsigned const numBytesToAuthenticate
|
|
= inPacketSize - (SRTP_MKI_LENGTH + SRTP_AUTH_TAG_LENGTH); // ASSERT: > 0
|
|
u_int8_t const* authenticationTag = &buffer[inPacketSize - SRTP_AUTH_TAG_LENGTH];
|
|
|
|
if (!verifySRTPAuthenticationTag(buffer, numBytesToAuthenticate, thisPacketsROC, authenticationTag)) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "SRTPCryptographicContext::processIncomingSRTPPacket(): Failed to authenticate incoming SRTP packet!\n");
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Now that we've verified the packet, set the 'index values' for next time:
|
|
fROC = nextROC;
|
|
fPreviousHighRTPSeqNum = nextHighRTPSeqNum;
|
|
fHaveReceivedSRTPPackets = True;
|
|
|
|
if (weEncryptSRTP()) {
|
|
// Decrypt the SRTP packet. It has the index "thisPacketsROC" with "rtpSeqNum":
|
|
u_int64_t index = (thisPacketsROC<<16)|rtpSeqNum;
|
|
|
|
// Figure out the RTP header size. This will tell us which bytes to decrypt:
|
|
unsigned rtpHeaderSize = 12; // at least the basic 12-byte header
|
|
rtpHeaderSize += (buffer[0]&0x0F)*4; // # CSRC identifiers
|
|
if ((buffer[0]&0x10) != 0) {
|
|
// There's a RTP extension header. Add its size:
|
|
if (inPacketSize < rtpHeaderSize + 4) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "SRTPCryptographicContext::processIncomingSRTPPacket(): Error: Packet size %d is shorter than the minimum specified RTP header size %d!\n", inPacketSize, rtpHeaderSize + 4);
|
|
#endif
|
|
break;
|
|
}
|
|
u_int16_t hdrExtLength = (buffer[rtpHeaderSize+2]<<8)|buffer[rtpHeaderSize+3];
|
|
rtpHeaderSize += 4 + hdrExtLength*4;
|
|
}
|
|
|
|
unsigned const offsetToEncryptedBytes = rtpHeaderSize;
|
|
unsigned numEncryptedBytes = inPacketSize - numBytesPastEncryption; // ASSERT: > 0
|
|
if (offsetToEncryptedBytes > numEncryptedBytes) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "SRTPCryptographicContext::processIncomingSRTPPacket(): Error: RTP header size %d (expected <= %d) is too large!\n", rtpHeaderSize, numEncryptedBytes);
|
|
#endif
|
|
break;
|
|
}
|
|
numEncryptedBytes -= offsetToEncryptedBytes;
|
|
|
|
u_int32_t const SSRC = (buffer[8]<<24)|(buffer[9]<<16)|(buffer[10]<<8)|buffer[11];
|
|
decryptSRTPPacket(index, SSRC, &buffer[offsetToEncryptedBytes], numEncryptedBytes);
|
|
outPacketSize = inPacketSize - numBytesPastEncryption; // trim to what we use
|
|
}
|
|
|
|
return True;
|
|
} while (0);
|
|
#endif
|
|
|
|
// An error occurred in the handling of the packet:
|
|
return False;
|
|
}
|
|
|
|
Boolean SRTPCryptographicContext
|
|
::processIncomingSRTCPPacket(u_int8_t* buffer, unsigned inPacketSize,
|
|
unsigned& outPacketSize) {
|
|
#ifndef NO_OPENSSL
|
|
do {
|
|
if (inPacketSize < 12) {
|
|
// For SRTCP, 8 is the minumum RTCP packet size, but there's also a mandatory
|
|
// 4-byte "E+SRTCP index" word.
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "SRTPCryptographicContext::processIncomingSRTCPPacket(): Error: Packet size %d is too short for SRTCP!\n", inPacketSize);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
unsigned const numBytesPastEncryption
|
|
= 4/*E+SRTCP index*/ + SRTP_MKI_LENGTH + (weAuthenticate() ? SRTP_AUTH_TAG_LENGTH : 0);
|
|
if (inPacketSize <= numBytesPastEncryption) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "SRTPCryptographicContext::processIncomingSRTCPPacket(): Error: Packet size %d is too short for encrpytion and/or authentication!\n", inPacketSize);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
if (weAuthenticate()) {
|
|
// Authenticate the packet.
|
|
unsigned const numBytesToAuthenticate
|
|
= inPacketSize - (SRTP_MKI_LENGTH + SRTP_AUTH_TAG_LENGTH); // ASSERT: > 0
|
|
u_int8_t const* authenticationTag = &buffer[inPacketSize - SRTP_AUTH_TAG_LENGTH];
|
|
|
|
if (!verifySRTCPAuthenticationTag(buffer, numBytesToAuthenticate, authenticationTag)) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "SRTPCryptographicContext::processIncomingSRTCPPacket(): Failed to authenticate incoming SRTCP packet!\n");
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (weEncryptSRTCP()) {
|
|
// Decrypt the SRTCP packet:
|
|
unsigned numEncryptedBytes = inPacketSize - numBytesPastEncryption; // ASSERT: > 0
|
|
u_int8_t const* p = &buffer[numEncryptedBytes]; // E + SRTCP index
|
|
u_int32_t E_plus_SRTCPIndex = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
|
|
if ((E_plus_SRTCPIndex&0x80000000) != 0) {
|
|
// The packet is encrypted
|
|
unsigned const offsetToEncryptedBytes = 8;
|
|
if (offsetToEncryptedBytes > numEncryptedBytes) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "SRTPCryptographicContext::processIncomingSRTCPPacket(): Error: RTCP packet size %d is too small!\n", numEncryptedBytes);
|
|
#endif
|
|
break;
|
|
}
|
|
numEncryptedBytes -= offsetToEncryptedBytes;
|
|
|
|
u_int32_t index = E_plus_SRTCPIndex&0x7FFFFFFF;
|
|
u_int32_t const SSRC = (buffer[4]<<24)|(buffer[5]<<16)|(buffer[6]<<8)|buffer[7];
|
|
decryptSRTCPPacket(index, SSRC, &buffer[offsetToEncryptedBytes], numEncryptedBytes);
|
|
}
|
|
outPacketSize = inPacketSize - numBytesPastEncryption; // trim to what we use
|
|
}
|
|
|
|
return True;
|
|
} while (0);
|
|
#endif
|
|
|
|
// An error occurred in the handling of the packet:
|
|
return False;
|
|
}
|
|
|
|
Boolean SRTPCryptographicContext
|
|
::processOutgoingSRTCPPacket(u_int8_t* buffer, unsigned inPacketSize,
|
|
unsigned& outPacketSize) {
|
|
#ifndef NO_OPENSSL
|
|
do {
|
|
// Encrypt the appropriate part of the packet.
|
|
u_int8_t eFlag = 0x00;
|
|
if (weEncryptSRTCP()) {
|
|
unsigned const unencryptedHeaderSize = 8;
|
|
if (inPacketSize < unencryptedHeaderSize) { // packet is too small
|
|
// Hack: Let small, non RTCP packets through w/o encryption; they may be used to
|
|
// punch through NATs
|
|
outPacketSize = inPacketSize;
|
|
return True;
|
|
}
|
|
unsigned const encryptedDataSize = inPacketSize - unencryptedHeaderSize;
|
|
|
|
u_int8_t* const dataToEncrypt = &buffer[unencryptedHeaderSize];
|
|
u_int32_t const ssrc = (buffer[4]<<24)|(buffer[5]<<16)|(buffer[6]<<8)|buffer[7];
|
|
encryptSRTCPPacket(fSRTCPIndex, ssrc, dataToEncrypt, encryptedDataSize);
|
|
eFlag = 0x80;
|
|
}
|
|
|
|
outPacketSize = inPacketSize; // initially
|
|
|
|
// Add 4 bytes for the 'E' flag and SRTCP index:
|
|
buffer[outPacketSize++] = (fSRTCPIndex>>24)|eFlag;
|
|
buffer[outPacketSize++] = fSRTCPIndex>>16;
|
|
buffer[outPacketSize++] = fSRTCPIndex>>8;
|
|
buffer[outPacketSize++] = fSRTCPIndex;
|
|
++fSRTCPIndex; // for next time
|
|
|
|
// Add the MKI:
|
|
buffer[outPacketSize++] = MKI()>>24;
|
|
buffer[outPacketSize++] = MKI()>>16;
|
|
buffer[outPacketSize++] = MKI()>>8;
|
|
buffer[outPacketSize++] = MKI();
|
|
|
|
// Generate and add an authentication tag over the data built so far (except the MKI)
|
|
outPacketSize += generateSRTCPAuthenticationTag(buffer, outPacketSize-SRTP_MKI_LENGTH,
|
|
&buffer[outPacketSize]);
|
|
|
|
return True;
|
|
} while (0);
|
|
#endif
|
|
|
|
// An error occurred:
|
|
return False;
|
|
}
|
|
|
|
#ifndef NO_OPENSSL
|
|
unsigned SRTPCryptographicContext
|
|
::generateSRTCPAuthenticationTag(u_int8_t const* dataToAuthenticate, unsigned numBytesToAuthenticate,
|
|
u_int8_t* resultAuthenticationTag) {
|
|
return generateAuthenticationTag(fDerivedKeys.srtcp, dataToAuthenticate, numBytesToAuthenticate,
|
|
resultAuthenticationTag);
|
|
}
|
|
|
|
Boolean SRTPCryptographicContext
|
|
::verifySRTPAuthenticationTag(u_int8_t* dataToAuthenticate, unsigned numBytesToAuthenticate,
|
|
u_int32_t roc, u_int8_t const* authenticationTag) {
|
|
// Append the (4-byte) 'ROC' (roll-over counter) to "dataToAuthenticate" before computing
|
|
// the authentication tag. We can do this because we have enough space after
|
|
// "dataToAuthenticate":
|
|
// - If we're encrypted, then there's assumed to be a (4-byte) MKI there. Just overwrite
|
|
// that. (If we need the MKI, we could copy it beforehand; later, allow for there being
|
|
// no MKI #####)
|
|
// - If we're not encrypted, then the ROC will overwrite part of the existing
|
|
// authentication tag, so we need to make a copy of this.
|
|
u_int8_t const* existingAuthenticationTag;
|
|
Boolean haveMKI = True; // later, allow for there being no MKI #####
|
|
u_int8_t authenticationTagCopy[SRTP_AUTH_TAG_LENGTH];
|
|
|
|
if (fMIKEYState.encryptSRTP() && haveMKI) {
|
|
existingAuthenticationTag = authenticationTag;
|
|
} else {
|
|
memcpy(authenticationTagCopy, authenticationTag, sizeof authenticationTagCopy);
|
|
existingAuthenticationTag = authenticationTagCopy;
|
|
}
|
|
|
|
dataToAuthenticate[numBytesToAuthenticate++] = roc>>24;
|
|
dataToAuthenticate[numBytesToAuthenticate++] = roc>>16;
|
|
dataToAuthenticate[numBytesToAuthenticate++] = roc>>8;
|
|
dataToAuthenticate[numBytesToAuthenticate++] = roc;
|
|
|
|
return verifyAuthenticationTag(fDerivedKeys.srtp,
|
|
dataToAuthenticate, numBytesToAuthenticate,
|
|
existingAuthenticationTag);
|
|
}
|
|
|
|
Boolean SRTPCryptographicContext
|
|
::verifySRTCPAuthenticationTag(u_int8_t const* dataToAuthenticate, unsigned numBytesToAuthenticate,
|
|
u_int8_t const* authenticationTag) {
|
|
return verifyAuthenticationTag(fDerivedKeys.srtcp,
|
|
dataToAuthenticate, numBytesToAuthenticate,
|
|
authenticationTag);
|
|
}
|
|
|
|
void SRTPCryptographicContext
|
|
::decryptSRTPPacket(u_int64_t index, u_int32_t ssrc, u_int8_t* data, unsigned numDataBytes) {
|
|
cryptData(fDerivedKeys.srtp, index, ssrc, data, numDataBytes);
|
|
}
|
|
|
|
void SRTPCryptographicContext
|
|
::decryptSRTCPPacket(u_int32_t index, u_int32_t ssrc, u_int8_t* data, unsigned numDataBytes) {
|
|
cryptData(fDerivedKeys.srtcp, (u_int64_t)index, ssrc, data, numDataBytes);
|
|
}
|
|
|
|
void SRTPCryptographicContext
|
|
::encryptSRTCPPacket(u_int32_t index, u_int32_t ssrc, u_int8_t* data, unsigned numDataBytes) {
|
|
cryptData(fDerivedKeys.srtcp, (u_int64_t)index, ssrc, data, numDataBytes);
|
|
}
|
|
|
|
unsigned SRTPCryptographicContext
|
|
::generateAuthenticationTag(derivedKeys& keysToUse,
|
|
u_int8_t const* dataToAuthenticate, unsigned numBytesToAuthenticate,
|
|
u_int8_t* resultAuthenticationTag) {
|
|
if (SRTP_AUTH_TAG_LENGTH > SHA1_DIGEST_LEN) return 0; // sanity check; shouldn't happen
|
|
u_int8_t computedAuthTag[SHA1_DIGEST_LEN];
|
|
HMAC_SHA1(keysToUse.authKey, sizeof keysToUse.authKey,
|
|
dataToAuthenticate, numBytesToAuthenticate,
|
|
computedAuthTag);
|
|
|
|
for (unsigned i = 0; i < SRTP_AUTH_TAG_LENGTH; ++i) {
|
|
resultAuthenticationTag[i] = computedAuthTag[i];
|
|
}
|
|
|
|
return SRTP_AUTH_TAG_LENGTH;
|
|
}
|
|
|
|
Boolean SRTPCryptographicContext
|
|
::verifyAuthenticationTag(derivedKeys& keysToUse,
|
|
u_int8_t const* dataToAuthenticate, unsigned numBytesToAuthenticate,
|
|
u_int8_t const* authenticationTag) {
|
|
u_int8_t computedAuthTag[SHA1_DIGEST_LEN];
|
|
HMAC_SHA1(keysToUse.authKey, sizeof keysToUse.authKey,
|
|
dataToAuthenticate, numBytesToAuthenticate,
|
|
computedAuthTag);
|
|
|
|
if (SRTP_AUTH_TAG_LENGTH > SHA1_DIGEST_LEN) return False; // sanity check
|
|
for (unsigned i = 0; i < SRTP_AUTH_TAG_LENGTH; ++i) {
|
|
if (computedAuthTag[i] != authenticationTag[i]) return False;
|
|
}
|
|
return True;
|
|
}
|
|
|
|
void SRTPCryptographicContext::cryptData(derivedKeys& keys, u_int64_t index, u_int32_t ssrc,
|
|
u_int8_t* data, unsigned numDataBytes) {
|
|
// Begin by constructing the IV: (salt * 2^16) XOR (ssrc * 2^64) XOR (index * 2^16)
|
|
u_int8_t iv[SRTP_CIPHER_KEY_LENGTH];
|
|
|
|
memmove(iv, keys.salt, SRTP_CIPHER_SALT_LENGTH);
|
|
iv[SRTP_CIPHER_SALT_LENGTH] = iv[SRTP_CIPHER_SALT_LENGTH + 1] = 0;
|
|
// (This is based upon the fact that SRTP_CIPHER_KEY_LENGTH == SRTP_CIPHER_SALT_LENGTH + 2)
|
|
|
|
iv[sizeof iv-12] ^= ssrc>>24; iv[sizeof iv-11] ^= ssrc>>16; iv[sizeof iv-10] ^= ssrc>>8; iv[sizeof iv-9] ^= ssrc;
|
|
|
|
iv[sizeof iv-8] ^= index>>40; iv[sizeof iv-7] ^= index>>32; iv[sizeof iv-6] ^= index>>24; iv[sizeof iv-5] ^= index>>16; iv[sizeof iv-4] ^= index>>8; iv[sizeof iv-3] ^= index;
|
|
|
|
// Now generate as many blocks of the keystream as we need, by repeatedly encrypting
|
|
// the IV using our cipher key. (After each step, we increment the IV by 1.)
|
|
// We then XOR the keystream into the provided data, to do the en/decryption.
|
|
AES_KEY key;
|
|
AES_set_encrypt_key(keys.cipherKey, 8*SRTP_CIPHER_KEY_LENGTH, &key);
|
|
|
|
while (numDataBytes > 0) {
|
|
u_int8_t keyStream[SRTP_CIPHER_KEY_LENGTH];
|
|
AES_encrypt(iv, keyStream, &key);
|
|
|
|
unsigned numBytesToUse
|
|
= numDataBytes < SRTP_CIPHER_KEY_LENGTH ? numDataBytes : SRTP_CIPHER_KEY_LENGTH;
|
|
for (unsigned i = 0; i < numBytesToUse; ++i) data[i] ^= keyStream[i];
|
|
data += numBytesToUse;
|
|
numDataBytes -= numBytesToUse;
|
|
|
|
// Increment the IV by 1:
|
|
u_int8_t* ptr = &iv[sizeof iv];
|
|
do {
|
|
--ptr;
|
|
++*ptr;
|
|
} while (*ptr == 0x00);
|
|
}
|
|
}
|
|
|
|
void SRTPCryptographicContext::performKeyDerivation() {
|
|
// Perform a key derivation for the master key+salt, as defined
|
|
// by RFC 3711, section 4.3:
|
|
deriveKeysFromMaster(masterKey(), masterSalt(), fDerivedKeys);
|
|
}
|
|
|
|
#define deriveKey(label, resultKey) deriveSingleKey(masterKey, salt, label, sizeof resultKey, resultKey)
|
|
|
|
void SRTPCryptographicContext
|
|
::deriveKeysFromMaster(u_int8_t const* masterKey, u_int8_t const* salt,
|
|
allDerivedKeys& allKeysResult) {
|
|
// Derive cipher, salt, and auth keys for both SRTP and SRTCP:
|
|
deriveKey(label_srtp_encryption, allKeysResult.srtp.cipherKey);
|
|
deriveKey(label_srtp_msg_auth, allKeysResult.srtp.authKey);
|
|
deriveKey(label_srtp_salt, allKeysResult.srtp.salt);
|
|
|
|
deriveKey(label_srtcp_encryption, allKeysResult.srtcp.cipherKey);
|
|
deriveKey(label_srtcp_msg_auth, allKeysResult.srtcp.authKey);
|
|
deriveKey(label_srtcp_salt, allKeysResult.srtcp.salt);
|
|
}
|
|
|
|
#define KDF_PRF_CIPHER_BLOCK_LENGTH 16
|
|
|
|
void SRTPCryptographicContext
|
|
::deriveSingleKey(u_int8_t const* masterKey, u_int8_t const* salt,
|
|
SRTPKeyDerivationLabel label,
|
|
unsigned resultKeyLength, u_int8_t* resultKey) {
|
|
// This looks a little different from the mechanism described in RFC 3711, section 4.3, but
|
|
// it's what the 'libsrtp' code does, so I hope it's functionally equivalent:
|
|
AES_KEY key;
|
|
AES_set_encrypt_key(masterKey, 8*SRTP_CIPHER_KEY_LENGTH, &key);
|
|
|
|
u_int8_t counter[KDF_PRF_CIPHER_BLOCK_LENGTH];
|
|
// Set the first bytes of "counter" to be the 'salt'; set the remainder to zero:
|
|
memmove(counter, salt, SRTP_CIPHER_SALT_LENGTH);
|
|
for (unsigned i = SRTP_CIPHER_SALT_LENGTH; i < sizeof counter; ++i) {
|
|
counter[i] = 0;
|
|
}
|
|
|
|
// XOR "label" into byte 7 of "counter":
|
|
counter[7] ^= label;
|
|
|
|
// And use the resulting "counter" as the plaintext:
|
|
u_int8_t const* plaintext = counter;
|
|
|
|
unsigned numBytesRemaining = resultKeyLength;
|
|
while (numBytesRemaining > 0) {
|
|
u_int8_t ciphertext[KDF_PRF_CIPHER_BLOCK_LENGTH];
|
|
AES_encrypt(plaintext, ciphertext, &key);
|
|
|
|
unsigned numBytesToCopy
|
|
= numBytesRemaining < KDF_PRF_CIPHER_BLOCK_LENGTH ? numBytesRemaining : KDF_PRF_CIPHER_BLOCK_LENGTH;
|
|
memmove(resultKey, ciphertext, numBytesToCopy);
|
|
resultKey += numBytesToCopy;
|
|
numBytesRemaining -= numBytesToCopy;
|
|
++counter[15]; // for next time
|
|
}
|
|
}
|
|
#endif
|