Эквивалент PHP для Java Triple DES шифрование / дешифрование

Я пытаюсь расшифровать ключ, зашифрованный функцией Java Triple DES с использованием функции PHP mcrypt, но безуспешно. Найдите ниже код Java

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


public class Encrypt3DES {

     private byte[] key;
     private byte[] initializationVector;

    public Encrypt3DES(){

    }

    public String encryptText(String plainText, String key) throws Exception{

         //----  Use specified 3DES key and IV from other source --------------
        byte[] plaintext = plainText.getBytes();
        byte[] myIV = key.getBytes();
        byte[] tdesKeyData = {(byte)0xA2, (byte)0x15, (byte)0x37, (byte)0x08, (byte)0xCA, (byte)0x62,
        (byte)0xC1, (byte)0xD2, (byte)0xF7, (byte)0xF1, (byte)0x93, (byte)0xDF,
        (byte)0xD2, (byte)0x15, (byte)0x4F, (byte)0x79, (byte)0x06, (byte)0x67,
        (byte)0x7A, (byte)0x82, (byte)0x94, (byte)0x16, (byte)0x32, (byte)0x95};

        Cipher c3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        SecretKeySpec    myKey = new SecretKeySpec(tdesKeyData, "DESede");
        IvParameterSpec ivspec = new IvParameterSpec(myIV);
           c3des.init(Cipher.ENCRYPT_MODE, myKey, ivspec);
        byte[] cipherText = c3des.doFinal(plaintext);
        sun.misc.BASE64Encoder obj64=new sun.misc.BASE64Encoder();
        return obj64.encode(cipherText);

    }

    public String decryptText(String encryptText, String key) throws Exception{


        byte[] initializationVector = key.getBytes();
        byte[] tdesKeyData = {(byte)0xA2, (byte)0x15, (byte)0x37, (byte)0x08, (byte)0xCA, (byte)0x62,
        (byte)0xC1, (byte)0xD2, (byte)0xF7, (byte)0xF1, (byte)0x93, (byte)0xDF,
        (byte)0xD2, (byte)0x15, (byte)0x4F, (byte)0x79, (byte)0x06, (byte)0x67,
        (byte)0x7A, (byte)0x82, (byte)0x94, (byte)0x16, (byte)0x32, (byte)0x95};


          byte[] encData = new sun.misc.BASE64Decoder().decodeBuffer(encryptText);
          Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
          SecretKeySpec myKey = new SecretKeySpec(tdesKeyData, "DESede");
          IvParameterSpec ivspec = new IvParameterSpec(initializationVector);
          decipher.init(Cipher.DECRYPT_MODE, myKey, ivspec);
          byte[] plainText = decipher.doFinal(encData);
          return new String(plainText);

    }
}

Я хочу написать PHP-функцию, эквивалентную Java-функции decryptText выше. Я нахожу трудности в генерации точного значения IV, сгенерированного кодом Java для шифрования, которое требуется для дешифрования.

2 ответа

Решение

Это PHP-эквивалент вашего Java-кода (я скопировал заполнение PKCS#5 из комментария 20-Sep-2006 07:56 из mcrypt ссылка)

function encryptText($plainText, $key) {
    $keyData = "\xA2\x15\x37\x08\xCA\x62\xC1\xD2"
        . "\xF7\xF1\x93\xDF\xD2\x15\x4F\x79\x06"
        . "\x67\x7A\x82\x94\x16\x32\x95";

    $padded = pkcs5_pad($plainText,
        mcrypt_get_block_size("tripledes", "cbc"));

    $encText = mcrypt_encrypt("tripledes", $keyData, $padded, "cbc", $key);

    return base64_encode($encText);
}

function decryptText($encryptText, $key) {
    $keyData = "\xA2\x15\x37\x08\xCA\x62\xC1\xD2"
        . "\xF7\xF1\x93\xDF\xD2\x15\x4F\x79\x06"
        . "\x67\x7A\x82\x94\x16\x32\x95";

    $cipherText = base64_decode($encryptText);

    $res = mcrypt_decrypt("tripledes", $keyData, $cipherText, "cbc", $key);

    $resUnpadded = pkcs5_unpad($res);

    return $resUnpadded;
}


function pkcs5_pad ($text, $blocksize)
{
    $pad = $blocksize - (strlen($text) % $blocksize);
    return $text . str_repeat(chr($pad), $pad);
}

function pkcs5_unpad($text)
{
    $pad = ord($text{strlen($text)-1});
    if ($pad > strlen($text)) return false;
    if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
    return substr($text, 0, -1 * $pad);
}

Но есть некоторые проблемы, о которых вы должны знать:

  • В вашем коде Java вы звоните String.getBytes() без указания кодировки. Это делает ваш код непереносимым, если ваш открытый текст содержит не ASCII-символы, такие как umlauts, потому что Java использует системный набор символов по умолчанию. Если вы можете изменить это, я бы так и сделал. Я рекомендую вам использовать utf-8 с обеих сторон (Java и PHP).
  • Вы жестко закодировали ключ шифрования и используете IV как "ключ". Я ни в коем случае не криптоэксперт, но для меня это просто неправильно и может привести к серьезной утечке безопасности.
  • Создайте случайный IV и просто объедините его в начале или в конце вашего сообщения. Поскольку размер IV равен AFAIK и равен размеру блока вашего шифра, вы просто удаляете столько байтов из начала или конца и легко отделяете IV от сообщения.
  • Что касается ключа, то лучше всего использовать какой-то метод получения ключа для генерации ключа правильного размера из "сгенерированного человеком" пароля.

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

Ответ почти хорош! Просто поменять $keyData а также $key в

$encText = mcrypt_encrypt("tripledes", $keyData, $padded, "cbc", $key);

а также

$res = mcrypt_decrypt("tripledes", $keyData, $cipherText, "cbc", $key);

в противном случае вы всегда будете использовать один и тот же ключ 3DES. И лучше переименовать $keyData в $iv,

В любом случае, большое спасибо за пример Java и перевод Php-Java.

Другие вопросы по тегам