Расшифровка расшифровки Java TripleDES PKCS5Padding на С# - неверные данные/ошибка заполнения

Я пытаюсь написать эквивалент С# для следующего кода Java:

protected static final String DES_ECB_PKCS5PADDING = "DESede/ECB/PKCS5Padding";

 public static String decryptValueDirect(String value, String key)
            throws NoSuchAlgorithmException, NoSuchPaddingException,
            GeneralSecurityException, IllegalBlockSizeException,
            BadPaddingException {
        byte[] bytes = Base64.decodeBase64(value);
        Cipher cipher = Cipher.getInstance(DES_ECB_PKCS5PADDING);
        cipher.init(Cipher.DECRYPT_MODE, convertSecretKey(key.getBytes()));
        byte[] decryptedValue = cipher.doFinal(bytes);

        String nstr =  new String(decryptedValue);
        return nstr;
    }
protected static SecretKey convertSecretKey(byte[] encryptionKey) throws GeneralSecurityException {
        if (encryptionKey == null || encryptionKey.length == 0)
            throw new IllegalArgumentException("Encryption key must be specified");

        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(TRIPLEDES);
        KeySpec keySpec = new DESedeKeySpec(encryptionKey);
        return keyFactory.generateSecret(keySpec);
    }

Исходный текст закодирован в base64, затем зашифрован и затем закодирован в base64 для передачи по очереди кролика. Наш поставщик, занимающийся шифрованием, предоставил вышеуказанное для расшифровки на Java, но понятия не имеет о C#.

Единственный вход на стороне шифрования — это ключ, случайная строка. Мы используем ту же строку для шифрования/дешифрования 012345678901234567890123456789 в нашей среде разработки. Это единственный ввод, без соли, хеширования (что я вижу) или итераций pw. Единственное требование состоит в том, что он должен быть не менее 24 символов.

Мой код C# приведен ниже, а скрипка моей попытки находится здесь.

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class Program
{
    public static void Main()
    {
        //Message Data value
        //We are using encrypted multibyte.     
        string myData = @"ROE8oYeV7B6faUsvfIx0Xe55vSs9IR5DlWGRbSM+lmKmLcaJsA13VudwWlAEYtLUD8+nMXShky0grSxsk0Z9cQe5V45XnAIfUhnyzI9a0jtMFC8XnIZ5dbclPO/V73QnieIZDkbNV5cPo3BM+l79ai96KB/gkF3xuerFPxvWejtPyWbOyO+FfNyFps4gAYDITsYIAEH39VP4eipmQ5zc18BA39lajQ3UaVewSxz7H+x3Ooe2SzJT/TQWRkioJSEFwexqzkHiLOQ0MOCIVD9xTWpLYnsL3LMwyF6H8f0PY4Fc57LVGhvUZ7dsB9NWUAnmG3uqbsonNFVhuXyvJTWNyFOHwFzOMx6XDLJJFHGZhaHg2VrescfnpUtonQY08RgojBngyJNRqK8URAvI3bqKq8Y7F/9HmEtMIIQe6KuuTmU=";
        string myKey = "012345678901234567890123456789";//Development Env Key.
        Console.WriteLine("Decrypt1:");
        string s = Decrypt1(myData, myKey);
        Console.ReadLine();
    }

    public static string Decrypt1(string value, string decryptionKey)
    {
        string decryptString = "";
        TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
        MD5CryptoServiceProvider hashMD5Provider = new MD5CryptoServiceProvider();
        try
        {
            byte[] decodedData = Convert.FromBase64String(value);
            tDESalg.Mode = CipherMode.ECB;
            tDESalg.Padding = PaddingMode.PKCS7;//According to MS, same as PKCS5PADDING

            byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey));
            //byte[] IV = tDESalg.IV;
            byte[] IV = new byte[tDESalg.BlockSize / 8]; //The size of the IV property must be the same as the BlockSize property divided by 8

            var memoryStream = new MemoryStream(decodedData);
            var cryptoStream = new CryptoStream(memoryStream, tDESalg.CreateDecryptor(Key, IV), CryptoStreamMode.Read);
            var reader = new StreamReader(cryptoStream);
            decryptString = reader.ReadToEnd();
            byte[] decryptData = Convert.FromBase64String(decryptString);
        }
        catch (Exception e)
        {
            Console.WriteLine("A Cryptographic error occurred: {0}", e.Message + e.StackTrace);
            return null;
        }

        return decryptString;
    }

}

