2009-10-09 109 views
1

我想用wincrypt解密一個文件,我似乎無法正確解密這個函數。這些字節是用C#中的RC2實現加密的,我爲加密和解密過程(在C#中加密,在C++中解密)提供了相同的密碼和IV。Wincrypt:無法解密在C#中加密的文件。 NTE_BAD_DATA CryptDecrypt

沿途的所有函數都返回true,直到最終的「CryptDecrypt」函數。而不是我打字出來,這裏是功能:

static char* DecryptMyFile(char *input, char *password, int size) 
{ 
    HCRYPTPROV provider = NULL; 

    if(CryptAcquireContext(&provider, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0)) 
    {printf("Context acquired.");} 
    else 
    { 
     if (GetLastError() == NTE_BAD_KEYSET) 
     { 
     if(CryptAcquireContext(&provider, 0, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) 
      {printf("new key made.");} 
      else 
      { 
       printf("Could not acquire context."); 
      } 
     } 
     else 
     {printf("Could not acquire context.");} 
    } 

    HCRYPTKEY key = NULL; 
    HCRYPTHASH hash = NULL; 

    if(CryptCreateHash(provider, CALG_MD5, 0, 0, &hash)) 
    {printf("empty hash created.");} 
    else 
    {printf("could not create hash.");} 

    if(CryptHashData(hash, (BYTE *)password, strlen(password), 0)) 
    {printf("data buffer is added to hash.");} 
    else 
    {printf("error. could not add data buffer to hash.");} 

    if(CryptDeriveKey(provider, CALG_RC2, hash, 0, &key)) 
    {printf("key derived.");} 
    else 
    {printf("Could not derive key.");} 

    DWORD dwKeyLength = 128; 

if(CryptSetKeyParam(key, KP_EFFECTIVE_KEYLEN, reinterpret_cast<BYTE*>(&dwKeyLength), 0)) 
    {printf("success");} 
    else 
    {printf("failed.");} 

    BYTE IV[8] = {0,0,0,0,0,0,0,0}; 

    if(CryptSetKeyParam(key, KP_IV, IV, 0)) 
    {printf("worked");} 
    else 
    {printf("faileD");} 

    DWORD dwCount = size; 
    BYTE *decrypted = new BYTE[dwCount + 1]; 

    memcpy(decrypted, input, dwCount); 
    decrypted[dwCount] = 0; 


    if(CryptDecrypt(key,0, true, 0, decrypted, &dwCount)) 
    {printf("succeeded");} 
    else 
    {printf("failed");} 

return (char *)decrypted; 
} 

輸入是傳遞給函數,加密的數據。密碼與用於加密C#中的數據的密碼相同。大小是加密時數據的大小。
所有上述函數返回true直到CryptDecrypt,我似乎無法弄清楚爲什麼。同時,我不確定CryptDecrypt函數如何編輯我的「解密」變量,因爲我沒有傳遞它的參考。

任何幫助或建議,爲什麼這是行不通的將不勝感激。這是我第一次使用Wincrypt和第一次使用C++的努力。

如果它是任何更多的幫助,還有,這是我的加密(在C#):

public static byte[] EncryptString(byte[] input, string password) 
    { 
     PasswordDeriveBytes pderiver = new PasswordDeriveBytes(password, null); 
     byte[] ivZeros = new byte[8]; 
     byte[] pbeKey = pderiver.CryptDeriveKey("RC2", "MD5", 128, ivZeros); 

     RC2CryptoServiceProvider RC2 = new RC2CryptoServiceProvider(); 

     //using an empty initialization vector for convenience. 
     byte[] IV = new byte[8]; 
     ICryptoTransform encryptor = RC2.CreateEncryptor(pbeKey, IV); 

     MemoryStream msEncrypt = new MemoryStream(); 
     CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write); 
     csEncrypt.Write(input, 0, input.Length); 
     csEncrypt.FlushFinalBlock(); 

     return msEncrypt.ToArray(); 
    } 

我已經證實,在C++中我的哈希值是相同的我在C#中的關鍵,通過創建PasswordDeriveBytes.CryptDeriveKey

+0

你應該調用GetLastError()來獲取錯誤代碼(NTE_BAD_DATA,NTE_BAD_KEY,NTE_BAD_LEN等) – 2009-10-09 23:10:01

+0

正確。我做了並得到了壞數據。 – Chris 2009-10-09 23:14:07

回答

3

首先,如我的評論,使用GetLastError(),所以你知道什麼它失敗。我假設你得到NTE_BAD_DATA,所有其他的錯誤更容易處理,因爲他們基本上意味着你錯過了API調用順序的一些步驟。

CryptDecrypt會因爲NTE_BAD_DATA而失敗的典型原因是,您正在解密塊密碼的最後一個塊(按照原樣)並且解密的填充字節不正確。如果輸入被截斷(並非所有加密的字節都保存到文件中)或密鑰不正確,則可能發生這種情況。

我建議,因爲有這麼多的地方你把這個有條不紊哪裏,這隻能在CryptDecrypt時失敗,這些都有助於清單:

  1. 確保在C#中,你加密的文件可以在C#中被解密。這將消除任何文件保存截斷問題。
  2. 嘗試使用固定硬編碼密鑰(無密碼派生)進行加密和解密,這將確保您的密鑰集編碼IV初始化是正確的(以及填充模式和密碼鏈模式)。
  3. 確保密碼派生過程在相同的哈希上得到。諸如ANSI與Uni​​code或終端0之類的東西可能會對MD5哈希產生havok,並導致明顯相同密碼哈希的非常不同的密鑰。
+0

這聽起來像是一個很好的戰鬥計劃,謝謝。你如何硬編碼這些關鍵?我對我的無知表示歉意。我沒有看到這樣做的例子,這是我第一次做這種事情。 – Chris 2009-10-10 00:01:47

+0

已經有一段時間了...如果我沒有記錯的話,您可以使用CryptImportKey從已知會話密鑰創建密鑰句柄。不知道如何與RC2一起工作,從來沒有使用過它。 – 2009-10-10 00:07:04

+0

如果這樣做不起作用,至少要在派生密鑰之前確保密碼短語匹配(使用CryptDuplicateHash複製md5句柄,然後提取散列值)。另請參閱生成的密鑰的數學運算符,使用CryptExportKey(... PLAINTEXTKEYBLOB)提取C++中的RC2密鑰 – 2009-10-10 00:11:45

1

有些人在操作系統間移動時發現問題。 CryptDeriveKey調用根據所選的操作系統和算法使用「默認密鑰長度」。對於RC2,默認生成的密鑰長度在Windows 2000上是40位,在Windows 2003上是128位。當生成的密鑰用於CryptDecrypt調用時,會導致「BAD DATA」返回碼。

大概這與嘗試應用128位密鑰解密40位加密流後出現在最終緩衝區末尾的「垃圾」有關。錯誤代碼通常表示錯誤的填充字節 - 但根本原因可能是密鑰生成問題。

要生成40位加密密鑰,請在CryptDeriveKey調用的標誌字段中使用(((40 < < 16))。