2016-12-29 4 views
0

J'essaye d'utiliser le winapi crypto api pour obtenir un hachage encodé en base64. J'ai copié et modifié pour obtenir la fonction ci-dessous. Je l'ai obtenu à partir d'ici la plupart - https://msdn.microsoft.com/en-us/library/windows/desktop/aa382379(v=vs.85).aspxMauvais résultat pour la chaîne base64 de HMAC_SHA1 en utilisant Crypto *** API

En cours d'exécution avec calcHmacSha1("message", "key") devrait donner IIjfdNXyFGtIFGyvSWU3fp0L46Q=. Cependant, il me donne SlLDwKvAoGBJ0atki7QFfj/181k=, la version non base64 qu'il donne est 4a 52 c3 c0 ab c0 a0 60 49 d1 ab 64 8b b4 05 7e 3f f5 f3 59. C'est la même situation rencontrée ici - CryptoAPI returns incorrect result for HMAC_SHA1 - cependant sa solution ne fonctionne pas pour les plus de 16 caractères de la clé, et c'est mon besoin.

#pragma comment (lib, "Crypt32.lib") 
#include <wincrypt.h> 

std::string calcHmacSha1(std::string msg, std::string key) { 
    std::string hash; 

    std::vector<BYTE> msgbytebuffer(msg.begin(), msg.end()); 
    std::vector<BYTE> keybytebuffer(key.begin(), key.end()); 

    // http://msdn.microsoft.com/en-us/library/Aa379863 

    HCRYPTPROV hProv  = NULL; 
    HCRYPTHASH hHash  = NULL; 
    HCRYPTKEY hKey  = NULL; 
    HCRYPTHASH hHmacHash = NULL; 
    PBYTE  pbHash  = NULL; 
    DWORD  dwDataLen = 0; 
    BYTE*  Data1  = &keybytebuffer[0]; // {0x6b,0x65,0x79}; 
    BYTE*  Data2  = &msgbytebuffer[0]; // {0x6D,0x65,0x73,0x73,0x61,0x67,0x65}; 
    HMAC_INFO HmacInfo; 

    //-------------------------------------------------------------------- 
    // Zero the HMAC_INFO structure and use the SHA1 algorithm for 
    // hashing. 

    debug_log("sizeof(Data2)", sizeof(Data2)); 
    debug_log("sizeof(BYTE)", sizeof(BYTE)); 

    ZeroMemory(&HmacInfo, sizeof(HmacInfo)); 
    HmacInfo.HashAlgid = CALG_SHA1; 

    //-------------------------------------------------------------------- 
    // Acquire a handle to the default RSA cryptographic service provider. 

    if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { 
     debug_log(" Error in AcquireContext 0x%08x", GetLastError()); 
     goto ErrorExit; 
    } 

    //-------------------------------------------------------------------- 
    // Derive a symmetric key from a hash object by performing the 
    // following steps: 
    // 1. Call CryptCreateHash to retrieve a handle to a hash object. 
    // 2. Call CryptHashData to add a text string (password) to the 
    //  hash object. 
    // 3. Call CryptDeriveKey to create the symmetric key from the 
    //  hashed password derived in step 2. 
    // You will use the key later to create an HMAC hash object. 

    if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)) { 
     debug_log("Error in CryptCreateHash 0x%08x \n", GetLastError()); 
     goto ErrorExit; 
    } 

    if (!CryptHashData(hHash, Data1, key.length() * sizeof(BYTE), 0)) { 
     debug_log("Error in CryptHashData 1 0x%08x", GetLastError()); 
     goto ErrorExit; 
    } 

    if (!CryptDeriveKey(hProv, CALG_RC4, hHash, 0, &hKey)) { 
     debug_log("Error in CryptDeriveKey 0x%08x", GetLastError()); 
     goto ErrorExit; 
    } 

    //-------------------------------------------------------------------- 
    // Create an HMAC by performing the following steps: 
    // 1. Call CryptCreateHash to create a hash object and retrieve 
    //  a handle to it. 
    // 2. Call CryptSetHashParam to set the instance of the HMAC_INFO 
    //  structure into the hash object. 
    // 3. Call CryptHashData to compute a hash of the message. 
    // 4. Call CryptGetHashParam to retrieve the size, in bytes, of 
    //  the hash. 
    // 5. Call malloc to allocate memory for the hash. 
    // 6. Call CryptGetHashParam again to retrieve the HMAC hash. 

    if (!CryptCreateHash(hProv, CALG_HMAC, hKey, 0, &hHmacHash)) { 
     debug_log("Error in CryptCreateHash key 0x%08x", GetLastError()); 
     goto ErrorExit; 
    } 

    if (!CryptSetHashParam(hHmacHash, HP_HMAC_INFO, (BYTE*)&HmacInfo, 0)) { 
     debug_log("Error in CryptSetHashParam 0x%08x", GetLastError()); 
     goto ErrorExit; 
    } 

    if (!CryptHashData(hHmacHash, Data2, msg.length() * sizeof(BYTE), 0)) { 
     debug_log("Error in CryptHashData 2 0x%08x", GetLastError()); 
     goto ErrorExit; 
    } 

    //-------------------------------------------------------------------- 
    // Call CryptGetHashParam twice. Call it the first time to retrieve 
    // the size, in bytes, of the hash. Allocate memory. Then call 
    // CryptGetHashParam again to retrieve the hash value. 

    if (!CryptGetHashParam(hHmacHash, HP_HASHVAL, NULL, &dwDataLen, 0)) { 
     debug_log("Error in CryptGetHashParam 0x%08x", GetLastError()); 
     goto ErrorExit; 
    } 

    pbHash = (BYTE*)malloc(dwDataLen); 
    if(NULL == pbHash) { 
     debug_log("unable to allocate memory\n"); 
     goto ErrorExit; 
    } 

    if (!CryptGetHashParam(hHmacHash, HP_HASHVAL, pbHash, &dwDataLen, 0)) { 
     debug_log("Error in CryptGetHashParam 0x%08x", GetLastError()); 
     goto ErrorExit; 
    } 

    DWORD base64Size = 0; 
    if (!CryptBinaryToString(pbHash, dwDataLen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &base64Size)) { 
     debug_log("Error in CryptBinaryToString 1 0x%08x", GetLastError()); 
     goto ErrorExit; 
    }; 

    WCHAR* base64 = new WCHAR[ base64Size + 1 ]; 
    if (!CryptBinaryToString(pbHash, dwDataLen, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, base64, &base64Size)) { 
     debug_log("Error in CryptBinaryToString 2 0x%08x", GetLastError()); 
     goto ErrorExit; 
    }; 
    hash = string_cast<std::string>(base64); 
    delete[] base64; 
    debug_log("hash:", hash); 

    // printf("The hash is: "); 
    // char chash[512]; 
    // for(DWORD i = 0 ; i < dwDataLen ; i++) { 
    // printf("%.2x ",pbHash[i]); 
    // } 
    MessageBox(NULL, L"hi", L"cap", 0); 

    // Free resources. 
    ErrorExit: 
     if(hHmacHash) CryptDestroyHash(hHmacHash); 
     if(hKey) CryptDestroyKey(hKey); 
     if(hHash) CryptDestroyHash(hHash); 
     if(hProv) CryptReleaseContext(hProv, 0); 
     if(pbHash) free(pbHash); 
     return hash; 
} 

