如何解密在Delphi中加密的C#中的字符串

时间:2010-05-31 08:15:08

标签: c# delphi encryption

我们有一个用Delphi编写的项目,我们想要转换为C#。问题是我们有一些加密并写入注册表的密码和设置。当我们需要指定的密码时,我们从注册表中获取它并解密它以便我们可以使用它。要转换为C#,我们必须以相同的方式执行此操作,以便具有旧版本并希望升级它的用户也可以使用该应用程序。
以下是我们用于在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.

因此,例如,当我们想要加密字符串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,如建议的那样。

5 个答案:

答案 0 :(得分:1)

我会推荐一种不同的方法。您应该P / Invoke原始代码以首次读取密码,然后使用.net代码重新保存。这样,您可以避免两个平台中不同加密例程的问题。

答案 1 :(得分:1)

你的Delphi和C#实现之间有些不同 - 某处。

我建议您使用两种语言对测试数据进行解密,并在流程的每一步输出您的中间体:查看它们的分歧点。特别是,您需要检查派生的3DES密钥和作为密码输入传递的字节数组。

答案 2 :(得分:0)

查看DCP源代码,看起来InitStr()使用IV = EncryptECB(0000000000000000)或IV = EncryptECB(FFFFFFFFFFFFFFFF)初始化 CBC模式中的3DES密码(取决于IFDEF) )。

然而,使用那些我仍然无法从Delphi代码中重现这些值。

我建议您通过每一侧的代码进行调试,并准确记录字符串如何转换为字节以及代码分配给派生密钥和IV的值。

答案 3 :(得分:0)

DES是一种分组密码。并且填充是执行加密和解密操作所必需的。如果要加密的源数据不是64位长度的倍数,则需要填充以进行加密。如果你不填充数据,你会得到意想不到的结果,这取决于默认的填充方案在哪里。

因此,如果可以,您应该重新加密Delphi中的所有密码,并在加密前填充它们。流行的填充方案是将0x80附加到数据并根据需要追加多达0x00,以使数据大小为8字节的倍数。然后,您将能够在解密后去除填充。

答案 4 :(得分: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