Шифрование 3DES / DES с использованием JCE - генерация приемлемого ключа - PullRequest
3 голосов
/ 14 декабря 2010

Я работаю над проектом, для которого требуется 3DES-шифрование в Java.Проблема заключается в том, что мне предоставили (и будут предоставлять) 128-битный шестнадцатеричный ключ, например "0123456789ABCDEF0123456789ABCDEF".Преобразование в байты не проблема.Однако проблема заключается в том, что API-интерфейс Java Cryptographic Extensions захлебнется этим ключом, заявив, что он недействителен.Я понимаю, что MSB каждого байта является просто битом четности, поэтому JCE ожидает, что я удалю их (или я так думаю).В .NET, однако, я могу указать ключ в том виде, в котором он поставляется, и он спокойно обрабатывает шифрование / дешифрование без нареканий.

Можно ли каким-либо образом сгенерировать тот тип ключа, который JCE ожидает от видаКлюч, который мне предоставляется?

Я обнаружил, что JCE позволяет вам указать 8-байтовый ключ для шифрования DES, поэтому я попытался реализовать 3DES в качестве DES EDE, используя половину предоставленного ключа.Тем не менее, я все еще получаю противоречивые результаты с .NET.

Вот код Java:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;

public class Main{
    public static void main(String[] args) throws Exception {
        byte [] plain = "I eat fish every day".getBytes("utf-8");

        byte [] keyBytes = new byte [] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
            };

        byte [] key2Bytes = new byte [] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0  }; // actual keys replaced with dummies.

        SecretKey keySpec = new SecretKeySpec(keyBytes, "DES");
        SecretKey keySpec2 = new SecretKeySpec(key2Bytes, "DES");

        IvParameterSpec iv = new IvParameterSpec(new byte[8]);

        Cipher e_cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");

        e_cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
        cipher.init(Cipher.DECRYPT_MODE, keySpec2, iv);

        byte [] cipherText = e_cipher.doFinal(plain);
        cipherText = cipher.doFinal(cipherText);
        cipherText = e_cipher.doFinal(cipherText);

        System.out.println("Ciphertext: " + new sun.misc.BASE64Encoder().encode(cipherText));
    }
}

и вот код .NET:

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

namespace EncryptionDemo
{
    class Program
    {
    public static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");

        // TODO: Implement Functionality Here
        var plainBytes = Encoding.UTF8.GetBytes("I eat fish every day");
        var keyBytes = new byte [] { 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00,
         0x00,  0x00, 0x00, 0x00  };

        var tripleDES = TripleDESCryptoServiceProvider.Create();
        var transform = tripleDES.CreateEncryptor(keyBytes, new byte [8]);

        var memStream = new MemoryStream();
        var cStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write);

        cStream.Write(plainBytes, 0, plainBytes.Length);
        cStream.FlushFinalBlock();

        //memStream.Position = 0;
        var cipherBytes = memStream.ToArray();

        Console.WriteLine("Ciphertext: " + Convert.ToBase64String(cipherBytes));

        Console.Write("Press any key to continue . . . ");
        Console.ReadKey(true);
    }
}

Обапроизводить разные выходные данные (некоторые символы в строке Base64 одинаковы)

Ответы [ 3 ]

4 голосов
/ 14 декабря 2010

3DES-ключи имеют длину 192 бита.

Как вы создаете экземпляр SecretKey?Какое сообщение об ошибке вы получите?


Код Java в вашем вопросе использует DES, а не "Triple DES".Имя алгоритма должно быть "DESede/CBC/PKCS5Padding".Код в вашем ответе , вероятно, работает, потому что вы правильно поняли алгоритм, а не потому, что вы сменили провайдера.Поставщик SunJCE в Java 6 будет принимать 128-битные ключи (и использовать вариант 2).Я не уверен насчет старых версий.

1 голос
/ 15 марта 2011

В проекте jPOS проблема решается путем всегда использования ключей одинарной длины (8 байтов) или тройной длины (24 байта).Допустим, ваш четкий ключ двойной длины (в байтах) - AAAAAAAA BBBBBBBB.Весь код в проекте jPOS, который я до сих пор видел, который использует JCE, снова добавляет первые 8 байтов к ключу очистки, поэтому он становится ключом тройной длины как таковой: AAAAAAAA BBBBBBBB AAAAAAAA.Похоже, что поставщик Sun принимает этот материал для создания SecreKeySpec, поскольку его длина составляет 192 бита, как упоминал @erickson.

1 голос
/ 14 декабря 2010

поставщик Sun не принимает 16-байтовые ключи 3DES, но поставщик BouncyCastle принимает.Я только что попробовал, и он работает как шарм - он производит тот же вывод, что и код .NET!

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.Security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class Main{
    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        byte [] plain = "I eat fish every day".getBytes("utf-8");

        byte [] keyBytes = new byte [] { (byte) 0xC1, (byte) 0x57, (byte) 0x45, (byte) 0x08,
            (byte) 0x85, (byte) 0x02, (byte) 0xB0, (byte) 0xD3,
            (byte) 0xA2, (byte) 0xEF, (byte) 0x68, (byte) 0x43,
            (byte) 0x5E, (byte) 0xE6, (byte) 0xD0, (byte) 0x75 };


        SecretKey keySpec = new SecretKeySpec(keyBytes, "DESede");

        IvParameterSpec iv = new IvParameterSpec(new byte[8]);

        Cipher e_cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding", "BC");

        e_cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

        byte [] cipherText = e_cipher.doFinal(plain);

        System.out.println("Ciphertext: " + new sun.misc.BASE64Encoder().encode(cipherText));
    }
}
...