2016-12-29 5 views
0

winapi暗号化APIを使用してbase64でエンコードされたハッシュを取得しようとしています。私は以下の機能を得るためにコピーして修正しました。私はここからほとんどそれを得た - https://msdn.microsoft.com/en-us/library/windows/desktop/aa382379(v=vs.85).aspxCrypto *** APIを使用したHMAC_SHA1のbase64文字列の結果が不正です

calcHmacSha1("message", "key")とそれを実行するとIIjfdNXyFGtIFGyvSWU3fp0L46Q=を与える必要があります。しかしそれは私にSlLDwKvAoGBJ0atki7QFfj/181k=を与え、それが与えるnonbase64バージョンは4a 52 c3 c0 ab c0 a0 60 49 d1 ab 64 8b b4 05 7e 3f f5 f3 59です。これはここで遭遇したのと同じ状況です - CryptoAPI returns incorrect result for HMAC_SHA1 - しかし、彼のソリューションは16文字以上の鍵では機能しません。それが私の必要です。

#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; 
} 

答えて

2

機能の修正、修正不要です。 HMACに使用されているキーが何であるかを考慮しないでください。文字列キーを直接指定するのではなく、まずRC4キーが作成され、このバイナリに対してHMACが計算されます。RC4キーです。

異なるキー - >別のハッシュ

Windowsでは、文字列キーを直接使用できません。それはアルゴリズムが良いです - 最初に弱い文字列のキーをより強力なバイナリキーに変換します。しかし、あなたは、キーの文字列を使用して、それのためになりましたしたい場合は - このようなコードを使用することができます:

#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

'CryptoDeriveKey'が、' CALG_NO_SIGN'を使用することはできませんでは?私はそれを試みたが、それは私にエラーを与えた。 – Noitidart

+1

@Noitidart - no。 'CALG_NO_SIGN'を試してみたら、'無効なアルゴリズムが指定されました。 ' – RbMm

関連する問題