Répondre

2

la fonction fonctionne correctement, pas besoin de le réparer. mais vous ne prenez pas en compte ce qui est la clé utilisée ici pour HMAC - ne pas diriger votre clé de chaîne, mais d'abord, en fonction de votre clé de chaîne, RC4 clé créée et HMAC calculé pour cette clé binaire RC4.

différentes clés -> hash différent. Windows n'autorise pas l'utilisation directe des clés de chaîne.

l'algorithme est meilleur - d'abord convertir la clé de chaîne faible en clé binaire plus forte. si vous voulez utiliser la touche de chaîne et avons obtenu résultat pour elle - peut utiliser le code comme ceci:

#define BLOCK_SIZE 64 

BOOL hmac(PCSTR key, PCSTR message, ALG_ID Algid) 
{ 
    UCHAR i_key_pad[BLOCK_SIZE], o_key_pad[BLOCK_SIZE]; 

    HCRYPTPROV hProv; 
    HCRYPTHASH hHash; 
    ULONG len = (ULONG)strlen(key), cb; 
    BOOL f; 

    if (f = CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) 
    { 
     if (len > BLOCK_SIZE) 
     { 
      if (f = CryptCreateHash(hProv, Algid, 0, 0, &hHash)) 
      { 
       f = CryptHashData(hHash, (PBYTE)key, len, 0) && 
        CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&len, &(cb = sizeof(len)), 0) && 
        CryptGetHashParam(hHash, HP_HASHVAL, (BYTE*)(key = (PCSTR)alloca(len)), &len, 0); 

       CryptDestroyHash(hHash); 
      } 
     } 

     if (f) 
     { 
      ULONG i = BLOCK_SIZE; 

      do 
      { 
       UCHAR c = --i < len ? key[i] : 0; 

       i_key_pad[i] = 0x36^c; 
       o_key_pad[i] = 0x5c^c; 

      } while (i); 

      if (f = CryptCreateHash(hProv, Algid, 0, 0, &hHash)) 
      { 
       f = CryptHashData(hHash, i_key_pad, sizeof(i_key_pad), 0) && 
        CryptHashData(hHash, (PBYTE)message, (ULONG)strlen(message), 0) && 
        CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&len, &(cb = sizeof(len)), 0) && 
        CryptGetHashParam(hHash, HP_HASHVAL, (BYTE*)(key = (PCSTR)alloca(len)), &len, 0); 

       CryptDestroyHash(hHash); 

       if (f && (f = CryptCreateHash(hProv, Algid, 0, 0, &hHash))) 
       { 
        f = CryptHashData(hHash, o_key_pad, sizeof(o_key_pad), 0) && 
         CryptHashData(hHash, (PBYTE)key, len, 0) && 
         CryptGetHashParam(hHash, HP_HASHVAL, (BYTE*)key, &len, 0); 

        CryptDestroyHash(hHash); 

        if (f && len) 
        { 
         DbgPrint("\nThe hash is: "); 
         do 
         { 
          DbgPrint("%02x", (UCHAR)*key++); 
         } while (--len); 
         DbgPrint("\n"); 
        } 
       } 
      } 
     } 

     CryptReleaseContext(hProv, 0); 
    } 

    return f; 
} 


//The hash is: 2088df74d5f2146b48146caf4965377e9d0be3a4 
hmac("key","message", CALG_SHA1); 
+0

Dans le 'CryptoDeriveKey' est-il pas possible d'utiliser' CALG_NO_SIGN'? J'ai essayé mais ça m'a donné une erreur. – Noitidart

+1

@Noitidart - no. si vous essayez 'CALG_NO_SIGN' - vous avez une erreur' Algorithme invalide spécifié. ' – RbMm