2010-05-31 4 views
2


nous avons un projet écrit en Delphi que nous voulons convertir en C#. Le problème est que nous avons des mots de passe et des paramètres cryptés et écrits dans le registre. Lorsque nous avons besoin d'un mot de passe spécifié, nous l'obtenons du registre et nous le décryptons pour que nous puissions l'utiliser. Pour la conversion en C#, nous devons le faire de la même manière afin que l'application puisse également être utilisée par les utilisateurs qui ont l'ancienne version et qui veulent la mettre à jour.
Voici le code que nous utilisons pour crypter/décrypter les chaînes dans Delphi:Comment décrypter une chaîne en C# qui a été cryptée en Delphi

unit uCrypt; 

interface 

function EncryptString(strPlaintext, strPassword : String) : String; 
function DecryptString(strEncryptedText, strPassword : String) : String; 

implementation 

uses 
    DCPcrypt2, DCPblockciphers, DCPdes, DCPmd5; 
const 
    CRYPT_KEY = '1q2w3e4r5t6z7u8'; 

function EncryptString(strPlaintext) : String; 
var 
    cipher   : TDCP_3des; 
    strEncryptedText : String; 
begin 
    if strPlaintext <> '' then 
    begin 
    try 
     cipher := TDCP_3des.Create(nil); 
     try 
     cipher.InitStr(CRYPT_KEY, TDCP_md5); 
     strEncryptedText := cipher.EncryptString(strPlaintext); 
     finally 
     cipher.Free; 
     end; 
    except 
     strEncryptedText := ''; 
    end; 
    end; 

    Result := strEncryptedText; 
end; 

function DecryptString(strEncryptedText) : String; 
var 
    cipher   : TDCP_3des; 
    strDecryptedText : String; 
begin 
    if strEncryptedText <> '' then 
    begin 
    try 
     cipher := TDCP_3des.Create(nil); 
     try 
     cipher.InitStr(CRYPT_KEY, TDCP_md5); 
     strDecryptedText := cipher.DecryptString(strEncryptedText); 
     finally 
     cipher.Free; 
     end; 
    except 
     strDecryptedText := ''; 
    end; 
    end; 

    Result := strDecryptedText; 
end; 
end. 

Ainsi, par exemple quand on veut chiffrer la chaîne asdf1234 nous obtenons le résultat WcOb/iKo4g8=.
Nous voulons maintenant décrypter cette chaîne en C#. Voici ce que nous avons essayé de faire:

public static void Main(string[] args) 
{ 
    string Encrypted = "WcOb/iKo4g8="; 
    string Password = "1q2w3e4r5t6z7u8"; 
    string DecryptedString = DecryptString(Encrypted, Password); 
} 

public static string DecryptString(string Message, string Passphrase) 
{ 
    byte[] Results; 
    System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding(); 

    // Step 1. We hash the passphrase using MD5 
    // We use the MD5 hash generator as the result is a 128 bit byte array 
    // which is a valid length for the TripleDES encoder we use below 

    MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider(); 
    byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase)); 

    // Step 2. Create a new TripleDESCryptoServiceProvider object 
    TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider(); 

    // Step 3. Setup the decoder 
    TDESAlgorithm.Key = TDESKey; 
    TDESAlgorithm.Mode = CipherMode.ECB; 
    TDESAlgorithm.Padding = PaddingMode.None; 

    // Step 4. Convert the input string to a byte[] 
    byte[] DataToDecrypt = Convert.FromBase64String(Message); 

    // Step 5. Attempt to decrypt the string 
    try 
    { 
     ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor(); 
     Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length); 
    } 
    finally 
    { 
     // Clear the TripleDes and Hashprovider services of any sensitive information 
     TDESAlgorithm.Clear(); 
     HashProvider.Clear(); 
    } 

    // Step 6. Return the decrypted string in UTF8 format 
    return UTF8.GetString(Results); 
} 

Bien le résultat diffère du résultat attendu. Après nous appelons DecryptString() nous nous attendons à obtenir asdf1234 mais nous obtenons autre chose.
Est-ce que quelqu'un a une idée de comment décrypter cela correctement?
Merci à l'avance
Simon

EDIT:
Ok, je vous remercie tous pour vos suggestions. Nous n'avons pas pu trouver comment tout faire en C#, nous avons donc décidé de prendre notre version de repli, en utilisant une DLL Delphi avec P/Invoke, comme cela a été suggéré.

Répondre

1

Je recommanderais une approche différente. Vous devez P/invoquer le code d'origine pour lire les mots de passe de retour la première fois, puis réenregistrer en utilisant le code. De cette façon, vous pouvez éviter les problèmes avec les différentes routines de cryptage dans les deux plates-formes.

