Dependents:   HTTPClient-SSL HTTPClient-SSL HTTPClient-SSL HTTPClient-SSL

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers hmac.c Source File

hmac.c

00001 /* hmac.c
00002  *
00003  * Copyright (C) 2006-2014 wolfSSL Inc.
00004  *
00005  * This file is part of CyaSSL.
00006  *
00007  * CyaSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * CyaSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023     #include <config.h>
00024 #endif
00025 
00026 #include <cyassl/ctaocrypt/settings.h>
00027 
00028 #ifndef NO_HMAC
00029 
00030 #ifdef CYASSL_PIC32MZ_HASH
00031 
00032 #define InitMd5   InitMd5_sw
00033 #define Md5Update Md5Update_sw
00034 #define Md5Final  Md5Final_sw
00035 
00036 #define InitSha   InitSha_sw
00037 #define ShaUpdate ShaUpdate_sw
00038 #define ShaFinal  ShaFinal_sw
00039 
00040 #define InitSha256   InitSha256_sw
00041 #define Sha256Update Sha256Update_sw
00042 #define Sha256Final  Sha256Final_sw
00043 
00044 #endif
00045 
00046 #ifdef HAVE_FIPS
00047     /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
00048     #define FIPS_NO_WRAPPERS
00049 #endif
00050 
00051 #include <cyassl/ctaocrypt/hmac.h>
00052 #include <cyassl/ctaocrypt/error-crypt.h>
00053 
00054 
00055 #ifdef HAVE_CAVIUM
00056     static void HmacCaviumFinal(Hmac* hmac, byte* hash);
00057     static void HmacCaviumUpdate(Hmac* hmac, const byte* msg, word32 length);
00058     static void HmacCaviumSetKey(Hmac* hmac, int type, const byte* key,
00059                                  word32 length);
00060 #endif
00061 
00062 static int InitHmac(Hmac* hmac, int type)
00063 {
00064     int ret = 0;
00065 
00066     hmac->innerHashKeyed = 0;
00067     hmac->macType = (byte)type;
00068 
00069     if (!(type == MD5 || type == SHA    || type == SHA256 || type == SHA384
00070                       || type == SHA512 || type == BLAKE2B_ID))
00071         return BAD_FUNC_ARG;
00072 
00073     switch (type) {
00074         #ifndef NO_MD5
00075         case MD5:
00076             InitMd5(&hmac->hash.md5);
00077         break;
00078         #endif
00079 
00080         #ifndef NO_SHA
00081         case SHA:
00082             ret = InitSha(&hmac->hash.sha);
00083         break;
00084         #endif
00085         
00086         #ifndef NO_SHA256
00087         case SHA256:
00088             ret = InitSha256(&hmac->hash.sha256);
00089         break;
00090         #endif
00091         
00092         #ifdef CYASSL_SHA384
00093         case SHA384:
00094             ret = InitSha384(&hmac->hash.sha384);
00095         break;
00096         #endif
00097         
00098         #ifdef CYASSL_SHA512
00099         case SHA512:
00100             ret = InitSha512(&hmac->hash.sha512);
00101         break;
00102         #endif
00103         
00104         #ifdef HAVE_BLAKE2 
00105         case BLAKE2B_ID:
00106             ret = InitBlake2b(&hmac->hash.blake2b, BLAKE2B_256);
00107         break;
00108         #endif
00109         
00110         default:
00111             return BAD_FUNC_ARG;
00112     }
00113 
00114     return ret;
00115 }
00116 
00117 
00118 int HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length)
00119 {
00120     byte*  ip = (byte*) hmac->ipad;
00121     byte*  op = (byte*) hmac->opad;
00122     word32 i, hmac_block_size = 0;
00123     int    ret;
00124 
00125 #ifdef HAVE_CAVIUM
00126     if (hmac->magic == CYASSL_HMAC_CAVIUM_MAGIC)
00127         return HmacCaviumSetKey(hmac, type, key, length);
00128 #endif
00129 
00130     ret = InitHmac(hmac, type);
00131     if (ret != 0)
00132         return ret;
00133 
00134 #ifdef HAVE_FIPS
00135     if (length < HMAC_FIPS_MIN_KEY)
00136         return HMAC_MIN_KEYLEN_E;
00137 #endif
00138 
00139     switch (hmac->macType) {
00140         #ifndef NO_MD5
00141         case MD5:
00142         {
00143             hmac_block_size = MD5_BLOCK_SIZE;
00144             if (length <= MD5_BLOCK_SIZE) {
00145                 XMEMCPY(ip, key, length);
00146             }
00147             else {
00148                 Md5Update(&hmac->hash.md5, key, length);
00149                 Md5Final(&hmac->hash.md5, ip);
00150                 length = MD5_DIGEST_SIZE;
00151             }
00152         }
00153         break;
00154         #endif
00155 
00156         #ifndef NO_SHA
00157         case SHA:
00158         {
00159             hmac_block_size = SHA_BLOCK_SIZE;
00160             if (length <= SHA_BLOCK_SIZE) {
00161                 XMEMCPY(ip, key, length);
00162             }
00163             else {
00164                 ShaUpdate(&hmac->hash.sha, key, length);
00165                 ShaFinal(&hmac->hash.sha, ip);
00166                 length = SHA_DIGEST_SIZE;
00167             }
00168         }
00169         break;
00170         #endif
00171 
00172         #ifndef NO_SHA256
00173         case SHA256:
00174         {
00175             hmac_block_size = SHA256_BLOCK_SIZE;
00176             if (length <= SHA256_BLOCK_SIZE) {
00177                 XMEMCPY(ip, key, length);
00178             }
00179             else {
00180                 ret = Sha256Update(&hmac->hash.sha256, key, length);
00181                 if (ret != 0)
00182                     return ret;
00183 
00184                 ret = Sha256Final(&hmac->hash.sha256, ip);
00185                 if (ret != 0)
00186                     return ret;
00187 
00188                 length = SHA256_DIGEST_SIZE;
00189             }
00190         }
00191         break;
00192         #endif
00193 
00194         #ifdef CYASSL_SHA384
00195         case SHA384:
00196         {
00197             hmac_block_size = SHA384_BLOCK_SIZE;
00198             if (length <= SHA384_BLOCK_SIZE) {
00199                 XMEMCPY(ip, key, length);
00200             }
00201             else {
00202                 ret = Sha384Update(&hmac->hash.sha384, key, length);
00203                 if (ret != 0)
00204                     return ret;
00205 
00206                 ret = Sha384Final(&hmac->hash.sha384, ip);
00207                 if (ret != 0)
00208                     return ret;
00209 
00210                 length = SHA384_DIGEST_SIZE;
00211             }
00212         }
00213         break;
00214         #endif
00215 
00216         #ifdef CYASSL_SHA512
00217         case SHA512:
00218         {
00219             hmac_block_size = SHA512_BLOCK_SIZE;
00220             if (length <= SHA512_BLOCK_SIZE) {
00221                 XMEMCPY(ip, key, length);
00222             }
00223             else {
00224                 ret = Sha512Update(&hmac->hash.sha512, key, length);
00225                 if (ret != 0)
00226                     return ret;
00227 
00228                 ret = Sha512Final(&hmac->hash.sha512, ip);
00229                 if (ret != 0)
00230                     return ret;
00231 
00232                 length = SHA512_DIGEST_SIZE;
00233             }
00234         }
00235         break;
00236         #endif
00237 
00238         #ifdef HAVE_BLAKE2 
00239         case BLAKE2B_ID:
00240         {
00241             hmac_block_size = BLAKE2B_BLOCKBYTES;
00242             if (length <= BLAKE2B_BLOCKBYTES) {
00243                 XMEMCPY(ip, key, length);
00244             }
00245             else {
00246                 ret = Blake2bUpdate(&hmac->hash.blake2b, key, length);
00247                 if (ret != 0)
00248                     return ret;
00249 
00250                 ret = Blake2bFinal(&hmac->hash.blake2b, ip, BLAKE2B_256);
00251                 if (ret != 0)
00252                     return ret;
00253 
00254                 length = BLAKE2B_256;
00255             }
00256         }
00257         break;
00258         #endif
00259 
00260         default:
00261             return BAD_FUNC_ARG;
00262     }
00263     if (length < hmac_block_size)
00264         XMEMSET(ip + length, 0, hmac_block_size - length);
00265 
00266     for(i = 0; i < hmac_block_size; i++) {
00267         op[i] = ip[i] ^ OPAD;
00268         ip[i] ^= IPAD;
00269     }
00270     return 0;
00271 }
00272 
00273 
00274 static int HmacKeyInnerHash(Hmac* hmac)
00275 {
00276     int ret = 0;
00277 
00278     switch (hmac->macType) {
00279         #ifndef NO_MD5
00280         case MD5:
00281             Md5Update(&hmac->hash.md5, (byte*) hmac->ipad, MD5_BLOCK_SIZE);
00282         break;
00283         #endif
00284 
00285         #ifndef NO_SHA
00286         case SHA:
00287             ShaUpdate(&hmac->hash.sha, (byte*) hmac->ipad, SHA_BLOCK_SIZE);
00288         break;
00289         #endif
00290 
00291         #ifndef NO_SHA256
00292         case SHA256:
00293             ret = Sha256Update(&hmac->hash.sha256,
00294                                          (byte*) hmac->ipad, SHA256_BLOCK_SIZE);
00295             if (ret != 0)
00296                 return ret;
00297         break;
00298         #endif
00299 
00300         #ifdef CYASSL_SHA384
00301         case SHA384:
00302             ret = Sha384Update(&hmac->hash.sha384,
00303                                          (byte*) hmac->ipad, SHA384_BLOCK_SIZE);
00304             if (ret != 0)
00305                 return ret;
00306         break;
00307         #endif
00308 
00309         #ifdef CYASSL_SHA512
00310         case SHA512:
00311             ret = Sha512Update(&hmac->hash.sha512,
00312                                          (byte*) hmac->ipad, SHA512_BLOCK_SIZE);
00313             if (ret != 0)
00314                 return ret;
00315         break;
00316         #endif
00317 
00318         #ifdef HAVE_BLAKE2 
00319         case BLAKE2B_ID:
00320             ret = Blake2bUpdate(&hmac->hash.blake2b,
00321                                          (byte*) hmac->ipad,BLAKE2B_BLOCKBYTES);
00322             if (ret != 0)
00323                 return ret;
00324         break;
00325         #endif
00326 
00327         default:
00328         break;
00329     }
00330 
00331     hmac->innerHashKeyed = 1;
00332 
00333     return ret;
00334 }
00335 
00336 
00337 int HmacUpdate(Hmac* hmac, const byte* msg, word32 length)
00338 {
00339     int ret;
00340 
00341 #ifdef HAVE_CAVIUM
00342     if (hmac->magic == CYASSL_HMAC_CAVIUM_MAGIC)
00343         return HmacCaviumUpdate(hmac, msg, length);
00344 #endif
00345 
00346     if (!hmac->innerHashKeyed) {
00347         ret = HmacKeyInnerHash(hmac);
00348         if (ret != 0)
00349             return ret;
00350     }
00351 
00352     switch (hmac->macType) {
00353         #ifndef NO_MD5
00354         case MD5:
00355             Md5Update(&hmac->hash.md5, msg, length);
00356         break;
00357         #endif
00358 
00359         #ifndef NO_SHA
00360         case SHA:
00361             ShaUpdate(&hmac->hash.sha, msg, length);
00362         break;
00363         #endif
00364 
00365         #ifndef NO_SHA256
00366         case SHA256:
00367             ret = Sha256Update(&hmac->hash.sha256, msg, length);
00368             if (ret != 0)
00369                 return ret;
00370         break;
00371         #endif
00372 
00373         #ifdef CYASSL_SHA384
00374         case SHA384:
00375             ret = Sha384Update(&hmac->hash.sha384, msg, length);
00376             if (ret != 0)
00377                 return ret;
00378         break;
00379         #endif
00380 
00381         #ifdef CYASSL_SHA512
00382         case SHA512:
00383             ret = Sha512Update(&hmac->hash.sha512, msg, length);
00384             if (ret != 0)
00385                 return ret;
00386         break;
00387         #endif
00388 
00389         #ifdef HAVE_BLAKE2 
00390         case BLAKE2B_ID:
00391             ret = Blake2bUpdate(&hmac->hash.blake2b, msg, length);
00392             if (ret != 0)
00393                 return ret;
00394         break;
00395         #endif
00396 
00397         default:
00398         break;
00399     }
00400 
00401     return 0;
00402 }
00403 
00404 
00405 int HmacFinal(Hmac* hmac, byte* hash)
00406 {
00407     int ret;
00408 
00409 #ifdef HAVE_CAVIUM
00410     if (hmac->magic == CYASSL_HMAC_CAVIUM_MAGIC)
00411         return HmacCaviumFinal(hmac, hash);
00412 #endif
00413 
00414     if (!hmac->innerHashKeyed) {
00415         ret = HmacKeyInnerHash(hmac);
00416         if (ret != 0)
00417             return ret;
00418     }
00419 
00420     switch (hmac->macType) {
00421         #ifndef NO_MD5
00422         case MD5:
00423         {
00424             Md5Final(&hmac->hash.md5, (byte*) hmac->innerHash);
00425 
00426             Md5Update(&hmac->hash.md5, (byte*) hmac->opad, MD5_BLOCK_SIZE);
00427             Md5Update(&hmac->hash.md5,
00428                                      (byte*) hmac->innerHash, MD5_DIGEST_SIZE);
00429 
00430             Md5Final(&hmac->hash.md5, hash);
00431         }
00432         break;
00433         #endif
00434 
00435         #ifndef NO_SHA
00436         case SHA:
00437         {
00438             ShaFinal(&hmac->hash.sha, (byte*) hmac->innerHash);
00439 
00440             ShaUpdate(&hmac->hash.sha, (byte*) hmac->opad, SHA_BLOCK_SIZE);
00441             ShaUpdate(&hmac->hash.sha,
00442                                      (byte*) hmac->innerHash, SHA_DIGEST_SIZE);
00443 
00444             ShaFinal(&hmac->hash.sha, hash);
00445         }
00446         break;
00447         #endif
00448 
00449         #ifndef NO_SHA256
00450         case SHA256:
00451         {
00452             ret = Sha256Final(&hmac->hash.sha256, (byte*) hmac->innerHash);
00453             if (ret != 0)
00454                 return ret;
00455 
00456             ret = Sha256Update(&hmac->hash.sha256,
00457                                 (byte*) hmac->opad, SHA256_BLOCK_SIZE);
00458             if (ret != 0)
00459                 return ret;
00460 
00461             ret = Sha256Update(&hmac->hash.sha256,
00462                                 (byte*) hmac->innerHash, SHA256_DIGEST_SIZE);
00463             if (ret != 0)
00464                 return ret;
00465 
00466             ret = Sha256Final(&hmac->hash.sha256, hash);
00467             if (ret != 0)
00468                 return ret;
00469         }
00470         break;
00471         #endif
00472 
00473         #ifdef CYASSL_SHA384
00474         case SHA384:
00475         {
00476             ret = Sha384Final(&hmac->hash.sha384, (byte*) hmac->innerHash);
00477             if (ret != 0)
00478                 return ret;
00479 
00480             ret = Sha384Update(&hmac->hash.sha384,
00481                                  (byte*) hmac->opad, SHA384_BLOCK_SIZE);
00482             if (ret != 0)
00483                 return ret;
00484 
00485             ret = Sha384Update(&hmac->hash.sha384,
00486                                  (byte*) hmac->innerHash, SHA384_DIGEST_SIZE);
00487             if (ret != 0)
00488                 return ret;
00489 
00490             ret = Sha384Final(&hmac->hash.sha384, hash);
00491             if (ret != 0)
00492                 return ret;
00493         }
00494         break;
00495         #endif
00496 
00497         #ifdef CYASSL_SHA512
00498         case SHA512:
00499         {
00500             ret = Sha512Final(&hmac->hash.sha512, (byte*) hmac->innerHash);
00501             if (ret != 0)
00502                 return ret;
00503 
00504             ret = Sha512Update(&hmac->hash.sha512,
00505                                  (byte*) hmac->opad, SHA512_BLOCK_SIZE);
00506             if (ret != 0)
00507                 return ret;
00508 
00509             ret = Sha512Update(&hmac->hash.sha512,
00510                                  (byte*) hmac->innerHash, SHA512_DIGEST_SIZE);
00511             if (ret != 0)
00512                 return ret;
00513 
00514             ret = Sha512Final(&hmac->hash.sha512, hash);
00515             if (ret != 0)
00516                 return ret;
00517         }
00518         break;
00519         #endif
00520 
00521         #ifdef HAVE_BLAKE2 
00522         case BLAKE2B_ID:
00523         {
00524             ret = Blake2bFinal(&hmac->hash.blake2b, (byte*) hmac->innerHash,
00525                          BLAKE2B_256);
00526             if (ret != 0)
00527                 return ret;
00528 
00529             ret = Blake2bUpdate(&hmac->hash.blake2b,
00530                                  (byte*) hmac->opad, BLAKE2B_BLOCKBYTES);
00531             if (ret != 0)
00532                 return ret;
00533 
00534             ret = Blake2bUpdate(&hmac->hash.blake2b,
00535                                  (byte*) hmac->innerHash, BLAKE2B_256);
00536             if (ret != 0)
00537                 return ret;
00538 
00539             ret = Blake2bFinal(&hmac->hash.blake2b, hash, BLAKE2B_256);
00540             if (ret != 0)
00541                 return ret;
00542         }
00543         break;
00544         #endif
00545 
00546         default:
00547         break;
00548     }
00549 
00550     hmac->innerHashKeyed = 0;
00551 
00552     return 0;
00553 }
00554 
00555 
00556 #ifdef HAVE_CAVIUM
00557 
00558 /* Initiliaze Hmac for use with Nitrox device */
00559 int HmacInitCavium(Hmac* hmac, int devId)
00560 {
00561     if (hmac == NULL)
00562         return -1;
00563 
00564     if (CspAllocContext(CONTEXT_SSL, &hmac->contextHandle, devId) != 0)
00565         return -1;
00566 
00567     hmac->keyLen  = 0;
00568     hmac->dataLen = 0;
00569     hmac->type    = 0;
00570     hmac->devId   = devId;
00571     hmac->magic   = CYASSL_HMAC_CAVIUM_MAGIC;
00572     hmac->data    = NULL;        /* buffered input data */
00573    
00574     hmac->innerHashKeyed = 0;
00575 
00576     return 0;
00577 }
00578 
00579 
00580 /* Free Hmac from use with Nitrox device */
00581 void HmacFreeCavium(Hmac* hmac)
00582 {
00583     if (hmac == NULL)
00584         return;
00585 
00586     CspFreeContext(CONTEXT_SSL, hmac->contextHandle, hmac->devId);
00587     hmac->magic = 0;
00588     XFREE(hmac->data, NULL, DYNAMIC_TYPE_CAVIUM_TMP);
00589     hmac->data = NULL;
00590 }
00591 
00592 
00593 static void HmacCaviumFinal(Hmac* hmac, byte* hash)
00594 {
00595     word32 requestId;
00596 
00597     if (CspHmac(CAVIUM_BLOCKING, hmac->type, NULL, hmac->keyLen,
00598                 (byte*)hmac->ipad, hmac->dataLen, hmac->data, hash, &requestId,
00599                 hmac->devId) != 0) {
00600         CYASSL_MSG("Cavium Hmac failed");
00601     } 
00602     hmac->innerHashKeyed = 0;  /* tell update to start over if used again */
00603 }
00604 
00605 
00606 static void HmacCaviumUpdate(Hmac* hmac, const byte* msg, word32 length)
00607 {
00608     word16 add = (word16)length;
00609     word32 total;
00610     byte*  tmp;
00611 
00612     if (length > CYASSL_MAX_16BIT) {
00613         CYASSL_MSG("Too big msg for cavium hmac");
00614         return;
00615     }
00616 
00617     if (hmac->innerHashKeyed == 0) {  /* starting new */
00618         hmac->dataLen        = 0;
00619         hmac->innerHashKeyed = 1;
00620     }
00621 
00622     total = add + hmac->dataLen;
00623     if (total > CYASSL_MAX_16BIT) {
00624         CYASSL_MSG("Too big msg for cavium hmac");
00625         return;
00626     }
00627 
00628     tmp = XMALLOC(hmac->dataLen + add, NULL,DYNAMIC_TYPE_CAVIUM_TMP);
00629     if (tmp == NULL) {
00630         CYASSL_MSG("Out of memory for cavium update");
00631         return;
00632     }
00633     if (hmac->dataLen)
00634         XMEMCPY(tmp, hmac->data,  hmac->dataLen);
00635     XMEMCPY(tmp + hmac->dataLen, msg, add);
00636         
00637     hmac->dataLen += add;
00638     XFREE(hmac->data, NULL, DYNAMIC_TYPE_CAVIUM_TMP);
00639     hmac->data = tmp;
00640 }
00641 
00642 
00643 static void HmacCaviumSetKey(Hmac* hmac, int type, const byte* key,
00644                              word32 length)
00645 {
00646     hmac->macType = (byte)type;
00647     if (type == MD5)
00648         hmac->type = MD5_TYPE;
00649     else if (type == SHA)
00650         hmac->type = SHA1_TYPE;
00651     else if (type == SHA256)
00652         hmac->type = SHA256_TYPE;
00653     else  {
00654         CYASSL_MSG("unsupported cavium hmac type");
00655     }
00656 
00657     hmac->innerHashKeyed = 0;  /* should we key Startup flag */
00658 
00659     hmac->keyLen = (word16)length;
00660     /* store key in ipad */
00661     XMEMCPY(hmac->ipad, key, length);
00662 }
00663 
00664 #endif /* HAVE_CAVIUM */
00665 
00666 int CyaSSL_GetHmacMaxSize(void)
00667 {
00668     return MAX_DIGEST_SIZE;
00669 }
00670 
00671 #ifdef HAVE_HKDF
00672 
00673 #ifndef min
00674 
00675     static INLINE word32 min(word32 a, word32 b)
00676     {
00677         return a > b ? b : a;
00678     }
00679 
00680 #endif /* min */
00681 
00682 
00683 static INLINE int GetHashSizeByType(int type)
00684 {
00685     if (!(type == MD5 || type == SHA    || type == SHA256 || type == SHA384
00686                       || type == SHA512 || type == BLAKE2B_ID))
00687         return BAD_FUNC_ARG;
00688 
00689     switch (type) {
00690         #ifndef NO_MD5
00691         case MD5:
00692             return MD5_DIGEST_SIZE;
00693         break;
00694         #endif
00695 
00696         #ifndef NO_SHA
00697         case SHA:
00698             return SHA_DIGEST_SIZE;
00699         break;
00700         #endif
00701         
00702         #ifndef NO_SHA256
00703         case SHA256:
00704             return SHA256_DIGEST_SIZE;
00705         break;
00706         #endif
00707         
00708         #ifdef CYASSL_SHA384
00709         case SHA384:
00710             return SHA384_DIGEST_SIZE;
00711         break;
00712         #endif
00713         
00714         #ifdef CYASSL_SHA512
00715         case SHA512:
00716             return SHA512_DIGEST_SIZE;
00717         break;
00718         #endif
00719         
00720         #ifdef HAVE_BLAKE2 
00721         case BLAKE2B_ID:
00722             return BLAKE2B_OUTBYTES;
00723         break;
00724         #endif
00725         
00726         default:
00727             return BAD_FUNC_ARG;
00728         break;
00729     }
00730 }
00731 
00732 
00733 /* HMAC-KDF with hash type, optional salt and info, return 0 on success */
00734 int HKDF(int type, const byte* inKey, word32 inKeySz,
00735                    const byte* salt,  word32 saltSz,
00736                    const byte* info,  word32 infoSz,
00737                    byte* out,         word32 outSz)
00738 {
00739     Hmac   myHmac;
00740 #ifdef CYASSL_SMALL_STACK
00741     byte* tmp;
00742     byte* prk;
00743 #else
00744     byte   tmp[MAX_DIGEST_SIZE]; /* localSalt helper and T */
00745     byte   prk[MAX_DIGEST_SIZE];
00746 #endif
00747     const  byte* localSalt;  /* either points to user input or tmp */
00748     int    hashSz = GetHashSizeByType(type);
00749     word32 outIdx = 0;
00750     byte   n = 0x1;
00751     int    ret;
00752 
00753     if (hashSz < 0)
00754         return BAD_FUNC_ARG;
00755 
00756 #ifdef CYASSL_SMALL_STACK
00757     tmp = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00758     if (tmp == NULL)
00759         return MEMORY_E;
00760 
00761     prk = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00762     if (prk == NULL) {
00763         XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00764         return MEMORY_E;
00765     }
00766 #endif
00767 
00768     localSalt = salt;
00769     if (localSalt == NULL) {
00770         XMEMSET(tmp, 0, hashSz);
00771         localSalt = tmp;
00772         saltSz    = hashSz;
00773     }
00774     
00775     do {
00776     ret = HmacSetKey(&myHmac, type, localSalt, saltSz);
00777     if (ret != 0)
00778         break;
00779     ret = HmacUpdate(&myHmac, inKey, inKeySz);
00780     if (ret != 0)
00781         break;
00782     ret = HmacFinal(&myHmac,  prk);
00783     } while (0);
00784 
00785     if (ret == 0) {
00786         while (outIdx < outSz) {
00787             int    tmpSz = (n == 1) ? 0 : hashSz;
00788             word32 left = outSz - outIdx;
00789 
00790             ret = HmacSetKey(&myHmac, type, prk, hashSz);
00791             if (ret != 0)
00792                 break;
00793             ret = HmacUpdate(&myHmac, tmp, tmpSz);
00794             if (ret != 0)
00795                 break;
00796             ret = HmacUpdate(&myHmac, info, infoSz);
00797             if (ret != 0)
00798                 break;
00799             ret = HmacUpdate(&myHmac, &n, 1);
00800             if (ret != 0)
00801                 break;
00802             ret = HmacFinal(&myHmac, tmp);
00803             if (ret != 0)
00804                 break;
00805 
00806             left = min(left, (word32)hashSz);
00807             XMEMCPY(out+outIdx, tmp, left);
00808 
00809             outIdx += hashSz;
00810             n++;
00811         }
00812     }
00813 
00814 #ifdef CYASSL_SMALL_STACK
00815     XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00816     XFREE(prk, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00817 #endif
00818 
00819     return ret;
00820 }
00821 
00822 #endif /* HAVE_HKDF */
00823 
00824 #endif /* NO_HMAC */
00825