Шифрование JAVA в PHP 7

Я хочу воспроизвести шифрование/дешифрование с JAVA на PHP. Но моя проблема, результат не совпадает. Я понятия не имею о java, поэтому пытаюсь понять каждую строку кода из java и написать на PHP.

ДЖАВА


    secretkey: thisisasecretkey
    import java.security.MessageDigest;
    import java.util.Arrays;
    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;

    import org.apache.commons.codec.binary.Base64;

    public class TDESEncrypter {

    public String _encrypt(String message, String secretKey) throws Exception {
    
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
        byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
            
        SecretKey key = new SecretKeySpec(keyBytes, "DESede");
        Cipher cipher = Cipher.getInstance("DESede");
        cipher.init(Cipher.ENCRYPT_MODE, key);
            
        byte[] plainTextBytes = message.getBytes("utf-8");
        byte[] buf = cipher.doFinal(plainTextBytes);
        byte [] base64Bytes = Base64.encodeBase64(buf);
        String base64EncryptedString = new String(base64Bytes);
            
        return base64EncryptedString;
    }

    public String _decrypt(String encryptedText, String secretKey) throws Exception {
    
        byte[] message = Base64.decodeBase64(encryptedText.getBytes("utf-8"));
            
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] digestOfPassword = md.digest(secretKey.getBytes("utf-8"));
        byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        SecretKey key = new SecretKeySpec(keyBytes, "DESede");
            
        Cipher decipher = Cipher.getInstance("DESede");
        decipher.init(Cipher.DECRYPT_MODE, key);
            
        byte[] plainText = decipher.doFinal(message);
            
        return new String(plainText, "UTF-8");
    }
   
}

Вот шаги с использованием java, которые могут быть полезны для репликации функций в PHP.

  1. создать хэш с помощью sha1
  2. преобразовать секретный ключ (из учетных данных) в массив байтов с кодировкой utf-8
  3. заполните шаг 2 ксерокопиями, усечением или дополнением нулями (при необходимости), чтобы копия имела указанную длину 24
  4. инициализируйте секретный ключ с помощью ключевых байтов из шага 3, используя DESede

  5. создать шифр с экземпляром DESede

  6. инициализировать шифр с режимом шифрования с использованием ключа из шага 4
  7. преобразовать данные (имя пользователя/пароль) для шифрования в массив байтов с кодировкой utf-8
  8. зашифровать шаг 7, используя шифр шага 6
  9. кодировать step8 в формате base 64
  10. преобразовать step9 в строку для окончательного зашифрованного сообщения строки

Что я сделал до сих пор,

function encrypt($data, $secret)  { 



    $key = sha1(utf8_encode($secret), true); <-- Step 1 & 2
    $iv = utf8_encode("jvz8bUAx"); <-- Do I use initialise vector on it?

    $key .= substr($key, 0, 8); 

    $method = 'des-ede3-cbc'; //<-- Is this cypher method correct from the above?


    if (strlen($data) % 8) {
        $data = str_pad($data, strlen($data) + 8 - strlen($data) % 8, "\0");
    }

    $encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); //Force zero padding.

    $encrypted = urlencode(base64_encode($encrypted)); // Added the urlencode.....
    return $encrypted;
} 

Мы мало чем сможем вам помочь, если вы не покажете нам исходный код Java ?

Luke Joshua Park 30.04.2019 10:56

Также было бы полезно, если бы вы предоставили исходные данные и «секрет», который вы использовали для создания образца в JAVA. Но я думаю, мы могли бы создать свой собственный, если бы у нас был код JAVA... но тогда нам пришлось бы запускать JAVA... ай...

KIKO Software 30.04.2019 11:01

А также покажите нам, что вы получили вместо этого в PHP.

RealSkeptic 30.04.2019 11:02

@RealSkeptic Я думаю, что этот код там ... мне кажется, PHP. Или это не то, что вы имеете в виду?

KIKO Software 30.04.2019 11:03

Нет, я имел в виду результат, который дает PHP.

RealSkeptic 30.04.2019 11:03

@RealSkeptic Ах, понял... не такой умный здесь...

KIKO Software 30.04.2019 11:05
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
6
718
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В Java-коде алгоритм шифрования указан как DESede. Это соответствует DESede/ECB/PKCS5Padding, т.е. используется режим ECB и заполнение PKCS5. Это означает для PHP-кода:

  • des-ede3 необходимо применить
  • все части кода, относящиеся к IV, должны быть удалены (поскольку режим ECB не использует IV)
  • пользовательское заполнение (которое ни в коем случае не является PKCS5-заполнение) должно быть удалено (поскольку openssl_encrypt по умолчанию использует заполнение PKCS5)

В Java-коде SHA1-хэш (размером 20 байт) расширяется до 24 байт путем добавления 0-значений. Это расширение также необходимо сделать в PHP-коде.

Возможный PHP-аналог Java _encrypt-метода:

function encrypt($data, $secret)  {
    $key = sha1(mb_convert_encoding($secret, "UTF-8"), true);                   // Create SHA-1 hash (20 byte) 
    $key = str_pad($key, 24, "\0");                                             // Extend to 24 byte by appending 0-values (would also happen automatically on openssl_encrypt-call)
    $encrypted = openssl_encrypt($data, 'DES-EDE3', $key, OPENSSL_RAW_DATA);    // Encryption: DESede (24 byte key), ECB-mode, PKCS5-Padding
    return base64_encode($encrypted);                                           // Base64-encoding
}

Наконец: Java-код имеет ряд недостатков, например.

  • Используется тройной DES. Лучшим выбором будет AES, см., например. здесь
  • используется режим ECB, который сам по себе небезопасен, см., например, здесь. Лучшим выбором будет CBC или GCM (последний в AES).
  • SHA-1 используется как KDF (что дает слишком короткий ключ, 20 байтов вместо фактически необходимых 24 байтов). Лучшим выбором будет ПБКДФ2.

Последнее просто для полноты, так как это, вероятно, устаревший код, который нельзя изменить ни по какой причине.

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