1/*
2 * Copyright (c) 2000-2001,2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19/*
20 	File:		HmacSha1Legacy.c
21 	Contains:	HMAC/SHA1, bug-for-bug compatible with BSAFE 4.0.
22 	Copyright (c) 2001,2011-2014 Apple Inc. All Rights Reserved.
23*/
24
25#include "ckconfig.h"
26
27#if	CRYPTKIT_HMAC_LEGACY
28
29#include "HmacSha1Legacy.h"
30#include "ckSHA1.h"
31#include <string.h>
32#include <stdlib.h>
33#include <Security/SecBase.h>
34#define kHMACSHA1DigestSize  20
35
36/* XXX These should really be in ckSHA1.h */
37#define kSHA1DigestSize  	20
38#define kSHA1BlockSize  	64
39
40/*
41 * bug-for-bug compatible with BSAFE 4.0. See
42 * BSafe/bsource/algs/ahchhmac.c.
43 *
44 * This implementation, and the BSAFE implementation it emulates, work fine
45 * when calculating a MAC in a single update (init, update, final). They
46 * generate nonconforming MACs when performing multiple updates because
47 * the entire algorithm - both inner and outer digests - are performed
48 * in the update() step. As a result, if one e.g. calculates a MAC of
49 * a block of text with one update, and then calculates the MAC over the
50 * same block of text via two updates, different results will obtain.�The
51 * incorrect result from the multiple-update scenario is repeatable if and
52 * only if the same boundaries (same update sizes) are observed on each operation.
53 *
54 * Because all of the data to be MAC'd is in fact protected by both levels of
55 * SHA1, and all of the key bits are used, this nonconforming implementation is
56 * believed to be as strong, cryptographically, as a conforming SHA1HMAC
57 * implementation.
58 */
59struct hmacLegacyContext {
60	sha1Obj sha1Context;
61	UInt8 	k_ipad[kSHA1BlockSize];
62	UInt8 	k_opad[kSHA1BlockSize];
63};
64
65hmacLegacyContextRef hmacLegacyAlloc(void)
66{
67	hmacLegacyContextRef hmac =
68		(hmacLegacyContextRef)malloc(sizeof(struct hmacLegacyContext));
69	memset(hmac, 0, sizeof(struct hmacLegacyContext));
70	return hmac;
71}
72
73void hmacLegacyFree(
74	hmacLegacyContextRef hmac)
75{
76	if(hmac != NULL) {
77		if(hmac->sha1Context != NULL) {
78			sha1Free (hmac->sha1Context);
79		}
80		memset(hmac, 0, sizeof(struct hmacLegacyContext));
81		free(hmac);
82	}
83}
84
85/* reusable init */
86OSStatus hmacLegacyInit(
87	hmacLegacyContextRef hmac,
88	const void *keyPtr,
89	UInt32 keyLen)
90{
91	UInt8 	*key;
92	UInt32 	byte;
93
94	if(hmac->sha1Context == NULL) {
95		hmac->sha1Context = sha1Alloc();
96		if(hmac->sha1Context == NULL) {
97			return errSecAllocate;
98		}
99	}
100	else {
101		sha1Reinit(hmac->sha1Context);
102	}
103	/* this implementation requires a 20-byte key */
104	if (keyLen != kSHA1DigestSize) {
105		/* FIXME */
106		return errSecParam;
107	}
108	key = (UInt8*)keyPtr;
109
110	/* The HMAC_SHA_1 transform looks like:
111	   SHA1 (K XOR opad || SHA1 (K XOR ipad || text))
112	   Where K is a n byte key
113	   ipad is the byte 0x36 repeated 64 times.
114	   opad is the byte 0x5c repeated 64 times.
115	   text is the data being protected.
116	  */
117	/* Copy the key into k_ipad and k_opad while doing the XOR. */
118	for (byte = 0; byte < keyLen; byte++)
119	{
120		hmac->k_ipad[byte] = key[byte] ^ 0x36;
121		hmac->k_opad[byte] = key[byte] ^ 0x5c;
122	}
123
124	/* Fill the remainder of k_ipad and k_opad with 0 XORed with
125	 * appropriate value. */
126	memset (hmac->k_ipad + keyLen, 0x36, kSHA1BlockSize - keyLen);
127	memset (hmac->k_opad + keyLen, 0x5c, kSHA1BlockSize - keyLen);
128
129	/* remainder happens in update */
130	return errSecSuccess;
131}
132
133OSStatus hmacLegacyUpdate(
134	hmacLegacyContextRef hmac,
135	const void *textPtr,
136	UInt32 textLen)
137{
138	UInt8 innerDigest[kSHA1DigestSize];
139
140	/* compute SHA1(k_ipad || data) ==> innerDigest */
141	sha1AddData (hmac->sha1Context, hmac->k_ipad, kSHA1BlockSize);
142	sha1AddData (hmac->sha1Context, (UInt8*)textPtr, textLen);
143	memcpy (innerDigest, sha1Digest(hmac->sha1Context), kSHA1DigestSize);
144
145	/* reset context (BSAFE does this implicitly in a final() call) */
146	sha1Reinit(hmac->sha1Context);
147
148	/* compute SHA1(k_opad || innerDigest) */
149	sha1AddData (hmac->sha1Context, hmac->k_opad, kSHA1BlockSize);
150	sha1AddData (hmac->sha1Context, innerDigest, kSHA1DigestSize);
151
152	/* if there is another update coming, it gets added in to existing
153	 * context; if the next step is a final, the current digest state is used. */
154	return errSecSuccess;
155}
156
157OSStatus hmacLegacyFinal(
158	hmacLegacyContextRef hmac,
159	void *resultPtr)		// caller mallocs, must be HMACSHA1_OUT_SIZE bytes
160{
161	memcpy (resultPtr, sha1Digest (hmac->sha1Context), kSHA1DigestSize);
162	return errSecSuccess;
163}
164
165#endif	/* CRYPTKIT_HMAC_LEGACY */
166