1/* 2 * Copyright (c) 2011 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24// #define COMMON_CMAC_FUNCTIONS 25 26#include "CommonCMACSPI.h" 27#include "CommonCryptorPriv.h" 28#include <corecrypto/ccaes.h> 29#include "ccdebug.h" 30#include "ccMemory.h" 31 32#if 0 33 34/* Internal functions to support one-shot */ 35 36const uint8_t const_Rb[16] = { 37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 39}; 40 41 42 43static void leftshift_onebit(uint8_t *input, uint8_t *output) 44{ 45 int i; 46 uint8_t overflow = 0; 47 48 for ( i=15; i>=0; i-- ) { 49 output[i] = input[i] << 1; 50 output[i] |= overflow; 51 overflow = (input[i] & 0x80)?1:0; 52 } 53 return; 54} 55 56static void xor_128(const uint8_t *a, const uint8_t *b, uint8_t *out) 57{ 58 int i; 59 for (i=0;i<16; i++) out[i] = a[i] ^ b[i]; 60} 61 62 63static void ccGenAESSubKey(const struct ccmode_ecb *aesmode, ccecb_ctx *ctx, void *key1, void *key2) 64{ 65 uint8_t L[16]; 66 uint8_t Z[16]; 67 uint8_t tmp[16]; 68 69 memset(Z, 0, 16); 70 71 aesmode->ecb(ctx, 1, Z, L); 72 73 if ( (L[0] & 0x80) == 0 ) { /* If MSB(L) = 0, then K1 = L << 1 */ 74 leftshift_onebit(L, key1); 75 } else { /* Else K1 = ( L << 1 ) (+) Rb */ 76 leftshift_onebit(L, tmp); 77 xor_128(tmp,const_Rb, key1); 78 } 79 80 if ( (((uint8_t *)key1)[0] & 0x80) == 0 ) { 81 leftshift_onebit(key1, key2); 82 } else { 83 leftshift_onebit(key1, tmp); 84 xor_128(tmp,const_Rb, key2); 85 } 86 return; 87 88} 89 90static void ccAESCMacPadding (const uint8_t *lastb, uint8_t *pad, int length) 91{ 92 int j; 93 94 for ( j=0; j<16; j++ ) { 95 if ( j < length ) pad[j] = lastb[j]; 96 else if ( j == length ) pad[j] = 0x80; 97 else pad[j] = 0x00; 98 } 99} 100 101/* This would be the one-shot CMAC interface */ 102 103void CCAESCmac(const void *key, 104 const uint8_t *data, 105 size_t dataLength, /* length of data in bytes */ 106 void *macOut) /* MAC written here */ 107{ 108 uint8_t X[16],Y[16], M_last[16], padded[16]; 109 uint8_t K1[16], K2[16]; 110 int flag; 111 size_t n; 112 const struct ccmode_ecb *aesmode = getCipherMode(kCCAlgorithmAES128, kCCModeECB, kCCEncrypt).ecb; 113 ccecb_ctx_decl(aesmode->size, ctx); 114 115 CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n"); 116 117 // CMacInit 118 119 aesmode->init(aesmode, ctx, 16, key); 120 aesmode->ecb(ctx, 1, Y, X); 121 ccGenAESSubKey(aesmode, ctx, K1, K2); 122 123 // CMacUpdates (all in this case) 124 125 n = (dataLength+15) / 16; /* n is number of rounds */ 126 127 if ( 0 == n ) { 128 n = 1; 129 flag = 0; 130 } else { 131 if ( (dataLength%16) == 0 ) flag = 1; 132 else flag = 0; 133 } 134 135 if ( flag ) { /* last block is complete block */ 136 xor_128(&data[16*(n-1)],K1,M_last); 137 } else { 138 ccAESCMacPadding(&data[16*(n-1)],padded,dataLength%16); 139 xor_128(padded,K2,M_last); 140 } 141 142 memset(X, 0, 16); 143 for (size_t i=0; i<n-1; i++ ) { 144 xor_128(X,&data[16*i],Y); /* Y := Mi (+) X */ 145 aesmode->ecb(ctx, 1, Y, X); 146 } 147 148 // CMacFinal 149 150 xor_128(X,M_last,Y); 151 aesmode->ecb(ctx, 1, Y, X); 152 153 memcpy(macOut, X, 16); 154} 155 156#else 157#include <corecrypto/cccmac.h> 158#include <corecrypto/ccaes.h> 159 160void CCAESCmac(const void *key, 161 const uint8_t *data, 162 size_t dataLength, /* length of data in bytes */ 163 void *macOut) /* MAC written here */ 164{ 165 cccmac(ccaes_cbc_encrypt_mode(), key, dataLength, data, macOut); 166} 167 168struct CCCmacContext { 169 const struct ccmode_cbc *cbc; 170 cccmac_ctx_t ctxptr; 171 size_t pos; 172 uint8_t buf[16]; 173}; 174 175CCCmacContextPtr 176CCAESCmacCreate(const void *key, size_t keyLength) 177{ 178 CCCmacContextPtr retval = (CCCmacContextPtr) CC_XMALLOC(sizeof(struct CCCmacContext)); 179 if(!retval) return NULL; 180 retval->cbc = ccaes_cbc_encrypt_mode(); 181 retval->ctxptr.b = CC_XMALLOC(cccmac_ctx_size(retval->cbc)); 182 retval->pos = 0; 183 if(!retval->ctxptr.b) { 184 CC_XFREE(retval, cccmac_ctx_size(retval->cbc)); 185 return NULL; 186 } 187 cccmac_init(retval->cbc, retval->ctxptr, key); 188 189 return retval; 190} 191 192void CCAESCmacUpdate(CCCmacContextPtr ctx, const void *data, size_t dataLength) { 193 size_t blocksize = ctx->cbc->block_size; 194 // Need to have some data for final - so don't process all available data - even if it's even blocks 195 while(dataLength) { 196 if(ctx->pos == blocksize) { // flush what we have - there's more 197 cccmac_block_update(ctx->cbc, ctx->ctxptr, 1, ctx->buf); 198 ctx->pos = 0; 199 } else if (ctx->pos == 0 && dataLength > blocksize) { 200 size_t fullblocks = ((dataLength + blocksize - 1) / blocksize) - 1; 201 cccmac_block_update(ctx->cbc, ctx->ctxptr, fullblocks, data); 202 size_t nbytes = fullblocks * blocksize; 203 dataLength -= nbytes; data += nbytes; 204 } else { 205 size_t n = CC_XMIN(dataLength, (blocksize - ctx->pos)); 206 CC_XMEMCPY(&ctx->buf[ctx->pos], data, n); 207 ctx->pos += n; dataLength -= n; data += n; 208 } 209 } 210} 211 212void CCAESCmacFinal(CCCmacContextPtr ctx, void *macOut) { 213 cccmac_final(ctx->cbc, ctx->ctxptr, ctx->pos, ctx->buf, macOut); 214} 215 216void CCAESCmacDestroy(CCCmacContextPtr ctx) { 217 if(ctx) { 218 CC_BZERO(ctx->buf, 16); 219 if(!ctx->ctxptr.b) CC_XFREE(ctx->ctxptr.b, cccmac_ctx_size(retval->cbc)); 220 CC_XFREE(ctx, sizeof(struct CCCmacContext)); 221 } 222} 223 224size_t 225CCAESCmacOutputSizeFromContext(CCCmacContextPtr ctx) { 226 return ctx->cbc->block_size; 227} 228 229#endif 230