1/*
2 * Copyright (c) 2012 Apple 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_HMAC_FUNCTIONS
25#include "CommonHMAC.h"
26#include "CommonHmacSPI.h"
27#include "CommonDigest.h"
28#include "CommonDigestSPI.h"
29#include "CommonDigestPriv.h"
30#include <corecrypto/cchmac.h>
31#include "ccMemory.h"
32#include "ccdebug.h"
33
34#ifndef	NDEBUG
35#define ASSERT(s)
36#else
37#define ASSERT(s)	assert(s)
38#endif
39
40#define	HMAC_MAX_BLOCK_SIZE     CC_SHA512_BLOCK_BYTES
41#define	HMAC_MAX_DIGEST_SIZE    CC_SHA512_DIGEST_LENGTH
42
43/*
44 * This is what a CCHmacContext actually points to.
45 * we have 384 bytes to work with
46 */
47
48typedef struct {
49    const struct ccdigest_info *di;
50    cchmac_ctx_decl(HMAC_MAX_BLOCK_SIZE, HMAC_MAX_DIGEST_SIZE, ctx);
51} _NewHmacContext;
52
53
54typedef struct {
55    CCHmacAlgorithm ccHmacValue;
56    CCDigestAlgorithm ccDigestAlg;
57    const char *ccDigestName;
58} ccHmac2DigestConversion;
59
60
61const ccHmac2DigestConversion ccconversionTable[] = {
62    { kCCHmacAlgSHA1, kCCDigestSHA1, "sha1" },
63    { kCCHmacAlgMD5, kCCDigestMD5, "md5" },
64    { kCCHmacAlgSHA224, kCCDigestSHA224, "sha224" },
65    { kCCHmacAlgSHA256, kCCDigestSHA256, "sha256" },
66    { kCCHmacAlgSHA384, kCCDigestSHA384, "sha384" },
67    { kCCHmacAlgSHA512, kCCDigestSHA512, "sha512" },
68};
69
70const static int ccHmacConversionTableLength = sizeof(ccconversionTable) / sizeof(ccHmac2DigestConversion);
71
72static const struct ccdigest_info *
73convertccHmacSelector(CCHmacAlgorithm oldSelector)
74{
75    int i;
76
77    for(i=0; i<ccHmacConversionTableLength; i++)
78        if(oldSelector == ccconversionTable[i].ccHmacValue) {
79            return CCDigestGetDigestInfo(ccconversionTable[i].ccDigestAlg);
80        }
81    return NULL;
82}
83
84
85void CCHmacInit(
86                CCHmacContext *ctx,
87                CCHmacAlgorithm algorithm,	/* kCCHmacSHA1, kCCHmacMD5 */
88                const void *key,
89                size_t keyLength)		/* length of key in bytes */
90{
91	_NewHmacContext		*hmacCtx = (_NewHmacContext *)ctx;
92    // CCDigestCtxPtr  digestCtx = &hmacCtx->digestCtx;
93
94    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering Algorithm: %d\n", algorithm);
95
96
97	ASSERT(sizeof(_NewHmacContext) < sizeof(CCHmacContext));
98
99	if(hmacCtx == NULL) {
100        CC_DEBUG_LOG(CC_DEBUG, "NULL Context passed in\n");
101        return;
102    }
103
104	CC_XZEROMEM(hmacCtx, sizeof(_NewHmacContext));
105
106    if((hmacCtx->di = convertccHmacSelector(algorithm)) == NULL) {
107        CC_DEBUG_LOG(CC_DEBUG, "CCHMac Unknown Digest %d\n", algorithm);
108        return;
109	}
110
111    cchmac_init(hmacCtx->di, hmacCtx->ctx, keyLength, key);
112
113
114}
115
116void CCHmacUpdate(
117                  CCHmacContext *ctx,
118                  const void *dataIn,
119                  size_t dataInLength)	/* length of data in bytes */
120{
121	_NewHmacContext	*hmacCtx = (_NewHmacContext *)ctx;
122
123    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
124    cchmac_update(hmacCtx->di, hmacCtx->ctx, dataInLength, dataIn);
125}
126
127void CCHmacFinal(
128                 CCHmacContext *ctx,
129                 void *macOut)
130{
131	_NewHmacContext	*hmacCtx = (_NewHmacContext *)ctx;
132
133    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
134    cchmac_final(hmacCtx->di, hmacCtx->ctx, macOut);
135}
136
137void
138CCHmacDestroy(CCHmacContextRef ctx)
139{
140	CC_XZEROMEM(ctx, sizeof(_NewHmacContext));
141    CC_XFREE(ctx, sizeof(_NewHmacContext));
142}
143
144
145size_t
146CCHmacOutputSizeFromRef(CCHmacContextRef ctx)
147{
148	_NewHmacContext		*hmacCtx = (_NewHmacContext *)ctx;
149    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
150	return hmacCtx->di->output_size;
151}
152
153
154size_t
155CCHmacOutputSize(CCDigestAlg alg)
156{
157    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
158	return CCDigestGetOutputSize(alg);
159}
160
161
162/*
163 * Stateless, one-shot HMAC function.
164 * Output is written to caller-supplied buffer, as in CCHmacFinal().
165 */
166void CCHmac(
167            CCHmacAlgorithm algorithm,	/* kCCHmacSHA1, kCCHmacMD5 */
168            const void *key,
169            size_t keyLength,		/* length of key in bytes */
170            const void *data,
171            size_t dataLength,		/* length of data in bytes */
172            void *macOut)			/* MAC written here */
173{
174    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering Algorithm: %d\n", algorithm);
175    cchmac(convertccHmacSelector(algorithm), keyLength, key, dataLength, data, macOut);
176}
177
178
179
180CCHmacContextRef
181CCHmacCreate(CCDigestAlg alg, const void *key, size_t keyLength)
182{
183	_NewHmacContext		*hmacCtx;
184
185    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
186	/* if this fails, it's time to adjust CC_HMAC_CONTEXT_SIZE */
187    if((hmacCtx = CC_XMALLOC(sizeof(_NewHmacContext))) == NULL) return NULL;
188
189	CC_XZEROMEM(hmacCtx, sizeof(_NewHmacContext));
190
191    if((hmacCtx->di = CCDigestGetDigestInfo(alg)) == NULL) {
192        CC_DEBUG_LOG(CC_DEBUG, "CCHMac Unknown Digest %d\n");
193        CC_XFREE(hmacCtx, sizeof(_NewHmacContext));
194        return NULL;
195	}
196
197    cchmac_init(hmacCtx->di, hmacCtx->ctx, keyLength, key);
198	return (CCHmacContextRef) hmacCtx;
199}
200
201void CCHmacOneShot(CCDigestAlg alg,  const void *key, size_t keyLength, const void *data, size_t dataLength, void *macOut) {
202    const struct ccdigest_info *di = CCDigestGetDigestInfo(alg);
203    cchmac(di, keyLength, key, dataLength, data, macOut);
204}
205
206CCHmacContextRef
207CCHmacClone(CCHmacContextRef ctx) {
208	_NewHmacContext		*hmacCtx;
209
210    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
211	/* if this fails, it's time to adjust CC_HMAC_CONTEXT_SIZE */
212    if((hmacCtx = CC_XMALLOC(sizeof(_NewHmacContext))) == NULL) return NULL;
213
214	CC_MEMCPY(hmacCtx, ctx, sizeof(_NewHmacContext));
215	return (CCHmacContextRef) hmacCtx;
216}
217
218