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