]> git.saurik.com Git - apple/security.git/blob - AppleCSP/PBKDF2/HMACSHA1.c
Security-54.tar.gz
[apple/security.git] / AppleCSP / PBKDF2 / HMACSHA1.c
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: HMACSHA1.c
21 Contains: Apple Data Security Services HMACSHA1 function definition.
22 Copyright: (C) 1999 by Apple Computer, Inc., all rights reserved
23 Written by: Michael Brouwer <mb@apple.com>
24 */
25 #include "HMACSHA1.h"
26 #include <MiscCSPAlgs/SHA1.h>
27 #include <MiscCSPAlgs/MD5.h>
28 #include <string.h>
29 #include <stdlib.h> // for malloc - maybe we should use CssmAllocator?
30 #include <Security/cssmerr.h>
31
32 #pragma mark --- Common digest class ---
33
34 typedef struct {
35 union {
36 sha1Obj sha1Context; // must be allocd via sha1Alloc
37 struct MD5Context md5Context;
38 } dig;
39 CSSM_BOOL isSha1;
40 } DigestCtx;
41
42 /* Ops on a DigestCtx */
43 static CSSM_RETURN DigestCtxInit(
44 DigestCtx *ctx,
45 CSSM_BOOL isSha1)
46 {
47 if(isSha1) {
48 if(ctx->dig.sha1Context == NULL) {
49 ctx->dig.sha1Context = sha1Alloc();
50 if(ctx->dig.sha1Context == NULL) {
51 return CSSMERR_CSP_MEMORY_ERROR;
52 }
53 }
54 else {
55 sha1Reinit(ctx->dig.sha1Context);
56 }
57 }
58 else {
59 MD5Init(&ctx->dig.md5Context);
60 }
61 ctx->isSha1 = isSha1;
62 return CSSM_OK;
63 }
64
65 static void DigestCtxFree(
66 DigestCtx *ctx)
67 {
68 if(ctx->isSha1) {
69 sha1Free(ctx->dig.sha1Context);
70 }
71 memset(ctx, 0, sizeof(DigestCtx));
72 }
73
74 static void DigestCtxUpdate(
75 DigestCtx *ctx,
76 const void *textPtr,
77 UInt32 textLen)
78 {
79 if(ctx->isSha1) {
80 sha1AddData(ctx->dig.sha1Context, (unsigned char *)textPtr, textLen);
81 }
82 else {
83 MD5Update(&ctx->dig.md5Context, (unsigned char *)textPtr, textLen);
84 }
85 }
86
87 static void DigestCtxFinal(
88 DigestCtx *ctx,
89 void *digest)
90 {
91 if(ctx->isSha1) {
92 sha1GetDigest(ctx->dig.sha1Context, (unsigned char *)digest);
93 }
94 else {
95 MD5Final(&ctx->dig.md5Context, (unsigned char *)digest);
96 }
97 }
98
99 #pragma mark --- HMAC class ---
100
101 struct hmacContext {
102 DigestCtx digest;
103 UInt8 k_opad[kSHA1BlockSize];
104 };
105
106 hmacContextRef hmacAlloc()
107 {
108 hmacContextRef hmac = (hmacContextRef)malloc(sizeof(struct hmacContext));
109 memset(hmac, 0, sizeof(struct hmacContext));
110 return hmac;
111 }
112
113 void hmacFree(
114 hmacContextRef hmac)
115 {
116 if(hmac != NULL) {
117 DigestCtxFree(&hmac->digest);
118 memset(hmac, 0, sizeof(struct hmacContext));
119 free(hmac);
120 }
121 }
122
123 /* reusable init */
124 CSSM_RETURN hmacInit(
125 hmacContextRef hmac,
126 const void *keyPtr,
127 UInt32 keyLen,
128 CSSM_BOOL isSha1) // true -> SHA1; false -> MD5
129 {
130 UInt8 tk[kSHA1DigestSize];
131 UInt8 *key;
132 UInt32 byte;
133 UInt8 k_ipad[kSHA1BlockSize];
134 UInt32 digestSize = sha1Digest ? kSHA1DigestSize : MD5_DIGEST_SIZE;
135
136 DigestCtxInit(&hmac->digest, isSha1);
137
138 /* If the key is longer than kSHA1BlockSize reset it to key=digest(key) */
139 if (keyLen <= kSHA1BlockSize)
140 key = (UInt8*)keyPtr;
141 else {
142 DigestCtxUpdate(&hmac->digest, (UInt8*)keyPtr, keyLen);
143 DigestCtxFinal(&hmac->digest, tk);
144 key = tk;
145 keyLen = digestSize;
146 DigestCtxInit(&hmac->digest, isSha1);
147 }
148
149 /* The HMAC_<DIG> transform looks like:
150 <DIG> (K XOR opad || <DIG> (K XOR ipad || text))
151 Where K is a n byte key
152 ipad is the byte 0x36 repeated 64 times.
153 opad is the byte 0x5c repeated 64 times.
154 text is the data being protected.
155 */
156 /* Copy the key into k_ipad and k_opad while doing the XOR. */
157 for (byte = 0; byte < keyLen; byte++)
158 {
159 k_ipad[byte] = key[byte] ^ 0x36;
160 hmac->k_opad[byte] = key[byte] ^ 0x5c;
161 }
162 /* Fill the remainder of k_ipad and k_opad with 0 XORed with the appropriate value. */
163 if (keyLen < kSHA1BlockSize)
164 {
165 memset (k_ipad + keyLen, 0x36, kSHA1BlockSize - keyLen);
166 memset (hmac->k_opad + keyLen, 0x5c, kSHA1BlockSize - keyLen);
167 }
168 DigestCtxUpdate(&hmac->digest, k_ipad, kSHA1BlockSize);
169 return CSSM_OK;
170 }
171
172 CSSM_RETURN hmacUpdate(
173 hmacContextRef hmac,
174 const void *textPtr,
175 UInt32 textLen)
176 {
177 DigestCtxUpdate(&hmac->digest, textPtr, textLen);
178 return CSSM_OK;
179 }
180
181 CSSM_RETURN hmacFinal(
182 hmacContextRef hmac,
183 void *resultPtr) // caller mallocs, must be appropriate output size for
184 // current digest algorithm
185 {
186 UInt32 digestSize = hmac->digest.isSha1 ? kSHA1DigestSize : kHMACMD5DigestSize;
187
188 DigestCtxFinal(&hmac->digest, resultPtr);
189 DigestCtxInit(&hmac->digest, hmac->digest.isSha1);
190 /* Perform outer digest */
191 DigestCtxUpdate(&hmac->digest, hmac->k_opad, kSHA1BlockSize);
192 DigestCtxUpdate(&hmac->digest, resultPtr, digestSize);
193 DigestCtxFinal(&hmac->digest, resultPtr);
194 return CSSM_OK;
195 }
196
197 /* one-shot, ignoring memory errors. */
198 void
199 hmacsha1 (const void *keyPtr, UInt32 keyLen,
200 const void *textPtr, UInt32 textLen,
201 void *resultPtr)
202 {
203 hmacContextRef hmac = hmacAlloc();
204 hmacInit(hmac, keyPtr, keyLen, CSSM_TRUE);
205 hmacUpdate(hmac, textPtr, textLen);
206 hmacFinal(hmac, resultPtr);
207 hmacFree(hmac);
208 }
209