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	if(key == NULL) {
105        CC_DEBUG_LOG(CC_DEBUG, "NULL Context passed in\n");
106        return;
107    }
108
109	CC_XZEROMEM(hmacCtx, sizeof(_NewHmacContext));
110
111    if((hmacCtx->di = convertccHmacSelector(algorithm)) == NULL) {
112        CC_DEBUG_LOG(CC_DEBUG, "CCHMac Unknown Digest %d\n", algorithm);
113        return;
114	}
115
116    cchmac_init(hmacCtx->di, hmacCtx->ctx, keyLength, key);
117
118
119}
120
121void CCHmacUpdate(
122                  CCHmacContext *ctx,
123                  const void *dataIn,
124                  size_t dataInLength)	/* length of data in bytes */
125{
126	_NewHmacContext	*hmacCtx = (_NewHmacContext *)ctx;
127
128    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
129    cchmac_update(hmacCtx->di, hmacCtx->ctx, dataInLength, dataIn);
130}
131
132void CCHmacFinal(
133                 CCHmacContext *ctx,
134                 void *macOut)
135{
136	_NewHmacContext	*hmacCtx = (_NewHmacContext *)ctx;
137
138    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
139    cchmac_final(hmacCtx->di, hmacCtx->ctx, macOut);
140}
141
142void
143CCHmacDestroy(CCHmacContextRef ctx)
144{
145	CC_XZEROMEM(ctx, sizeof(_NewHmacContext));
146    CC_XFREE(ctx, sizeof(_NewHmacContext));
147}
148
149
150size_t
151CCHmacOutputSizeFromRef(CCHmacContextRef ctx)
152{
153	_NewHmacContext		*hmacCtx = (_NewHmacContext *)ctx;
154    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
155	return hmacCtx->di->output_size;
156}
157
158
159size_t
160CCHmacOutputSize(CCDigestAlg alg)
161{
162    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
163	return CCDigestGetOutputSize(alg);
164}
165
166
167/*
168 * Stateless, one-shot HMAC function.
169 * Output is written to caller-supplied buffer, as in CCHmacFinal().
170 */
171void CCHmac(
172            CCHmacAlgorithm algorithm,	/* kCCHmacSHA1, kCCHmacMD5 */
173            const void *key,
174            size_t keyLength,		/* length of key in bytes */
175            const void *data,
176            size_t dataLength,		/* length of data in bytes */
177            void *macOut)			/* MAC written here */
178{
179    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering Algorithm: %d\n", algorithm);
180    cchmac(convertccHmacSelector(algorithm), keyLength, key, dataLength, data, macOut);
181}
182
183
184
185CCHmacContextRef
186CCHmacCreate(CCDigestAlg alg, const void *key, size_t keyLength)
187{
188	_NewHmacContext		*hmacCtx;
189
190    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
191	/* if this fails, it's time to adjust CC_HMAC_CONTEXT_SIZE */
192    if((hmacCtx = CC_XMALLOC(sizeof(_NewHmacContext))) == NULL) return NULL;
193
194	CC_XZEROMEM(hmacCtx, sizeof(_NewHmacContext));
195
196    if((hmacCtx->di = CCDigestGetDigestInfo(alg)) == NULL) {
197        CC_DEBUG_LOG(CC_DEBUG, "CCHMac Unknown Digest %d\n");
198        CC_XFREE(hmacCtx, sizeof(_NewHmacContext));
199        return NULL;
200	}
201
202    cchmac_init(hmacCtx->di, hmacCtx->ctx, keyLength, key);
203	return (CCHmacContextRef) hmacCtx;
204}
205
206