2  * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. 
   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 
  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. 
  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 
  28 #if     CRYPTKIT_HMAC_LEGACY 
  30 #include "HmacSha1Legacy.h" 
  34 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 
  36 #define kHMACSHA1DigestSize  20 
  38 /* XXX These should really be in ckSHA1.h */ 
  39 #define kSHA1DigestSize         20 
  40 #define kSHA1BlockSize          64 
  43  * bug-for-bug compatible with BSAFE 4.0. See 
  44  * BSafe/bsource/algs/ahchhmac.c. 
  46  * This implementation, and the BSAFE implementation it emulates, work fine  
  47  * when calculating a MAC in a single update (init, update, final). They  
  48  * generate nonconforming MACs when performing multiple updates because  
  49  * the entire algorithm - both inner and outer digests - are performed  
  50  * in the update() step. As a result, if one e.g. calculates a MAC of  
  51  * a block of text with one update, and then calculates the MAC over the  
  52  * same block of text via two updates, different results will obtain.ÊThe  
  53  * incorrect result from the multiple-update scenario is repeatable if and  
  54  * only if the same boundaries (same update sizes) are observed on each operation.  
  56  * Because all of the data to be MAC'd is in fact protected by both levels of  
  57  * SHA1, and all of the key bits are used, this nonconforming implementation is 
  58  * believed to be as strong, cryptographically, as a conforming SHA1HMAC 
  61 struct hmacLegacyContext 
{ 
  63         UInt8   k_ipad
[kSHA1BlockSize
]; 
  64         UInt8   k_opad
[kSHA1BlockSize
]; 
  67 hmacLegacyContextRef 
hmacLegacyAlloc() 
  69         hmacLegacyContextRef hmac 
=  
  70                 (hmacLegacyContextRef
)malloc(sizeof(struct hmacLegacyContext
)); 
  71         memset(hmac
, 0, sizeof(struct hmacLegacyContext
)); 
  76         hmacLegacyContextRef hmac
) 
  79                 if(hmac
->sha1Context 
!= NULL
) { 
  80                         sha1Free (hmac
->sha1Context
); 
  82                 memset(hmac
, 0, sizeof(struct hmacLegacyContext
)); 
  88 OSStatus 
hmacLegacyInit( 
  89         hmacLegacyContextRef hmac
, 
  96         if(hmac
->sha1Context 
== NULL
) { 
  97                 hmac
->sha1Context 
= sha1Alloc(); 
  98                 if(hmac
->sha1Context 
== NULL
) { 
 103                 sha1Reinit(hmac
->sha1Context
); 
 105         /* this implementation requires a 20-byte key */ 
 106         if (keyLen 
!= kSHA1DigestSize
) { 
 110         key 
= (UInt8
*)keyPtr
; 
 112         /* The HMAC_SHA_1 transform looks like: 
 113            SHA1 (K XOR opad || SHA1 (K XOR ipad || text)) 
 114            Where K is a n byte key 
 115            ipad is the byte 0x36 repeated 64 times. 
 116            opad is the byte 0x5c repeated 64 times. 
 117            text is the data being protected. 
 119         /* Copy the key into k_ipad and k_opad while doing the XOR. */ 
 120         for (byte 
= 0; byte 
< keyLen
; byte
++) 
 122                 hmac
->k_ipad
[byte
] = key
[byte
] ^ 0x36; 
 123                 hmac
->k_opad
[byte
] = key
[byte
] ^ 0x5c; 
 126         /* Fill the remainder of k_ipad and k_opad with 0 XORed with  
 127          * appropriate value. */ 
 128         memset (hmac
->k_ipad 
+ keyLen
, 0x36, kSHA1BlockSize 
- keyLen
); 
 129         memset (hmac
->k_opad 
+ keyLen
, 0x5c, kSHA1BlockSize 
- keyLen
); 
 131         /* remainder happens in update */ 
 135 OSStatus 
hmacLegacyUpdate( 
 136         hmacLegacyContextRef hmac
, 
 140         UInt8 innerDigest
[kSHA1DigestSize
]; 
 142         /* compute SHA1(k_ipad || data) ==> innerDigest */ 
 143         sha1AddData (hmac
->sha1Context
, hmac
->k_ipad
, kSHA1BlockSize
); 
 144         sha1AddData (hmac
->sha1Context
, (UInt8
*)textPtr
, textLen
); 
 145         memcpy (innerDigest
, sha1Digest(hmac
->sha1Context
), kSHA1DigestSize
); 
 147         /* reset context (BSAFE does this implicitly in a final() call) */ 
 148         sha1Reinit(hmac
->sha1Context
); 
 150         /* compute SHA1(k_opad || innerDigest) */ 
 151         sha1AddData (hmac
->sha1Context
, hmac
->k_opad
, kSHA1BlockSize
); 
 152         sha1AddData (hmac
->sha1Context
, innerDigest
, kSHA1DigestSize
); 
 154         /* if there is another update coming, it gets added in to existing  
 155          * context; if the next step is a final, the current digest state is used. */ 
 159 OSStatus 
hmacLegacyFinal( 
 160         hmacLegacyContextRef hmac
, 
 161         void *resultPtr
)                // caller mallocs, must be HMACSHA1_OUT_SIZE bytes 
 163         memcpy (resultPtr
, sha1Digest (hmac
->sha1Context
), kSHA1DigestSize
); 
 167 #endif  /* CRYPTKIT_HMAC_LEGACY */