Шифрование TripleDES работает нормально в Java, но не в C # - PullRequest
0 голосов
/ 31 января 2019

Я сталкиваюсь с ошибкой слабого ключа при выполнении шифрования tripleDES. Код работает нормально в Java, но выдает ошибку в C # .net.

У меня есть Java-код, в котором работает TripleDES-шифрование, мне нужно конвертировать мой Javaкод в c #. я сталкиваюсь со слабой ошибкой ключа во время преобразования. Ниже приведены оба кода: java и c #.

1) код Java

public class TripleDES {
    private DESedeKeySpec desKeySpec;

    public TripleDES(String key) {
        try {
            byte[] keyBytes = { (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
                    (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
                    (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
                    (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
                    (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02,
                    (byte) 0x02, (byte) 0x02, (byte) 0x02, (byte) 0x02};



            this.desKeySpec = new DESedeKeySpec(keyBytes);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public byte[] encrypt(byte[] origData) {
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
            SecretKey key = factory.generateSecret(this.desKeySpec);
            Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return cipher.doFinal(origData);
        }  catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public byte[] decrypt(byte[] crypted) {
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
            SecretKey key = factory.generateSecret(this.desKeySpec);
            Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");  //DESede/CBC/PKCS5Padding
            cipher.init(Cipher.DECRYPT_MODE, key);
            return cipher.doFinal(crypted);
        }  catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void main(String[] args) throws Exception {
        TripleDES des = new TripleDES("");

      byte[] data = { (byte)0x04, (byte)0x12, (byte)0x05, (byte)0xFF, (byte)0xFB, (byte)0xA6, (byte)0x66, (byte)0xCF};
      //byte[] data = { (byte)0x04, (byte)0x12, (byte)0x15, (byte)0xAF, (byte)0xFD, (byte)0xD8, (byte)0x88, (byte)0xBB};  


//-----------------Edited-----------------
String text = new BigInteger(1, data).toString(16);
System.out.println("Before encryption = " +text);             
    byte[] crypted = des.encrypt(data);
String text1 = new BigInteger(1, crypted).toString(16);
    System.out.println("Encrypted = " +text1);
byte[] decrypted = des.decrypt(crypted);
String text2 = new BigInteger(1, decrypted).toString(16);
    System.out.println("Decrypted = " +text2);
    }

}

2) код C #

    static void Main(string[] args)
    {
        String Data = EncryptDES("041205FFFBA666CF");
    }

    public static string EncryptDES(string InputText)
    {
        byte[] key = new byte[] { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 };
        byte[] clearData = System.Text.Encoding.UTF8.GetBytes(InputText);
        MemoryStream ms = new MemoryStream();
        TripleDES alg = TripleDES.Create();
        alg.Key = key;
        alg.Mode = CipherMode.ECB;
        CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
        cs.Write(clearData, 0, clearData.Length);
        cs.FlushFinalBlock();
        byte[] CipherBytes = ms.ToArray();
        ms.Close();
        cs.Close();
        string EncryptedData = Convert.ToBase64String(CipherBytes);
        return EncryptedData;

    }

Ключ: 02020202020202020202020202020202

Данные: 041205FFFBA666CF

Результат: A334C92CEC163D9F

Может кто-нибудь, пожалуйста, написать код на c #, который будет давать такой же результат, как и Java.

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Ключ 3DES - это 24-байтовое значение, которое разбито на два трех 8-байтовых значения: key0, key1, key2.

Поскольку 3DES - это DES_Encrypt (key2, DES_Decrypt (key1, DES_Encrypt (key0, data))) в любое время key1 равно key2 или key0, алгоритм сводится к DES.Это то, о чем вам предупреждает TripleDES .NET.

Надлежащий тест здесь должен учитывать очистку (или установку, или исправление) битов четности в каждом байте, но версия с ручной разметкой:

SymmetricAlgorithm alg;
IEnumerable<byte> key0 = key.Take(8);
IEnumerable<byte> key1 = key.Skip(8).Take(8);
IEnumerable<byte> key2 = key.Skip(16);

if (key0.SequenceEquals(key1))
{
    alg = DES.Create();
    alg.Key = key2.ToArray();
}
else if (key1.SequenceEquals(key2))
{
    alg = DES.Create();
    alg.Key = key0.ToArray();
}
else
{
    alg = TripleDES.Create();
    alg.Key = key;
}

Чтобы заменить ваши два лайнера:

TripleDES alg = TripleDES.Create();
alg.Key = key;
0 голосов
/ 31 января 2019

Прежде чем я начну, я хочу сказать, что я не рекомендую или рекомендую вам следовать этим путем, чтобы заставить TripleDES использовать ключ, который он считает слабым, однако, учитывая, что вы используете его дляТолько расшифровка, вот способ сделать это с помощью Reflection.

Во-первых, вы должны «принудительно» заставить класс TripeDES взять слабый ключ, который вы хотите использовать.Для этого мы используем Reflection, чтобы обойти проверку слабого ключа, которая выполняется при попытке установить ключ (alg.Key = key) и установить переменную-член непосредственно:

//alg.Key = key; - THIS IS REPLACED BY THE BELOW
FieldInfo keyField = alg.GetType().GetField("KeyValue", BindingFlags.NonPublic | BindingFlags.Instance);
keyField.SetValue(alg, key);

Значение ключаTripleDES теперь будет установлен на ваш слабый ключ (alg.Key);

Далее у вас есть небольшая ошибка в том, что вы забыли отключить заполнение:

alg.Mode = CipherMode.ECB;
alg.Padding = PaddingMode.None; // Add this, as the default padding is PKCS7

Наконец, будет дальнейшая проверка слабого ключа при создании Decryptor, поэтому мы должны снова использовать Reflection, чтобы обойти проверку и создать ICryptoTransform:

// Comment out the below line and use the code below
// CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
ICryptoTransform Decryptor;
MethodInfo createMethod = alg.GetType().GetMethod("_NewEncryptor", BindingFlags.NonPublic | BindingFlags.Instance);
Decryptor = createMethod.Invoke(alg, new object[] { alg.Key, alg.Mode, alg.IV, alg.FeedbackSize, 1 }) as ICryptoTransform;
CryptoStream cs = new CryptoStream(ms, Decryptor, CryptoStreamMode.Write);

Теперь код будет работать и принимать слабые ключи,и выполните расшифровку, которую вы ищете.

Тем не менее, мне не кажется, что результат - это то, что вы ожидаете:

?Data
"4aU3DcHkiCTEywpiewWIow=="

По крайней мере, сейчас, хотя вы можете использоватькакой бы ключ вы ни выбрали с TripleDES.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...