代码之家  ›  专栏  ›  技术社区  ›  Simon Linder

如何解密用Delphi加密的C字符串

  •  2
  • Simon Linder  · 技术社区  · 15 年前


    我们有一个用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 回复  |  直到 9 年前
        1
  •  1
  •   Preet Sangha    15 年前

    我建议采用不同的方法。您应该p/调用原始代码来读取密码。 第一次 ,然后使用.NET代码重新保存。这样可以避免两个平台中不同加密例程的问题。

        2
  •  1
  •   crazyscot    15 年前

    Delphi和C实现之间有些不同-在某个地方。

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

        3
  •  0
  •   Rasmus Faber    15 年前

    通过查看DCP源代码,它看起来像initsrc()初始化3des密码 CBC模式 使用iv=encryptecb(0000000000000000)或iv=encryptecb(ffffffffffffffffff)(取决于ifdef)。

    但是,使用这些代码,我仍然无法从Delphi代码中复制值。

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

        4
  •  0
  •   Vladislav Rastrusny    15 年前

    DES是分组密码。需要填充来执行加密和解密操作。如果要加密的源数据的长度不是64位的倍数,则需要填充以进行加密。如果不填充数据,则根据此处和那里默认的填充方案,将得到意外的结果。

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

        5
  •  0
  •   Alejandro    9 年前
    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