2010-05-31 54 views
2


我們有一個用Delphi編寫的項目,我們希望將其轉換爲C#。問題是我們有一些密碼和設置被加密並寫入註冊表。當我們需要一個指定的密碼時,我們從註冊表中獲取並解密,以便我們可以使用它。爲了轉換到C#,我們必須以同樣的方式進行,以便具有舊版本並想升級它的用戶也可以使用該應用程序。
這是我們使用加密代碼/解密在Delphi中的字符串:如何解密在Delphi中加密的C#中的字符串

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. 

因此,例如,當我們想要的字符串asdf1234我們得到的結果WcOb/iKo4g8=加密。
我們現在想要在C#中解密該字符串。以下是我們試圖做的:

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

那麼結果與預期結果不同。在我們撥打DecryptString()後,我們預計會得到asdf1234,但我們還有其他的東西。
有沒有人有如何正確解密的想法?
在此先感謝
西蒙

編輯:
好的,謝謝大家的建議。我們無法找到如何在C#中完成所有工作,因此我們決定採用我們的回退版本,使用帶有P/Invoke的Delphi DLL,正如它的建議。

回答

1

我會推薦一種不同的方法。您應該P/Invoke原始代碼回讀密碼,然後使用.net代碼重新保存。這樣可以避免兩個平臺中不同加密例程的問題。

+1

這是我們的後備。我們已經有一個Delphi DLL,我們可以P/Invoke。但最好是將它全部放在相同的C#代碼中。 – 2010-05-31 08:27:15

+0

這不是遷移問題嗎?一旦你遷移了所有的客戶,那麼delphi DLL就可以被刪除。 – 2010-05-31 08:35:46

+0

無法確保何時以及是否所有客戶都被遷移。 – 2010-05-31 08:43:58

0

通過DCP的源代碼,它看起來像InitStr(尋找)在初始化CBC 模式的3DES密碼與任一IV = EncryptECB(0000000000000000)或IV = EncryptECB(FFFFFFFFFFFFFFFF)(取決於一個IFDEF)。

但是,使用那些我仍然不能從Delphi代碼重現值。

我建議你通過代碼在每邊進行調試,並確切地注意字符串如何轉換爲字節以及代碼分配給派生鍵和IV的值。

+0

不幸的是,我不是德爾福的開發者,他今天不在這裏,但我明天會檢查它。 – 2010-05-31 11:03:29

+0

@Simon:有關這方面的消息嗎? – 2010-06-03 16:49:49

+0

調試時找不到任何東西,所以我們決定採用Delphi DLL並使用P/Invoke。 – 2010-06-21 06:22:25

1

你的Delphi和C#實現之間有什麼不同 - 某處。

我建議你在兩種語言中對測試數據運行解密,並在流程的每個步驟輸出中間體:查看它們在哪裏分歧。特別是,您需要檢查派生的3DES密鑰和作爲密碼輸入傳遞的字節數組。

+0

不幸的是,我不是德爾福開發人員,他今天不在這裏,但我明天會檢查它。 – 2010-05-31 11:04:15

0

DES是分組密碼。填充需要執行加密和解密操作。如果要加密的源數據的長度不是64位的倍數,則需要使用填充進行加密。如果你沒有填充數據,你會得到意想不到的結果,這取決於在這裏和那裏默認的填充方案。

所以,如果可以的話,你應該重新加密Delphi中的所有密碼,並在加密前填充它們。流行的填充方案是將0x80附加到數據,並根據需要添加儘可能多的0x00,以使數據大小爲8字節的倍數。您將可以在解密後剝離填充。

+0

不能做。該應用程序的新C#實現將取代不能再改變的舊Delphi實現。 – 2010-05-31 09:37:27

+0

你只需要重新加密舊的密碼。然後替換Delphi實現。如果你有一些用戶基礎,你可以讓他們在你轉移到C#後更改密碼。如果這是不可能的,那麼在解密/加密操作之前,嘗試在.NET中使用零填充到8字節的數據。 – 2010-05-31 11:00:34

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 
相關問題