Поиск, кажется, указывает на один и тот же ответ, ключ, кодировку... все должно быть одинаковым. Я просто не знаю, что это будет эквивалентно предоставленному исходному коду Java. :) Любые предложения будут полезны.


person bruce neiman    schedule 14.08.2017    source источник
comment
Если у вас возникли проблемы с кодом, вы должны предоставить минимальный, полный и проверяемый пример, демонстрирующий вашу проблему. Помогите нам помочь вам, не тратя время на догадки. Также не указывайте ссылку на свой код. Вместо этого отредактируйте свой вопрос, включив в него код. Ссылки все время ломаются, и если это произойдет, этот вопрос потеряет всякую ценность.   -  person Artjom B.    schedule 15.08.2017
comment
Вы, конечно, понимаете, что 3DES и режим ECB — плохой выбор для обеспечения безопасности.   -  person zaph    schedule 15.08.2017
comment
Что ж, ключ декодирован дефектным образом, теряющим половину энтропии. Однако, чтобы получить тот же эффект в C#, просто отбросьте последние 8 символов ключа и декодируйте таким же образом, используя Encoding.UTF8.GetBytes(), а не используя MD5.   -  person President James K. Polk    schedule 15.08.2017
comment
@JamesKPolk Вы, кажется, думаете, что ключ не является шестнадцатеричным представлением. Скорее всего, это шестнадцатеричное представление двухклавишного ключа 3DES, иногда известного как 2TDEA.   -  person zaph    schedule 15.08.2017
comment
Я думаю, что это должно было быть шестнадцатеричное представление, но оно было неправильно декодировано. Если C# должен соответствовать дефектному коду Java, я показываю, как это сделать. Конечно, лучше не делать это неправильно, если это возможно.   -  person President James K. Polk    schedule 15.08.2017
comment
Это утверждение: Единственным входом на стороне шифрования является ключ, случайная строка. Мы используем ту же строку для шифрования/дешифрования 012345678901234567890123456789. Это единственный ввод, без соли, хеширования (что я вижу) или итераций pw. относится к ключу шифрования/дешифрования для шифрования/дешифрования общего содержимого репликатора. Это случайная строка GUID, но может быть любой строкой длиной 24 символа. Надеюсь это поможет.   -  person bruce neiman    schedule 15.08.2017
comment
Ну, я уже дал вам ответ.   -  person President James K. Polk    schedule 15.08.2017
comment
@zaph: я забыл упомянуть, что на самом деле я расшифровал строку, обработав ключ так, как я описал.   -  person President James K. Polk    schedule 15.08.2017


Ответы (1)


MD5 имеет 16-байтовый вывод, для Triple DES (3DES) требуется 24-байтовый ключ. Несоответствие размера ключа.

Производные ключи C# и Java существенно различаются:

C#:
byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey));
возвращает 16 байт.

Java:
SecretKeyFactory.getInstance(TRIPLEDES)
возвращает 24 байта.

Существует опция ключа (2TDEA), в которой используется 16-байтовый ключ, а первые 8 байтов будут продублированы для создания последних 8 байтов. NIST устарел от этой опции.

Некоторые реализации будут принимать 16-байтовый ключ и расширять ключ до 24 байтов, а некоторые — нет. Вы должны предоставить все 24 байта для 3DES, не полагайтесь на реализацию для создания 24-байтового ключа.

Примечание. Вопрос был обновлен, поэтому неясно, получен ли фактический ключ шифрования.

person zaph    schedule 15.08.2017
comment
Вышеизложенное является отличным объяснением комментария Джеймса. Я следовал тому, что написал Джеймс К. Полк выше, и сделал это изменение: Отсюда: byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey)); К этому: byte[] Key = Encoding.UTF8.GetBytes(decryptionKey.Substring(0,24)); Теперь работает без ошибок. Спасибо, Заф и @James K Polk - person bruce neiman; 16.08.2017