+1

Ceci est notre solution de repli. Nous avons déjà une DLL Delphi que nous pouvons P/Invoke. Mais il serait préférable d'avoir tout dans le même code C#. –

+0

N'est-ce pas un problème de migration? Une fois que vous avez migré tous vos clients, la DLL Delphi peut être supprimée. –

+0

Être ne peut pas assurer quand et si tous les clients sont migrés. –

0

En regardant à travers le code source DCP il ressemble à initstr() initialise le chiffrement 3DES en mode CBC soit IV = EncryptECB (0000000000000000) ou IV = EncryptECB (ffffffffffffffff) (selon un IFDEF). En utilisant ceux que je ne peux toujours pas reproduire les valeurs du code Delphi, cependant.

Je vous suggère de déboguer le code de chaque côté et de noter exactement comment les chaînes sont converties en octets et quelle valeur le code attribue à la clé dérivée et l'IV.

+0

Malheureusement, je ne suis pas le développeur Delphi et il n'est pas là aujourd'hui, mais je vais le vérifier demain. –

+0

@Simon: des nouvelles à ce sujet? –

+0

Impossible de trouver quoi que ce soit pendant le débogage, nous avons donc décidé de prendre une DLL Delphi et d'utiliser P/Invoke. –

1

Quelque chose diffère entre vos implémentations Delphi et C# - quelque part.

Je vous suggère d'exécuter le déchiffrement des données de test dans les deux langues et de générer vos intermédiaires à chaque étape du processus: voir où ils divergent. En particulier, vous devez extraire la clé 3DES dérivée et le tableau d'octets transmis en entrée du chiffrement.

+0

Malheureusement, je ne suis pas le développeur Delphi et il n'est pas là aujourd'hui, mais je vais le vérifier demain. –

0

DES est un chiffrement par bloc. Et le remplissage est nécessaire pour effectuer des opérations de chiffrement et de déchiffrement. Si les données source à chiffrer ne sont pas un multiple de 64 bits, le remplissage est requis pour le chiffrement. Si vous ne remplissez pas les données, vous obtiendrez des résultats inattendus selon le mode de remplissage par défaut ici et là. Donc, si vous le pouvez, vous devez rechiffrer tous les mots de passe dans Delphi, les avoir rembourrés avant le cryptage. Le schéma de remplissage populaire consiste à ajouter 0x80 aux données et à ajouter autant de 0x00 que nécessaire pour que la taille des données soit un multiple de 8 octets. Vous serez alors en mesure de dépouiller le rembourrage après le déchiffrement.

+0

Ne peut pas faire. La nouvelle implémentation C# de l'application remplacera l'ancienne implémentation Delphi qui ne peut plus être modifiée. –

+0

Vous avez juste besoin de reencrypter les anciens mots de passe. Et puis remplacez l'implémentation Delphi. Si vous avez des utilisateurs de base, vous pouvez leur demander de changer les mots de passe une fois que vous avez déménagé en C#. Si cela est impossible, essayez de tamponner les données dans .NET avec des zéros à 8 octets avant l'opération decrypt/encrypt. –

0
Imports System.IO 
Imports System.Text 
Imports System.Security.Cryptography 

Public Class Crypto 
    Private Shared DES As New TripleDESCryptoServiceProvider 
    Private Shared MD5 As New MD5CryptoServiceProvider 
    Private Shared Function MD5Hash(ByVal value As String) As Byte() 
     Return MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(value)) 
    End Function 

    Public Shared Function Encrypt(ByVal stringToEncrypt As String, ByVal key As String) As String 
     DES.Key = Crypto.MD5Hash(key) 
     DES.Mode = CipherMode.ECB 
     Dim Buffer As Byte() = ASCIIEncoding.ASCII.GetBytes(stringToEncrypt) 
     Return Convert.ToBase64String(DES.CreateEncryptor().TransformFinalBlock(Buffer, 0, Buffer.Length)) 
    End Function 

    Public Shared Function Decrypt(ByVal encryptedString As String, ByVal key As String) As String 
     Try 
      DES.Key = Crypto.MD5Hash(key) 
      DES.Mode = CipherMode.ECB 
      Dim Buffer As Byte() = Convert.FromBase64String(encryptedString) 
      Return ASCIIEncoding.ASCII.GetString(DES.CreateDecryptor().TransformFinalBlock(Buffer, 0, Buffer.Length)) 
     Catch ex As Exception 
      MessageBox.Show("Invalid Key", "Decryption Failed", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) 

     End Try 
    End Function 
End Class 
Questions connexes