【问题标题】:How to decrypt a string in C# that was encrypted in Delphi如何解密在Delphi中加密的C#中的字符串
【发布时间】:2010-05-31 08:15:08
【问题描述】:


我们有一个用 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,正如建议的那样。

【问题讨论】:

    标签: c# delphi encryption


    【解决方案1】:

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

    【讨论】:

    • 这是我们的后备方案。我们已经有一个可以 P/Invoke 的 Delphi DLL。但最好将它们全部放在同一个 C# 代码中。
    • 这不是迁移问题吗?一旦迁移了所有客户,就可以删除 delphi DLL。
    • 无法保证何时以及是否迁移了所有客户。
    【解决方案2】:

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

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

    【讨论】:

    • 很遗憾我不是Delphi开发人员,他今天不在,但我明天会检查一下。
    【解决方案3】:

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

    但是,使用那些我仍然无法重现 Delphi 代码中的值。

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

    【讨论】:

    • 很遗憾我不是Delphi开发人员,他今天不在,但我明天会检查一下。
    • 调试时找不到任何东西,所以我们决定采用 Delphi DLL 并使用 P/Invoke。
    【解决方案4】:

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

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

    【讨论】:

    • 不能。应用程序的新 C# 实现将替换无法再更改的旧 Delphi 实现。
    • 您只需要重新加密旧密码。然后替换Delphi实现。如果您有一些用户群,您可以在迁移到 C# 后要求他们更改密码。如果这是不可能的,请尝试在解密/加密操作之前将 .NET 中的数据填充 0 到 8 个字节。
    【解决方案5】:
    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
    

    【讨论】:

      猜你喜欢
      • 2018-04-16
      • 1970-01-01
      • 2016-03-19
      • 2018-08-17
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多