d 0773d / CyaSSL

Dependents:   CyaSSL_Example

Fork of CyaSSL by wolf 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     switch (hmac->macType) {
00135         #ifndef NO_MD5
00136         case MD5:
00137         {
00138             hmac_block_size = MD5_BLOCK_SIZE;
00139             if (length <= MD5_BLOCK_SIZE) {
00140                 XMEMCPY(ip, key, length);
00141             }
00142             else {
00143                 Md5Update(&hmac->hash.md5, key, length);
00144                 Md5Final(&hmac->hash.md5, ip);
00145                 length = MD5_DIGEST_SIZE;
00146             }
00147         }
00148         break;
00149         #endif
00150 
00151         #ifndef NO_SHA
00152         case SHA:
00153         {
00154             hmac_block_size = SHA_BLOCK_SIZE;
00155             if (length <= SHA_BLOCK_SIZE) {
00156                 XMEMCPY(ip, key, length);
00157             }
00158             else {
00159                 ShaUpdate(&hmac->hash.sha, key, length);
00160                 ShaFinal(&hmac->hash.sha, ip);
00161                 length = SHA_DIGEST_SIZE;
00162             }
00163         }
00164         break;
00165         #endif
00166 
00167         #ifndef NO_SHA256
00168         case SHA256:
00169         {
00170             hmac_block_size = SHA256_BLOCK_SIZE;
00171             if (length <= SHA256_BLOCK_SIZE) {
00172                 XMEMCPY(ip, key, length);
00173             }
00174             else {
00175                 ret = Sha256Update(&hmac->hash.sha256, key, length);
00176                 if (ret != 0)
00177                     return ret;
00178 
00179                 ret = Sha256Final(&hmac->hash.sha256, ip);
00180                 if (ret != 0)
00181                     return ret;
00182 
00183                 length = SHA256_DIGEST_SIZE;
00184             }
00185         }
00186         break;
00187         #endif
00188 
00189         #ifdef CYASSL_SHA384
00190         case SHA384:
00191         {
00192             hmac_block_size = SHA384_BLOCK_SIZE;
00193             if (length <= SHA384_BLOCK_SIZE) {
00194                 XMEMCPY(ip, key, length);
00195             }
00196             else {
00197                 ret = Sha384Update(&hmac->hash.sha384, key, length);
00198                 if (ret != 0)
00199                     return ret;
00200 
00201                 ret = Sha384Final(&hmac->hash.sha384, ip);
00202                 if (ret != 0)
00203                     return ret;
00204 
00205                 length = SHA384_DIGEST_SIZE;
00206             }
00207         }
00208         break;
00209         #endif
00210 
00211         #ifdef CYASSL_SHA512
00212         case SHA512:
00213         {
00214             hmac_block_size = SHA512_BLOCK_SIZE;
00215             if (length <= SHA512_BLOCK_SIZE) {
00216                 XMEMCPY(ip, key, length);
00217             }
00218             else {
00219                 ret = Sha512Update(&hmac->hash.sha512, key, length);
00220                 if (ret != 0)
00221                     return ret;
00222 
00223                 ret = Sha512Final(&hmac->hash.sha512, ip);
00224                 if (ret != 0)
00225                     return ret;
00226 
00227                 length = SHA512_DIGEST_SIZE;
00228             }
00229         }
00230         break;
00231         #endif
00232 
00233         #ifdef HAVE_BLAKE2 
00234         case BLAKE2B_ID:
00235         {
00236             hmac_block_size = BLAKE2B_BLOCKBYTES;
00237             if (length <= BLAKE2B_BLOCKBYTES) {
00238                 XMEMCPY(ip, key, length);
00239             }
00240             else {
00241                 ret = Blake2bUpdate(&hmac->hash.blake2b, key, length);
00242                 if (ret != 0)
00243                     return ret;
00244 
00245                 ret = Blake2bFinal(&hmac->hash.blake2b, ip, BLAKE2B_256);
00246                 if (ret != 0)
00247                     return ret;
00248 
00249                 length = BLAKE2B_256;
00250             }
00251         }
00252         break;
00253         #endif
00254 
00255         default:
00256             return BAD_FUNC_ARG;
00257     }
00258     if (length < hmac_block_size)
00259         XMEMSET(ip + length, 0, hmac_block_size - length);
00260 
00261     for(i = 0; i < hmac_block_size; i++) {
00262         op[i] = ip[i] ^ OPAD;
00263         ip[i] ^= IPAD;
00264     }
00265     return 0;
00266 }
00267 
00268 
00269 static int HmacKeyInnerHash(Hmac* hmac)
00270 {
00271     int ret = 0;
00272 
00273     switch (hmac->macType) {
00274         #ifndef NO_MD5
00275         case MD5:
00276             Md5Update(&hmac->hash.md5, (byte*) hmac->ipad, MD5_BLOCK_SIZE);
00277         break;
00278         #endif
00279 
00280         #ifndef NO_SHA
00281         case SHA:
00282             ShaUpdate(&hmac->hash.sha, (byte*) hmac->ipad, SHA_BLOCK_SIZE);
00283         break;
00284         #endif
00285 
00286         #ifndef NO_SHA256
00287         case SHA256:
00288             ret = Sha256Update(&hmac->hash.sha256,
00289                                          (byte*) hmac->ipad, SHA256_BLOCK_SIZE);
00290             if (ret != 0)
00291                 return ret;
00292         break;
00293         #endif
00294 
00295         #ifdef CYASSL_SHA384
00296         case SHA384:
00297             ret = Sha384Update(&hmac->hash.sha384,
00298                                          (byte*) hmac->ipad, SHA384_BLOCK_SIZE);
00299             if (ret != 0)
00300                 return ret;
00301         break;
00302         #endif
00303 
00304         #ifdef CYASSL_SHA512
00305         case SHA512:
00306             ret = Sha512Update(&hmac->hash.sha512,
00307                                          (byte*) hmac->ipad, SHA512_BLOCK_SIZE);
00308             if (ret != 0)
00309                 return ret;
00310         break;
00311         #endif
00312 
00313         #ifdef HAVE_BLAKE2 
00314         case BLAKE2B_ID:
00315             ret = Blake2bUpdate(&hmac->hash.blake2b,
00316                                          (byte*) hmac->ipad,BLAKE2B_BLOCKBYTES);
00317             if (ret != 0)
00318                 return ret;
00319         break;
00320         #endif
00321 
00322         default:
00323         break;
00324     }
00325 
00326     hmac->innerHashKeyed = 1;
00327 
00328     return ret;
00329 }
00330 
00331 
00332 int HmacUpdate(Hmac* hmac, const byte* msg, word32 length)
00333 {
00334     int ret;
00335 
00336 #ifdef HAVE_CAVIUM
00337     if (hmac->magic == CYASSL_HMAC_CAVIUM_MAGIC)
00338         return HmacCaviumUpdate(hmac, msg, length);
00339 #endif
00340 
00341     if (!hmac->innerHashKeyed) {
00342         ret = HmacKeyInnerHash(hmac);
00343         if (ret != 0)
00344             return ret;
00345     }
00346 
00347     switch (hmac->macType) {
00348         #ifndef NO_MD5
00349         case MD5:
00350             Md5Update(&hmac->hash.md5, msg, length);
00351         break;
00352         #endif
00353 
00354         #ifndef NO_SHA
00355         case SHA:
00356             ShaUpdate(&hmac->hash.sha, msg, length);
00357         break;
00358         #endif
00359 
00360         #ifndef NO_SHA256
00361         case SHA256:
00362             ret = Sha256Update(&hmac->hash.sha256, msg, length);
00363             if (ret != 0)
00364                 return ret;
00365         break;
00366         #endif
00367 
00368         #ifdef CYASSL_SHA384
00369         case SHA384:
00370             ret = Sha384Update(&hmac->hash.sha384, msg, length);
00371             if (ret != 0)
00372                 return ret;
00373         break;
00374         #endif
00375 
00376         #ifdef CYASSL_SHA512
00377         case SHA512:
00378             ret = Sha512Update(&hmac->hash.sha512, msg, length);
00379             if (ret != 0)
00380                 return ret;
00381         break;
00382         #endif
00383 
00384         #ifdef HAVE_BLAKE2 
00385         case BLAKE2B_ID:
00386             ret = Blake2bUpdate(&hmac->hash.blake2b, msg, length);
00387             if (ret != 0)
00388                 return ret;
00389         break;
00390         #endif
00391 
00392         default:
00393         break;
00394     }
00395 
00396     return 0;
00397 }
00398 
00399 
00400 int HmacFinal(Hmac* hmac, byte* hash)
00401 {
00402     int ret;
00403 
00404 #ifdef HAVE_CAVIUM
00405     if (hmac->magic == CYASSL_HMAC_CAVIUM_MAGIC)
00406         return HmacCaviumFinal(hmac, hash);
00407 #endif
00408 
00409     if (!hmac->innerHashKeyed) {
00410         ret = HmacKeyInnerHash(hmac);
00411         if (ret != 0)
00412             return ret;
00413     }
00414 
00415     switch (hmac->macType) {
00416         #ifndef NO_MD5
00417         case MD5:
00418         {
00419             Md5Final(&hmac->hash.md5, (byte*) hmac->innerHash);
00420 
00421             Md5Update(&hmac->hash.md5, (byte*) hmac->opad, MD5_BLOCK_SIZE);
00422             Md5Update(&hmac->hash.md5,
00423                                      (byte*) hmac->innerHash, MD5_DIGEST_SIZE);
00424 
00425             Md5Final(&hmac->hash.md5, hash);
00426         }
00427         break;
00428         #endif
00429 
00430         #ifndef NO_SHA
00431         case SHA:
00432         {
00433             ShaFinal(&hmac->hash.sha, (byte*) hmac->innerHash);
00434 
00435             ShaUpdate(&hmac->hash.sha, (byte*) hmac->opad, SHA_BLOCK_SIZE);
00436             ShaUpdate(&hmac->hash.sha,
00437                                      (byte*) hmac->innerHash, SHA_DIGEST_SIZE);
00438 
00439             ShaFinal(&hmac->hash.sha, hash);
00440         }
00441         break;
00442         #endif
00443 
00444         #ifndef NO_SHA256
00445         case SHA256:
00446         {
00447             ret = Sha256Final(&hmac->hash.sha256, (byte*) hmac->innerHash);
00448             if (ret != 0)
00449                 return ret;
00450 
00451             ret = Sha256Update(&hmac->hash.sha256,
00452                                 (byte*) hmac->opad, SHA256_BLOCK_SIZE);
00453             if (ret != 0)
00454                 return ret;
00455 
00456             ret = Sha256Update(&hmac->hash.sha256,
00457                                 (byte*) hmac->innerHash, SHA256_DIGEST_SIZE);
00458             if (ret != 0)
00459                 return ret;
00460 
00461             ret = Sha256Final(&hmac->hash.sha256, hash);
00462             if (ret != 0)
00463                 return ret;
00464         }
00465         break;
00466         #endif
00467 
00468         #ifdef CYASSL_SHA384
00469         case SHA384:
00470         {
00471             ret = Sha384Final(&hmac->hash.sha384, (byte*) hmac->innerHash);
00472             if (ret != 0)
00473                 return ret;
00474 
00475             ret = Sha384Update(&hmac->hash.sha384,
00476                                  (byte*) hmac->opad, SHA384_BLOCK_SIZE);
00477             if (ret != 0)
00478                 return ret;
00479 
00480             ret = Sha384Update(&hmac->hash.sha384,
00481                                  (byte*) hmac->innerHash, SHA384_DIGEST_SIZE);
00482             if (ret != 0)
00483                 return ret;
00484 
00485             ret = Sha384Final(&hmac->hash.sha384, hash);
00486             if (ret != 0)
00487                 return ret;
00488         }
00489         break;
00490         #endif
00491 
00492         #ifdef CYASSL_SHA512
00493         case SHA512:
00494         {
00495             ret = Sha512Final(&hmac->hash.sha512, (byte*) hmac->innerHash);
00496             if (ret != 0)
00497                 return ret;
00498 
00499             ret = Sha512Update(&hmac->hash.sha512,
00500                                  (byte*) hmac->opad, SHA512_BLOCK_SIZE);
00501             if (ret != 0)
00502                 return ret;
00503 
00504             ret = Sha512Update(&hmac->hash.sha512,
00505                                  (byte*) hmac->innerHash, SHA512_DIGEST_SIZE);
00506             if (ret != 0)
00507                 return ret;
00508 
00509             ret = Sha512Final(&hmac->hash.sha512, hash);
00510             if (ret != 0)
00511                 return ret;
00512         }
00513         break;
00514         #endif
00515 
00516         #ifdef HAVE_BLAKE2 
00517         case BLAKE2B_ID:
00518         {
00519             ret = Blake2bFinal(&hmac->hash.blake2b, (byte*) hmac->innerHash,
00520                          BLAKE2B_256);
00521             if (ret != 0)
00522                 return ret;
00523 
00524             ret = Blake2bUpdate(&hmac->hash.blake2b,
00525                                  (byte*) hmac->opad, BLAKE2B_BLOCKBYTES);
00526             if (ret != 0)
00527                 return ret;
00528 
00529             ret = Blake2bUpdate(&hmac->hash.blake2b,
00530                                  (byte*) hmac->innerHash, BLAKE2B_256);
00531             if (ret != 0)
00532                 return ret;
00533 
00534             ret = Blake2bFinal(&hmac->hash.blake2b, hash, BLAKE2B_256);
00535             if (ret != 0)
00536                 return ret;
00537         }
00538         break;
00539         #endif
00540 
00541         default:
00542         break;
00543     }
00544 
00545     hmac->innerHashKeyed = 0;
00546 
00547     return 0;
00548 }
00549 
00550 
00551 #ifdef HAVE_CAVIUM
00552 
00553 /* Initiliaze Hmac for use with Nitrox device */
00554 int HmacInitCavium(Hmac* hmac, int devId)
00555 {
00556     if (hmac == NULL)
00557         return -1;
00558 
00559     if (CspAllocContext(CONTEXT_SSL, &hmac->contextHandle, devId) != 0)
00560         return -1;
00561 
00562     hmac->keyLen  = 0;
00563     hmac->dataLen = 0;
00564     hmac->type    = 0;
00565     hmac->devId   = devId;
00566     hmac->magic   = CYASSL_HMAC_CAVIUM_MAGIC;
00567     hmac->data    = NULL;        /* buffered input data */
00568    
00569     hmac->innerHashKeyed = 0;
00570 
00571     return 0;
00572 }
00573 
00574 
00575 /* Free Hmac from use with Nitrox device */
00576 void HmacFreeCavium(Hmac* hmac)
00577 {
00578     if (hmac == NULL)
00579         return;
00580 
00581     CspFreeContext(CONTEXT_SSL, hmac->contextHandle, hmac->devId);
00582     hmac->magic = 0;
00583     XFREE(hmac->data, NULL, DYNAMIC_TYPE_CAVIUM_TMP);
00584     hmac->data = NULL;
00585 }
00586 
00587 
00588 static void HmacCaviumFinal(Hmac* hmac, byte* hash)
00589 {
00590     word32 requestId;
00591 
00592     if (CspHmac(CAVIUM_BLOCKING, hmac->type, NULL, hmac->keyLen,
00593                 (byte*)hmac->ipad, hmac->dataLen, hmac->data, hash, &requestId,
00594                 hmac->devId) != 0) {
00595         CYASSL_MSG("Cavium Hmac failed");
00596     } 
00597     hmac->innerHashKeyed = 0;  /* tell update to start over if used again */
00598 }
00599 
00600 
00601 static void HmacCaviumUpdate(Hmac* hmac, const byte* msg, word32 length)
00602 {
00603     word16 add = (word16)length;
00604     word32 total;
00605     byte*  tmp;
00606 
00607     if (length > CYASSL_MAX_16BIT) {
00608         CYASSL_MSG("Too big msg for cavium hmac");
00609         return;
00610     }
00611 
00612     if (hmac->innerHashKeyed == 0) {  /* starting new */
00613         hmac->dataLen        = 0;
00614         hmac->innerHashKeyed = 1;
00615     }
00616 
00617     total = add + hmac->dataLen;
00618     if (total > CYASSL_MAX_16BIT) {
00619         CYASSL_MSG("Too big msg for cavium hmac");
00620         return;
00621     }
00622 
00623     tmp = XMALLOC(hmac->dataLen + add, NULL,DYNAMIC_TYPE_CAVIUM_TMP);
00624     if (tmp == NULL) {
00625         CYASSL_MSG("Out of memory for cavium update");
00626         return;
00627     }
00628     if (hmac->dataLen)
00629         XMEMCPY(tmp, hmac->data,  hmac->dataLen);
00630     XMEMCPY(tmp + hmac->dataLen, msg, add);
00631         
00632     hmac->dataLen += add;
00633     XFREE(hmac->data, NULL, DYNAMIC_TYPE_CAVIUM_TMP);
00634     hmac->data = tmp;
00635 }
00636 
00637 
00638 static void HmacCaviumSetKey(Hmac* hmac, int type, const byte* key,
00639                              word32 length)
00640 {
00641     hmac->macType = (byte)type;
00642     if (type == MD5)
00643         hmac->type = MD5_TYPE;
00644     else if (type == SHA)
00645         hmac->type = SHA1_TYPE;
00646     else if (type == SHA256)
00647         hmac->type = SHA256_TYPE;
00648     else  {
00649         CYASSL_MSG("unsupported cavium hmac type");
00650     }
00651 
00652     hmac->innerHashKeyed = 0;  /* should we key Startup flag */
00653 
00654     hmac->keyLen = (word16)length;
00655     /* store key in ipad */
00656     XMEMCPY(hmac->ipad, key, length);
00657 }
00658 
00659 #endif /* HAVE_CAVIUM */
00660 
00661 int CyaSSL_GetHmacMaxSize(void)
00662 {
00663     return MAX_DIGEST_SIZE;
00664 }
00665 
00666 #ifdef HAVE_HKDF
00667 
00668 #ifndef min
00669 
00670     static INLINE word32 min(word32 a, word32 b)
00671     {
00672         return a > b ? b : a;
00673     }
00674 
00675 #endif /* min */
00676 
00677 
00678 static INLINE int GetHashSizeByType(int type)
00679 {
00680     if (!(type == MD5 || type == SHA    || type == SHA256 || type == SHA384
00681                       || type == SHA512 || type == BLAKE2B_ID))
00682         return BAD_FUNC_ARG;
00683 
00684     switch (type) {
00685         #ifndef NO_MD5
00686         case MD5:
00687             return MD5_DIGEST_SIZE;
00688         break;
00689         #endif
00690 
00691         #ifndef NO_SHA
00692         case SHA:
00693             return SHA_DIGEST_SIZE;
00694         break;
00695         #endif
00696         
00697         #ifndef NO_SHA256
00698         case SHA256:
00699             return SHA256_DIGEST_SIZE;
00700         break;
00701         #endif
00702         
00703         #ifdef CYASSL_SHA384
00704         case SHA384:
00705             return SHA384_DIGEST_SIZE;
00706         break;
00707         #endif
00708         
00709         #ifdef CYASSL_SHA512
00710         case SHA512:
00711             return SHA512_DIGEST_SIZE;
00712         break;
00713         #endif
00714         
00715         #ifdef HAVE_BLAKE2 
00716         case BLAKE2B_ID:
00717             return BLAKE2B_OUTBYTES;
00718         break;
00719         #endif
00720         
00721         default:
00722             return BAD_FUNC_ARG;
00723         break;
00724     }
00725 }
00726 
00727 
00728 /* HMAC-KDF with hash type, optional salt and info, return 0 on success */
00729 int HKDF(int type, const byte* inKey, word32 inKeySz,
00730                    const byte* salt,  word32 saltSz,
00731                    const byte* info,  word32 infoSz,
00732                    byte* out,         word32 outSz)
00733 {
00734     Hmac   myHmac;
00735 #ifdef CYASSL_SMALL_STACK
00736     byte* tmp;
00737     byte* prk;
00738 #else
00739     byte   tmp[MAX_DIGEST_SIZE]; /* localSalt helper and T */
00740     byte   prk[MAX_DIGEST_SIZE];
00741 #endif
00742     const  byte* localSalt;  /* either points to user input or tmp */
00743     int    hashSz = GetHashSizeByType(type);
00744     word32 outIdx = 0;
00745     byte   n = 0x1;
00746     int    ret;
00747 
00748     if (hashSz < 0)
00749         return BAD_FUNC_ARG;
00750 
00751 #ifdef CYASSL_SMALL_STACK
00752     tmp = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00753     if (tmp == NULL)
00754         return MEMORY_E;
00755 
00756     prk = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00757     if (prk == NULL) {
00758         XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00759         return MEMORY_E;
00760     }
00761 #endif
00762 
00763     localSalt = salt;
00764     if (localSalt == NULL) {
00765         XMEMSET(tmp, 0, hashSz);
00766         localSalt = tmp;
00767         saltSz    = hashSz;
00768     }
00769     
00770     do {
00771     ret = HmacSetKey(&myHmac, type, localSalt, saltSz);
00772     if (ret != 0)
00773         break;
00774     ret = HmacUpdate(&myHmac, inKey, inKeySz);
00775     if (ret != 0)
00776         break;
00777     ret = HmacFinal(&myHmac,  prk);
00778     } while (0);
00779 
00780     if (ret == 0) {
00781         while (outIdx < outSz) {
00782             int    tmpSz = (n == 1) ? 0 : hashSz;
00783             word32 left = outSz - outIdx;
00784 
00785             ret = HmacSetKey(&myHmac, type, prk, hashSz);
00786             if (ret != 0)
00787                 break;
00788             ret = HmacUpdate(&myHmac, tmp, tmpSz);
00789             if (ret != 0)
00790                 break;
00791             ret = HmacUpdate(&myHmac, info, infoSz);
00792             if (ret != 0)
00793                 break;
00794             ret = HmacUpdate(&myHmac, &n, 1);
00795             if (ret != 0)
00796                 break;
00797             ret = HmacFinal(&myHmac, tmp);
00798             if (ret != 0)
00799                 break;
00800 
00801             left = min(left, (word32)hashSz);
00802             XMEMCPY(out+outIdx, tmp, left);
00803 
00804             outIdx += hashSz;
00805             n++;
00806         }
00807     }
00808 
00809 #ifdef CYASSL_SMALL_STACK
00810     XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00811     XFREE(prk, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00812 #endif
00813 
00814     return ret;
00815 }
00816 
00817 #endif /* HAVE_HKDF */
00818 
00819 #endif /* NO_HMAC */
00820 
00821