2  * Copyright (c) 2000-2001,2011-2014 Apple 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,2011-2014 Apple Inc. All Rights Reserved. 
  27 #if     CRYPTKIT_HMAC_LEGACY 
  29 #include "HmacSha1Legacy.h" 
  33 #include <Security/SecBase.h> 
  34 #define kHMACSHA1DigestSize  20 
  36 /* XXX These should really be in ckSHA1.h */ 
  37 #define kSHA1DigestSize         20 
  38 #define kSHA1BlockSize          64 
  41  * bug-for-bug compatible with BSAFE 4.0. See 
  42  * BSafe/bsource/algs/ahchhmac.c. 
  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.  
  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 
  59 struct hmacLegacyContext 
{ 
  61         UInt8   k_ipad
[kSHA1BlockSize
]; 
  62         UInt8   k_opad
[kSHA1BlockSize
]; 
  65 hmacLegacyContextRef 
hmacLegacyAlloc(void) 
  67         hmacLegacyContextRef hmac 
=  
  68                 (hmacLegacyContextRef
)malloc(sizeof(struct hmacLegacyContext
)); 
  69         memset(hmac
, 0, sizeof(struct hmacLegacyContext
)); 
  74         hmacLegacyContextRef hmac
) 
  77                 if(hmac
->sha1Context 
!= NULL
) { 
  78                         sha1Free (hmac
->sha1Context
); 
  80                 memset(hmac
, 0, sizeof(struct hmacLegacyContext
)); 
  86 OSStatus 
hmacLegacyInit( 
  87         hmacLegacyContextRef hmac
, 
  94         if(hmac
->sha1Context 
== NULL
) { 
  95                 hmac
->sha1Context 
= sha1Alloc(); 
  96                 if(hmac
->sha1Context 
== NULL
) { 
  97                         return errSecAllocate
; 
 101                 sha1Reinit(hmac
->sha1Context
); 
 103         /* this implementation requires a 20-byte key */ 
 104         if (keyLen 
!= kSHA1DigestSize
) { 
 108         key 
= (UInt8
*)keyPtr
; 
 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. 
 117         /* Copy the key into k_ipad and k_opad while doing the XOR. */ 
 118         for (byte 
= 0; byte 
< keyLen
; byte
++) 
 120                 hmac
->k_ipad
[byte
] = key
[byte
] ^ 0x36; 
 121                 hmac
->k_opad
[byte
] = key
[byte
] ^ 0x5c; 
 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
); 
 129         /* remainder happens in update */ 
 130         return errSecSuccess
; 
 133 OSStatus 
hmacLegacyUpdate( 
 134         hmacLegacyContextRef hmac
, 
 138         UInt8 innerDigest
[kSHA1DigestSize
]; 
 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
); 
 145         /* reset context (BSAFE does this implicitly in a final() call) */ 
 146         sha1Reinit(hmac
->sha1Context
); 
 148         /* compute SHA1(k_opad || innerDigest) */ 
 149         sha1AddData (hmac
->sha1Context
, hmac
->k_opad
, kSHA1BlockSize
); 
 150         sha1AddData (hmac
->sha1Context
, innerDigest
, kSHA1DigestSize
); 
 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
; 
 157 OSStatus 
hmacLegacyFinal( 
 158         hmacLegacyContextRef hmac
, 
 159         void *resultPtr
)                // caller mallocs, must be HMACSHA1_OUT_SIZE bytes 
 161         memcpy (resultPtr
, sha1Digest (hmac
->sha1Context
), kSHA1DigestSize
); 
 162         return errSecSuccess
; 
 165 #endif  /* CRYPTKIT_HMAC_LEGACY */