2012-06-06 3 views
3

Я пытаюсь зашифровать данные с помощью шифрования DES-EDE3-CBC в Ruby, а затем расшифровать зашифрованные данные на Java.Шифровать «DES-EDE3-CBC» в ruby ​​и расшифровать в Java

Вот код в Ruby, я шифрованной:

require 'digest' 
require 'openssl' 
require 'base64' 

ALG = "DES-EDE3-CBC" 
key = "80f28a1ef4aa9df6ee2ee3210316b98f383eb344" 
cipher = OpenSSL::Cipher::Cipher.new(ALG) 
cipher.pkcs5_keyivgen(key, nil) 
cipher.encrypt 
data = "hello" 
result = cipher.update(data) 
result << cipher.final 
# Write the data to file. 
File.open("enc.txt", "wb"){|f| f.write result} 

Тогда дешифрования в Java:

import java.security.*; 
import java.*; 
import java.io.*; 
import javax.crypto.*; 
import javax.crypto.spec.*; 

public class Test{ 
    public static void main(String[] args) throws Exception { 
    String key = "80f28a1ef4aa9df6ee2ee3210316b98f383eb344"; 

    // Init the key 
    DESKeySpec desKeySpec = new DESKeySpec(key.getBytes()); 
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 
    Key secretKey = keyFactory.generateSecret(desKeySpec); 

    Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, secretKey); 

    byte[] buf = new byte[1024]; 
    InputStream input = new FileInputStream(new File("enc.txt")); 
    FileOutputStream output = new FileOutputStream(new File("dec.txt")); 

    int count = input.read(buf); 

    // Read and decrypt file content 
    while (count >= 0) { 
     output.write(cipher.update(buf, 0, count)); 
     count = input.read(buf);   
    } 
    output.write(cipher.doFinal()); 
    output.flush(); 

    } 
} 

Но я всегда получаю исключение при выполнении кода Java:

Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded 
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811) 
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676) 
    at com.sun.crypto.provider.DESCipher.engineDoFinal(DESCipher.java:314) 
    at javax.crypto.Cipher.doFinal(Cipher.java:1969) 
    at Test.main(Test.java:29) 

Я думаю, что проблема в шифровании «DES-EDE3-CBC» в Ruby несовместима с Java «DES/ECB/PKCS5Padding». Как я могу это сделать?

+2

Одна ошибка, которую вы делаете, заключается в том, что вы используете ECB вместо CBC в java. Кроме того, убедитесь, что ваши данные кратные 8 байтам – user845279

+0

Вы также должны использовать DESede/CBC/PKCS5Padding с ключом DESedeKeySpec. – user845279

+0

Установите Java на No Заполнение и расшифровка. Посмотрите на последний блок и посмотрите, какой тип заполнения Ruby был добавлен. Затем скажите Java, чтобы ожидать этого типа заполнения. – rossum

ответ

6

На стороне Ruby не используйте Cipher#key_ivgen, если это не строгое требование. Он устарел и OpenSSL::PKCS5 следует использовать вместо шифрования на основе пароля. Ваш ключ кажется шестнадцатеричным, 40 символов, что приводит к не более чем 20 байтам энтропии. Любая причина, почему она имеет эту конкретную форму? Тройной ключ DES длиной 24 байта, самый простой способ создать безопасный ключ, чтобы сделать:

cipher = OpenSSL::Cipher.new("DES-EDE3-CBC") 
cipher.encrypt 
key = cipher.random_key 

При этом, вы должны также always generate a random IV перед шифрованием:

iv = cipher.random_iv 

Для того, чтобы коммуницировать ключ и IV на Java, если вы должны требовать шестнадцатеричного представления о них:

hex_key = key.unpack("H*")[0] 

в Java, вы сделали ошибку, чтобы использовать DES вместо DESede, и использовать его в режиме ECB, когда в Рубин, вы использовали CBC. Не используйте ЕЦБ. Вам также придется инициализировать Cipher ключом и IV, которые были использованы в Ruby. Для этого вам понадобится соответствующий hex-декодер/декодер (поиск в Интернете), я взял первый образец кода, который мог найти, но буду предупрежден, что это не самый эффективный способ сделать это, основанный поиск будет намного быстрее. Но нам нужно что-то начать, так вот вот:

public static byte[] hexDecode(String hex) { 
    ByteArrayOutputStream bas = new ByteArrayOutputStream(); 
    for (int i = 0; i < hex.length(); i+=2) { 
     int b = Integer.parseInt(hex.substring(i, i + 2), 16); 
     bas.write(b); 
    } 
    return bas.toByteArray(); 
} 

byte[] key = hexDecode("<hex representation of the Ruby key>"); 
byte[] iv = hexDecode("<hex representation of the Ruby IV>"); 

DESedeKeySpec desKeySpec = new DESedeKeySpec(key); 
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede"); 
Key secretKey = keyFactory.generateSecret(desKeySpec); 
IvParameterSpec ivSpec = new IvParameterSpec(iv); 
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); 
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec); 
... /* do the decryption */ 
+0

Спасибо @emboss, после исправления моей двух ошибок: удалите cipher.pkcs5_keyivgen в коде Ruby и замените неправильный «DES/ECB/PKCS5Padding» на «DESede/CBC/PKCS5Padding» в коде Java, он сработал! –

+0

Добро пожаловать! – emboss

Смежные вопросы