Как расшифровать строку в C #, которая была зашифрована в Delphi

2


у нас есть проект, написанный в Delphi, который мы хотим преобразовать в С#. Проблема в том, что у нас есть пароли и настройки, которые зашифрованы и записаны в реестр. Когда нам нужен указанный пароль, мы получаем его из реестра и расшифровываем его, чтобы мы могли его использовать. Для преобразования в С# мы должны сделать это таким же образом, чтобы приложение также могло использоваться пользователями, имеющими старую версию, и их необходимо обновить.
Вот код, который мы используем для шифрования/дешифрования строк в 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=.
Теперь мы хотим расшифровать эту строку в С#. Вот что мы пытались сделать:

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, но получим что-то еще.
Кто-нибудь имеет представление о том, как правильно его расшифровать?
Спасибо заранее
Simon

EDIT: Хорошо, спасибо всем вам за ваши предложения. Мы не смогли узнать, как сделать все это на С#, поэтому мы решили взять нашу версию обратно, используя DLL Delphi с P/Invoke, как было предложено.

Теги:
encryption

5 ответов

1
Лучший ответ

Я бы порекомендовал другой подход. Вы должны P/вызывать исходный код, чтобы прочитать пароли назад в первый раз, а затем повторно сохранить с помощью .net-кода. Таким образом, вы можете избежать проблем с различными процедурами шифрования на двух платформах.

  • 1
    Это наш запасной вариант. У нас уже есть Delphi DLL, которую мы можем P / Invoke. Но было бы лучше, чтобы все это было в одном коде C #.
  • 0
    Разве это не проблема миграции? После того как вы перенесли всех своих клиентов, DLL-библиотека delphi может быть удалена.
Показать ещё 1 комментарий
1

Что-то отличается от ваших реализаций Delphi и С# - где-то.

Я предлагаю вам запустить дешифрование с тестовыми данными на обоих языках и вывести свои промежуточные продукты на каждом этапе процесса: см., где они расходятся. В частности, вам нужно проверить полученный ключ 3DES и массив байтов, переданный в качестве ввода в шифр.

  • 0
    К сожалению, я не разработчик Delphi, и его здесь нет сегодня, но я проверю это завтра.
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
0

DES - это блок-шифр. И для выполнения операций шифрования и дешифрования требуется отступы. Если исходные данные для шифрования не кратны 64 битам, для шифрования требуется отступы. Если вы не вставляете данные, вы получите неожиданные результаты в зависимости от того, какая схема заполнения используется по умолчанию здесь и там.

Итак, если вы можете, вы должны повторно зашифровать все пароли в Delphi, если они будут дополнены до шифрования. Популярной схемой заполнения является добавление 0x80 к данным и добавление как можно большего количества 0x00, чтобы размер данных был кратным 8 байтам. После дешифрования вы сможете отключить отладку.

  • 0
    Не могу сделать Новая реализация приложения на C # заменит старую реализацию Delphi, которая больше не может быть изменена.
  • 0
    Вам просто нужно перешифровать старые пароли. А затем замените реализацию Delphi. Если у вас есть база пользователей, вы можете попросить их сменить пароли после перехода на C #. Если это невозможно, попробуйте добавить данные в .NET с нуля до 8 байт перед операцией дешифрования / шифрования.
0

Просматривая исходный код DCP, похоже, что InitStr() инициализирует шифр 3DES в режиме CBC с помощью IV = EncryptECB (0000000000000000) или IV = EncryptECB (FFFFFFFFFFFFFFFF) (в зависимости от IFDEF).

Используя те, я все еще не могу воспроизвести значения из Delphi-кода.

Я предлагаю вам отлаживать код с каждой стороны и точно знать, как строки преобразуются в байты и какие значения присваивает код производному ключу и IV.

  • 0
    К сожалению, я не разработчик Delphi, и его здесь нет сегодня, но я проверю это завтра.
  • 0
    @Simon: есть новости по этому поводу?
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню