2009-10-09 8 views
1

J'essaye de décrypter un morceau d'un fichier avec wincrypt et je ne peux pas sembler rendre cette fonction décryptée correctement. Les octets sont cryptés avec l'implémentation RC2 en C# et je fournis le même mot de passe et IV au processus de cryptage et de décryptage (crypté en C#, décrypté en C++).Wincrypt: Impossible de déchiffrer le fichier crypté en C#. NTE_BAD_DATA at CryptDecrypt

Toutes mes fonctions en cours retournent vrai jusqu'à la fonction finale "CryptDecrypt". Au lieu de me taper plus, voici la fonction:

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; 
} 
entrée

est les données transmises à la fonction cryptée. mot de passe est le même mot de passe utilisé pour crypter les données en C#. taille est la taille des données tout crypté.
Toutes les fonctions ci-dessus retournent vrai jusqu'à CryptDecrypt, dont je n'arrive pas à comprendre pourquoi. En même temps, je ne sais pas comment la fonction CryptDecrypt pourrait éditer ma variable "décryptée", puisque je n'en transmets pas de référence.

Toute aide ou conseil sur pourquoi cela ne fonctionne pas serait grandement apprécié. C'est mon premier effort avec wincrypt et la première fois en utilisant C++ dans les années.

Si elle est de plus d'aide, aussi bien, ceci est mon cryptage (en 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(); 
    } 

Je confirme que ma valeur de hachage en C++ est identique à ma clé en C#, créé par PasswordDeriveBytes.CryptDeriveKey

+0

Vous êtes censé appeler GetLastError() pour obtenir le code d'erreur (NTE_BAD_DATA, NTE_BAD_KEY, NTE_BAD_LEN, etc.) –

+0

Correct. Et j'ai fait et j'ai eu Bad Data comme le mien. – Chris

Répondre

3

Tout d'abord, comme dans mon commentaire, utilisez GetLastError() afin que vous sachiez échoué. Je suppose que vous obtenez NTE_BAD_DATA, toutes les autres erreurs sont beaucoup plus faciles à traiter car elles signifient fondamentalement que vous avez manqué une étape dans la séquence d'appel de l'API. La raison typique pour laquelle CryptDecrypt échouerait avec NTE_BAD_DATA serait que vous décryptiez le dernier bloc d'un chiffrement de bloc (comme vous êtes) et que les octets de remplissage décryptés sont incorrects. Cela peut se produire si l'entrée est tronquée (tous les octets cryptés n'ont pas été enregistrés dans le fichier) ou si la clé est incorrecte.

Je vous conseille de prendre cette méthode car il y a tellement d'endroits où cela peut échouer qui sera tout manifeste seulement au moment CryptDecrypt:

  1. Assurez-vous que le fichier que vous chiffrez en C# peut être déchiffré en C#. Cela éliminerait tous les problèmes de troncature d'enregistrement de fichier. Essayez de crypter et décrypter avec une clé codée fixe fixe en premier (pas de mot de passe dérivé), cela garantira que l'initialisation de votre code IV est correcte (ainsi que le mode de remplissage et le mode de chaînage de chiffrement).
  2. Assurez-vous que le processus de dérivation de mot de passe fonctionne sur le même hachage. Des choses comme ANSI ou Unicode ou le terminal 0 peuvent provoquer des havoks sur le hachage MD5 et entraîner des clés très différentes du hachage du mot de passe.
+0

Cela ressemble à un bon plan de bataille, merci. Comment codifiez-vous la clé pour cela? Mes excuses pour mon ignorance. Je n'ai pas vu d'exemples le faire et c'est la première fois que je fais ce genre de chose. – Chris

+0

Cela fait un moment ... Si je me souviens bien, vous utilisez CryptImportKey pour créer un handle de clé à partir d'une clé de session connue. Je ne sais pas comment cela fonctionne avec RC2, jamais utilisé moi-même. –

+0

Si cela ne fonctionne pas, vérifiez au moins que la phrase de passe correspond avant de dériver la clé (dupliquez le handle md5 avec CryptDuplicateHash, puis extrayez la valeur hachée). Voir aussi si mathc la clé générée, utilisez CryptExportKey (... PLAINTEXTKEYBLOB) pour extraire la clé RC2 en C++ –

1

Certaines personnes ont découvert des problèmes lors du passage d'un système d'exploitation à l'autre. L'appel CryptDeriveKey utilise une "longueur de clé par défaut" basée sur le système d'exploitation et l'algorithme choisi. Pour RC2, la longueur de clé générée par défaut est 40 bits sur Windows 2000 et 128 bits sur Windows 2003. Il en résulte un code de retour "BAD DATA" lorsque la clé générée est utilisée dans un appel CryptDecrypt.On peut supposer que ceci est lié au fait que "garbage" apparaît à la fin du tampon final après avoir essayé d'appliquer une clé de 128 bits pour déchiffrer un flux chiffré de 40 bits. Le code d'erreur indique généralement des octets de remplissage incorrects, mais la cause principale peut être un problème de génération de clé.

Pour générer une clé de chiffrement de 40 bits, utilisez ((40 < < 16)) dans le champ flags de l'appel CryptDeriveKey.

Questions connexes