1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 //** Introduction
36 //
37 // This file contains the implementation of the message authentication codes based
38 // on a symmetric block cipher. These functions only use the single block
39 // encryption functions of the selected symmetric cryptographic library.
40
41 //** Includes, Defines, and Typedefs
42 #define _CRYPT_HASH_C_
43 #include "Tpm.h"
44 #include "CryptSym.h"
45
46 #if ALG_CMAC
47
48 //** Functions
49
50 //*** CryptCmacStart()
51 // This is the function to start the CMAC sequence operation. It initializes the
52 // dispatch functions for the data and end operations for CMAC and initializes the
53 // parameters that are used for the processing of data, including the key, key size
54 // and block cipher algorithm.
55 UINT16
CryptCmacStart(SMAC_STATE * state,TPMU_PUBLIC_PARMS * keyParms,TPM_ALG_ID macAlg,TPM2B * key)56 CryptCmacStart(
57 SMAC_STATE *state,
58 TPMU_PUBLIC_PARMS *keyParms,
59 TPM_ALG_ID macAlg,
60 TPM2B *key
61 )
62 {
63 tpmCmacState_t *cState = &state->state.cmac;
64 TPMT_SYM_DEF_OBJECT *def = &keyParms->symDetail.sym;
65 //
66 if(macAlg != TPM_ALG_CMAC)
67 return 0;
68 // set up the encryption algorithm and parameters
69 cState->symAlg = def->algorithm;
70 cState->keySizeBits = def->keyBits.sym;
71 cState->iv.t.size = CryptGetSymmetricBlockSize(def->algorithm,
72 def->keyBits.sym);
73 MemoryCopy2B(&cState->symKey.b, key, sizeof(cState->symKey.t.buffer));
74
75 // Set up the dispatch methods for the CMAC
76 state->smacMethods.data = CryptCmacData;
77 state->smacMethods.end = CryptCmacEnd;
78 return cState->iv.t.size;
79 }
80
81
82 //*** CryptCmacData()
83 // This function is used to add data to the CMAC sequence computation. The function
84 // will XOR new data into the IV. If the buffer is full, and there is additional
85 // input data, the data is encrypted into the IV buffer, the new data is then
86 // XOR into the IV. When the data runs out, the function returns without encrypting
87 // even if the buffer is full. The last data block of a sequence will not be
88 // encrypted until the call to CryptCmacEnd(). This is to allow the proper subkey
89 // to be computed and applied before the last block is encrypted.
90 void
CryptCmacData(SMAC_STATES * state,UINT32 size,const BYTE * buffer)91 CryptCmacData(
92 SMAC_STATES *state,
93 UINT32 size,
94 const BYTE *buffer
95 )
96 {
97 tpmCmacState_t *cmacState = &state->cmac;
98 TPM_ALG_ID algorithm = cmacState->symAlg;
99 BYTE *key = cmacState->symKey.t.buffer;
100 UINT16 keySizeInBits = cmacState->keySizeBits;
101 tpmCryptKeySchedule_t keySchedule;
102 TpmCryptSetSymKeyCall_t encrypt;
103 //
104 // Set up the encryption values based on the algorithm
105 switch (algorithm)
106 {
107 FOR_EACH_SYM(ENCRYPT_CASE)
108 default:
109 FAIL(FATAL_ERROR_INTERNAL);
110 }
111 while(size > 0)
112 {
113 if(cmacState->bcount == cmacState->iv.t.size)
114 {
115 ENCRYPT(&keySchedule, cmacState->iv.t.buffer, cmacState->iv.t.buffer);
116 cmacState->bcount = 0;
117 }
118 for(;(size > 0) && (cmacState->bcount < cmacState->iv.t.size);
119 size--, cmacState->bcount++)
120 {
121 cmacState->iv.t.buffer[cmacState->bcount] ^= *buffer++;
122 }
123 }
124 }
125
126 //*** CryptCmacEnd()
127 // This is the completion function for the CMAC. It does padding, if needed, and
128 // selects the subkey to be applied before the last block is encrypted.
129 UINT16
CryptCmacEnd(SMAC_STATES * state,UINT32 outSize,BYTE * outBuffer)130 CryptCmacEnd(
131 SMAC_STATES *state,
132 UINT32 outSize,
133 BYTE *outBuffer
134 )
135 {
136 tpmCmacState_t *cState = &state->cmac;
137 // Need to set algorithm, key, and keySizeInBits in the local context so that
138 // the SELECT and ENCRYPT macros will work here
139 TPM_ALG_ID algorithm = cState->symAlg;
140 BYTE *key = cState->symKey.t.buffer;
141 UINT16 keySizeInBits = cState->keySizeBits;
142 tpmCryptKeySchedule_t keySchedule;
143 TpmCryptSetSymKeyCall_t encrypt;
144 TPM2B_IV subkey = {{0, {0}}};
145 BOOL xorVal;
146 UINT16 i;
147
148 subkey.t.size = cState->iv.t.size;
149 // Encrypt a block of zero
150 // Set up the encryption values based on the algorithm
151 switch (algorithm)
152 {
153 FOR_EACH_SYM(ENCRYPT_CASE)
154 default:
155 return 0;
156 }
157 ENCRYPT(&keySchedule, subkey.t.buffer, subkey.t.buffer);
158
159 // shift left by 1 and XOR with 0x0...87 if the MSb was 0
160 xorVal = ((subkey.t.buffer[0] & 0x80) == 0) ? 0 : 0x87;
161 ShiftLeft(&subkey.b);
162 subkey.t.buffer[subkey.t.size - 1] ^= xorVal;
163 // this is a sanity check to make sure that the algorithm is working properly.
164 // remove this check when debug is done
165 pAssert(cState->bcount <= cState->iv.t.size);
166 // If the buffer is full then no need to compute subkey 2.
167 if(cState->bcount < cState->iv.t.size)
168 {
169 //Pad the data
170 cState->iv.t.buffer[cState->bcount++] ^= 0x80;
171 // The rest of the data is a pad of zero which would simply be XORed
172 // with the iv value so nothing to do...
173 // Now compute K2
174 xorVal = ((subkey.t.buffer[0] & 0x80) == 0) ? 0 : 0x87;
175 ShiftLeft(&subkey.b);
176 subkey.t.buffer[subkey.t.size - 1] ^= xorVal;
177 }
178 // XOR the subkey into the IV
179 for(i = 0; i < subkey.t.size; i++)
180 cState->iv.t.buffer[i] ^= subkey.t.buffer[i];
181 ENCRYPT(&keySchedule, cState->iv.t.buffer, cState->iv.t.buffer);
182 i = (UINT16)MIN(cState->iv.t.size, outSize);
183 MemoryCopy(outBuffer, cState->iv.t.buffer, i);
184
185 return i;
186 }
187 #endif
188
189