/* Microsoft Reference Implementation for TPM 2.0 | |
* | |
* The copyright in this software is being made available under the BSD License, | |
* included below. This software may be subject to other third party and | |
* contributor rights, including patent rights, and no such rights are granted | |
* under this license. | |
* | |
* Copyright (c) Microsoft Corporation | |
* | |
* All rights reserved. | |
* | |
* BSD License | |
* | |
* Redistribution and use in source and binary forms, with or without modification, | |
* are permitted provided that the following conditions are met: | |
* | |
* Redistributions of source code must retain the above copyright notice, this list | |
* of conditions and the following disclaimer. | |
* | |
* Redistributions in binary form must reproduce the above copyright notice, this | |
* list of conditions and the following disclaimer in the documentation and/or | |
* other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" | |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
//** Introduction | |
// | |
// This file contains the implementation of the message authentication codes based | |
// on a symmetric block cipher. These functions only use the single block | |
// encryption functions of the selected symmetric cryptographic library. | |
//** Includes, Defines, and Typedefs | |
#define _CRYPT_HASH_C_ | |
#include "Tpm.h" | |
#include "CryptSym.h" | |
#if ALG_CMAC | |
//** Functions | |
//*** CryptCmacStart() | |
// This is the function to start the CMAC sequence operation. It initializes the | |
// dispatch functions for the data and end operations for CMAC and initializes the | |
// parameters that are used for the processing of data, including the key, key size | |
// and block cipher algorithm. | |
UINT16 | |
CryptCmacStart( | |
SMAC_STATE *state, | |
TPMU_PUBLIC_PARMS *keyParms, | |
TPM_ALG_ID macAlg, | |
TPM2B *key | |
) | |
{ | |
tpmCmacState_t *cState = &state->state.cmac; | |
TPMT_SYM_DEF_OBJECT *def = &keyParms->symDetail.sym; | |
// | |
if(macAlg != TPM_ALG_CMAC) | |
return 0; | |
// set up the encryption algorithm and parameters | |
cState->symAlg = def->algorithm; | |
cState->keySizeBits = def->keyBits.sym; | |
cState->iv.t.size = CryptGetSymmetricBlockSize(def->algorithm, | |
def->keyBits.sym); | |
MemoryCopy2B(&cState->symKey.b, key, sizeof(cState->symKey.t.buffer)); | |
// Set up the dispatch methods for the CMAC | |
state->smacMethods.data = CryptCmacData; | |
state->smacMethods.end = CryptCmacEnd; | |
return cState->iv.t.size; | |
} | |
//*** CryptCmacData() | |
// This function is used to add data to the CMAC sequence computation. The function | |
// will XOR new data into the IV. If the buffer is full, and there is additional | |
// input data, the data is encrypted into the IV buffer, the new data is then | |
// XOR into the IV. When the data runs out, the function returns without encrypting | |
// even if the buffer is full. The last data block of a sequence will not be | |
// encrypted until the call to CryptCmacEnd(). This is to allow the proper subkey | |
// to be computed and applied before the last block is encrypted. | |
void | |
CryptCmacData( | |
SMAC_STATES *state, | |
UINT32 size, | |
const BYTE *buffer | |
) | |
{ | |
tpmCmacState_t *cmacState = &state->cmac; | |
TPM_ALG_ID algorithm = cmacState->symAlg; | |
BYTE *key = cmacState->symKey.t.buffer; | |
UINT16 keySizeInBits = cmacState->keySizeBits; | |
tpmCryptKeySchedule_t keySchedule; | |
TpmCryptSetSymKeyCall_t encrypt; | |
// | |
// Set up the encryption values based on the algorithm | |
switch (algorithm) | |
{ | |
FOR_EACH_SYM(ENCRYPT_CASE) | |
default: | |
FAIL(FATAL_ERROR_INTERNAL); | |
} | |
while(size > 0) | |
{ | |
if(cmacState->bcount == cmacState->iv.t.size) | |
{ | |
ENCRYPT(&keySchedule, cmacState->iv.t.buffer, cmacState->iv.t.buffer); | |
cmacState->bcount = 0; | |
} | |
for(;(size > 0) && (cmacState->bcount < cmacState->iv.t.size); | |
size--, cmacState->bcount++) | |
{ | |
cmacState->iv.t.buffer[cmacState->bcount] ^= *buffer++; | |
} | |
} | |
} | |
//*** CryptCmacEnd() | |
// This is the completion function for the CMAC. It does padding, if needed, and | |
// selects the subkey to be applied before the last block is encrypted. | |
UINT16 | |
CryptCmacEnd( | |
SMAC_STATES *state, | |
UINT32 outSize, | |
BYTE *outBuffer | |
) | |
{ | |
tpmCmacState_t *cState = &state->cmac; | |
// Need to set algorithm, key, and keySizeInBits in the local context so that | |
// the SELECT and ENCRYPT macros will work here | |
TPM_ALG_ID algorithm = cState->symAlg; | |
BYTE *key = cState->symKey.t.buffer; | |
UINT16 keySizeInBits = cState->keySizeBits; | |
tpmCryptKeySchedule_t keySchedule; | |
TpmCryptSetSymKeyCall_t encrypt; | |
TPM2B_IV subkey = {{0, {0}}}; | |
BOOL xorVal; | |
UINT16 i; | |
subkey.t.size = cState->iv.t.size; | |
// Encrypt a block of zero | |
// Set up the encryption values based on the algorithm | |
switch (algorithm) | |
{ | |
FOR_EACH_SYM(ENCRYPT_CASE) | |
default: | |
return 0; | |
} | |
ENCRYPT(&keySchedule, subkey.t.buffer, subkey.t.buffer); | |
// shift left by 1 and XOR with 0x0...87 if the MSb was 0 | |
xorVal = ((subkey.t.buffer[0] & 0x80) == 0) ? 0 : 0x87; | |
ShiftLeft(&subkey.b); | |
subkey.t.buffer[subkey.t.size - 1] ^= xorVal; | |
// this is a sanity check to make sure that the algorithm is working properly. | |
// remove this check when debug is done | |
pAssert(cState->bcount <= cState->iv.t.size); | |
// If the buffer is full then no need to compute subkey 2. | |
if(cState->bcount < cState->iv.t.size) | |
{ | |
//Pad the data | |
cState->iv.t.buffer[cState->bcount++] ^= 0x80; | |
// The rest of the data is a pad of zero which would simply be XORed | |
// with the iv value so nothing to do... | |
// Now compute K2 | |
xorVal = ((subkey.t.buffer[0] & 0x80) == 0) ? 0 : 0x87; | |
ShiftLeft(&subkey.b); | |
subkey.t.buffer[subkey.t.size - 1] ^= xorVal; | |
} | |
// XOR the subkey into the IV | |
for(i = 0; i < subkey.t.size; i++) | |
cState->iv.t.buffer[i] ^= subkey.t.buffer[i]; | |
ENCRYPT(&keySchedule, cState->iv.t.buffer, cState->iv.t.buffer); | |
i = (UINT16)MIN(cState->iv.t.size, outSize); | |
MemoryCopy(outBuffer, cState->iv.t.buffer, i); | |
return i; | |
} | |
#endif | |