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

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

0 голосов
/ 30 апреля 2019

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

JAVA


    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. padd шаг 2 с ксерокопиями, усечение или заполнение нулями (при необходимости), чтобы копия имела заданныйдлина 24
  4. инициализация Secretkey с байтами ключа из шага 3 с использованием DESede

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

  6. инициализация шифра с режимомдля шифрования с использованием ключа из шага 4
  7. преобразования данных (имя пользователя / пароль) для шифрования в байтовый массив с кодировкой utf-8
  8. шифрование шага 7 с использованием шифра шага 6 * кодирование 1029 *
  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;
} 

1 Ответ

1 голос
/ 01 мая 2019

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

  • des-ede3 должно быть применено
  • все части кода, связанные с IV, должны быть удалены (поскольку в режиме ECB не используется IV)
  • пользовательские отступы (которые ни в коем случае не PKCS5-Padding ) должны быть удалены (поскольку 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-код имеет ряд недостатков, например,

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

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

...