1/*
2 * Copyright (c) 2000-2001 Apple Computer, 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 by Apple Computer, Inc., all rights reserved
23 	Written by:	Doug Mitchell
24*/
25
26#include "ckconfig.h"
27
28#if	CRYPTKIT_HMAC_LEGACY
29
30#include "HmacSha1Legacy.h"
31#include "ckSHA1.h"
32#include <string.h>
33#include <stdlib.h>
34#include <Security/SecBase.h>
35#define kHMACSHA1DigestSize  20
36
37/* XXX These should really be in ckSHA1.h */
38#define kSHA1DigestSize  	20
39#define kSHA1BlockSize  	64
40
41/*
42 * bug-for-bug compatible with BSAFE 4.0. See
43 * BSafe/bsource/algs/ahchhmac.c.
44 *
45 * This implementation, and the BSAFE implementation it emulates, work fine
46 * when calculating a MAC in a single update (init, update, final). They
47 * generate nonconforming MACs when performing multiple updates because
48 * the entire algorithm - both inner and outer digests - are performed
49 * in the update() step. As a result, if one e.g. calculates a MAC of
50 * a block of text with one update, and then calculates the MAC over the
51 * same block of text via two updates, different results will obtain.�The
52 * incorrect result from the multiple-update scenario is repeatable if and
53 * only if the same boundaries (same update sizes) are observed on each operation.
54 *
55 * Because all of the data to be MAC'd is in fact protected by both levels of
56 * SHA1, and all of the key bits are used, this nonconforming implementation is
57 * believed to be as strong, cryptographically, as a conforming SHA1HMAC
58 * implementation.
59 */
60struct hmacLegacyContext {
61	sha1Obj sha1Context;
62	UInt8 	k_ipad[kSHA1BlockSize];
63	UInt8 	k_opad[kSHA1BlockSize];
64};
65
66hmacLegacyContextRef hmacLegacyAlloc(void)
67{
68	hmacLegacyContextRef hmac =
69		(hmacLegacyContextRef)malloc(sizeof(struct hmacLegacyContext));
70	memset(hmac, 0, sizeof(struct hmacLegacyContext));
71	return hmac;
72}
73
74void hmacLegacyFree(
75	hmacLegacyContextRef hmac)
76{
77	if(hmac != NULL) {
78		if(hmac->sha1Context != NULL) {
79			sha1Free (hmac->sha1Context);
80		}
81		memset(hmac, 0, sizeof(struct hmacLegacyContext));
82		free(hmac);
83	}
84}
85
86/* reusable init */
87OSStatus hmacLegacyInit(
88	hmacLegacyContextRef hmac,
89	const void *keyPtr,
90	UInt32 keyLen)
91{
92	UInt8 	*key;
93	UInt32 	byte;
94
95	if(hmac->sha1Context == NULL) {
96		hmac->sha1Context = sha1Alloc();
97		if(hmac->sha1Context == NULL) {
98			return errSecAllocate;
99		}
100	}
101	else {
102		sha1Reinit(hmac->sha1Context);
103	}
104	/* this implementation requires a 20-byte key */
105	if (keyLen != kSHA1DigestSize) {
106		/* FIXME */
107		return errSecParam;
108	}
109	key = (UInt8*)keyPtr;
110
111	/* The HMAC_SHA_1 transform looks like:
112	   SHA1 (K XOR opad || SHA1 (K XOR ipad || text))
113	   Where K is a n byte key
114	   ipad is the byte 0x36 repeated 64 times.
115	   opad is the byte 0x5c repeated 64 times.
116	   text is the data being protected.
117	  */
118	/* Copy the key into k_ipad and k_opad while doing the XOR. */
119	for (byte = 0; byte < keyLen; byte++)
120	{
121		hmac->k_ipad[byte] = key[byte] ^ 0x36;
122		hmac->k_opad[byte] = key[byte] ^ 0x5c;
123	}
124
125	/* Fill the remainder of k_ipad and k_opad with 0 XORed with
126	 * appropriate value. */
127	memset (hmac->k_ipad + keyLen, 0x36, kSHA1BlockSize - keyLen);
128	memset (hmac->k_opad + keyLen, 0x5c, kSHA1BlockSize - keyLen);
129
130	/* remainder happens in update */
131	return errSecSuccess;
132}
133
134OSStatus hmacLegacyUpdate(
135	hmacLegacyContextRef hmac,
136	const void *textPtr,
137	UInt32 textLen)
138{
139	UInt8 innerDigest[kSHA1DigestSize];
140
141	/* compute SHA1(k_ipad || data) ==> innerDigest */
142	sha1AddData (hmac->sha1Context, hmac->k_ipad, kSHA1BlockSize);
143	sha1AddData (hmac->sha1Context, (UInt8*)textPtr, textLen);
144	memcpy (innerDigest, sha1Digest(hmac->sha1Context), kSHA1DigestSize);
145
146	/* reset context (BSAFE does this implicitly in a final() call) */
147	sha1Reinit(hmac->sha1Context);
148
149	/* compute SHA1(k_opad || innerDigest) */
150	sha1AddData (hmac->sha1Context, hmac->k_opad, kSHA1BlockSize);
151	sha1AddData (hmac->sha1Context, innerDigest, kSHA1DigestSize);
152
153	/* if there is another update coming, it gets added in to existing
154	 * context; if the next step is a final, the current digest state is used. */
155	return errSecSuccess;
156}
157
158OSStatus hmacLegacyFinal(
159	hmacLegacyContextRef hmac,
160	void *resultPtr)		// caller mallocs, must be HMACSHA1_OUT_SIZE bytes
161{
162	memcpy (resultPtr, sha1Digest (hmac->sha1Context), kSHA1DigestSize);
163	return errSecSuccess;
164}
165
166#endif	/* CRYPTKIT_HMAC_LEGACY */
167