Вопрос по java, encryption, aes, php – Несоответствие шифрования между Java и PHP

2

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

В целях тестирования я создал скрипт PHP, который также шифрует данные, чтобы я мог сравнить зашифрованные строки Java и PHP. Результаты совпадают до 21-го символа, а затем они отличаются. Вот что у меня есть:

<code>// Java - Encrypt
private String EncryptAES(String text,String key) throws Exception
    {
      SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");

      // Instantiate the cipher
      Cipher cipher = Cipher.getInstance("AES");

      cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
      byte[] encrypted = cipher.doFinal(text.getBytes());

      String encrypttext = new BASE64Encoder().encode(encrypted);

      return encrypttext;
    }

RESULT: TeUZAFxoFoQy/roPm5tXyPzJP/TLAwR1aIGn2xHbZpsbY1qrKwXfO+F/DAqmeTwB0b8e6dsSM+Yy0zrQt22E2Q== 
</code>

а также

<code>// PHP - Encrypt
<?php

$encrypt =  $crypt = openssl_encrypt($toCrypt,"AES256","key-32-char-long");
echo $encrypt; 

?>

RESULT: TeUZAFxoFoQy/roPm5tXyC05wta1Z5YOXcq4OtgFoSbfVi/bHAuD6B5tDthT8EcGXQir08UAx0QvcqRJ2fJmbQ==
</code>

Очевидно, что-то делается правильно, потому что часть строк совпадает, но, очевидно, не все правильно, потому что остальные не совпадают. Кроме того, если я пытаюсь расшифровать строку Java в PHP, ничего не происходит:

<code>// PHP - Decrypt
<?php
$toDecrypt = "TeUZAFxoFoQy/roPm5tXyPzJP/TLAwR1aIGn2xHbZpsbY1qrKwXfO+F/DAqmeTwB0b8e6dsSM+Yy0zrQt22E2Q==";
$decrypt = openssl_decrypt($toDecrypt,"AES256","<key-32-char-long>");
echo $decrypt;

?>

RESULT: <nothing>
</code>

У кого-нибудь есть идеи, что может происходить?

И еще одно предложение: не стоит делатьbase64_decode() до расшифровки ??? shadyyx
Попробуйте & quot; AES / CBC / PKCS5Padding & quot; или "AES / CBC / PKCS7Padding" вместо "AES". Поскольку начало вашей строки правильно / дешифровано, возможно, openSSL использует CBC (Code-Block-Chaining) и Java ECB (Electronic CodeBook). Marc-Christian Schulze
Привет, Шадыкс. Openssl_encrypt () для расшифровки была опечаткой, уже исправленной. Что касается base64_decode (), я попытался и не дал никаких результатов. openssl_decrypt (base64_decode ($ toDecrypt), & Quot; AES256 & Quot;, & Quot; ключ-32-символ длиной & Quot;); user1375193
Почему вы используете один раз"key-32-char-long" и однажды"<key-32-char-long>"? И почему ты звонишьopenssl_encrypt() когда ты хочешьdecrypt и, таким образом, будет звонитьopenssl_decrypt()??? shadyyx

Ваш Ответ

5   ответов
1

$toDecrypt = "TeUZAFxoFoQy/roPm5tXyPzJP/TLAwR1aIGn2xHbZpsbY1qrKwXfO+F/DAqmeTwB0b8e6dsSM+Yy0zrQt22E2Q==";
$decrypt = openssl_decrypt(base64_decode($toDecrypt),"AES256","key-32-char-long");
echo $decrypt;

Вы должны расшифровать декодированную строку base64, а для расшифровкиopenssl_decrypt неopenssl_encrypt :-)

Не смотрите на строку base64_decoded, она будет содержать много специальных байтов. Как и другие пользователи здесь, я предлагаю проверить режим шифрования / дешифрования - CBC, OFB, CFB или ECB между Java и PHP - они должны быть одинаковыми. Но если вы выполняете кодирование base64 в коде Java после того, как строка зашифрована, то вам необходимо выполнить декодирование base64 в PHP перед расшифровкой.
@ user1375193 Но все же Вы должны сделатьbase64_decode() до расшифровки ...
Ой, это было плохо. Это & APOS; sopenssl_decrypt() Я использую :) user1375193
Я попытался, и строка base64_decode 'd стала еще хуже: & quot; M & # xFFFD; \ h & # xFFFD; 2 & # xFFFD; & # xFFFD; & # xFFFD; & # xFFFD; W & # xFFFD; & # xFFFD; & # xFFFD; & # xFFFD; & # xFFFD; & # xFFFD; ;? & # xFFFD; & # xFFFD; э & # xFFFD; & # xFFFD; & # xFFFD; & # xFFFD; е & # xFFFD; Cz & # xFFFD + & # xFFFD ;; & # xFFFD; & # XFFFD; у & л; & # x47F; & # xFFFD; & # xFFFD; 3 & # xFFFD; 2 & # xFFFD;: & # x437; м & # xFFFD; & # xFFFD; & Quot ;. $ toDecrypt = & quot; TeUZAFxoFoQy / roPm5tXyPzJP / TLAwR1aIGn2xHbZpsbY1qrKwXfO + F / DAqmeTwB0b8e6dsSM + Yy0zrQt22E2Q == & quot; $ toDecrypt = base64_decode ($ toDecrypt); echo $ toDecrypt; $ decrypt = openssl_decrypt ($ toDecrypt, «AES256», «key-32-char-long»); echo $ decrypt; user1375193
1

вместо этого используйте метод getBytes (Charset), чтобы обеспечить ту же кодировку ключа и открытого текста, что и в php

(сбросьте массив байтов в оба и посмотрите, совпадают ли они, прежде чем продолжить)

1

the key size is not explicit in the java program did you check what is the block cipher modes of operation of both programs ? CBC, ECB, OFB, etc... ? Some can require an IV to passe with the encrypted data. last idea: what is the padding used by the Java and PHP programs ?

Этот документ может помочь вам: у вас есть все действительные комбинации шифр / блочный режим шифрования / режим заполнения / размер ключа.

Граничит с комментарием материала, это не совсем ответ. Хотя вы действительно делаете некоторые правильные замечания, поэтому я не буду вас опускать.
Все еще действительный намек ;-)
0

Нужно кодировать строку как UTF-8 перед заполнением, а затем отправлять байтовый массив для шифрования. UTF-8 представляет акцентированные символы в виде двух шестнадцатеричных байтов c3 xx, поэтому преобразованная строка будет длиннее, если она содержит символы, которые необходимо кодировать. Кстати, символ c3 - это "A" с & quot; ~ & quot; сверху, так что если ваша расшифровка обнаруживается с этими нечетными символами, то вы не перекодировали расшифровку.

import java.security.NoSuchAlgorithmException;

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

импорт android.util.Log;

открытый класс MCrypt {

private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
private String iv = "cant hear you";
private String SecretKey = "top secret";

public MCrypt()
{
    ivspec = new IvParameterSpec(iv.getBytes());
    keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");                        
    try {            
        cipher = Cipher.getInstance("AES/CBC/NoPadding");
    } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    }
}

public byte[] encrypt(String text) throws Exception{
    if(text == null || text.length() == 0) throw new Exception("Empty string");

    byte[] bs = text.getBytes("UTF-8");

    byte[] toEncrypt = padBytes(bs);
    byte[] encrypted = null;
    try {
        cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
        encrypted = cipher.doFinal(toEncrypt);
    } catch (Exception e){                       
            throw new Exception("[encrypt] " + e.getMessage());
    }
    return encrypted;
}

public byte[] decrypt(String code) throws Exception{
    if(code == null || code.length() == 0)  throw new Exception("Empty string");        
    byte[] decrypted = null;
    try {
        cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);                
        decrypted = cipher.doFinal(hexToBytes(code));
    } catch (Exception e){
        throw new Exception("[decrypt] " + e.getMessage());
    }
    return decrypted;
}



    public static String bytesToHex(byte[] data){
        if (data==null){
            return null;
        }            
        int len = data.length;
        String str = "";
        for (int i=0; i<len; i++) {
            if ((data[i]&0xFF)<16)
                    str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF);
            else
                    str = str + java.lang.Integer.toHexString(data[i]&0xFF);
        }
        return str;
    }


    public static byte[] hexToBytes(String str) {
            if (str==null) {
                    return null;
            } else if (str.length() < 2) {
                    return null;
            } else {
                    int len = str.length() / 2;
                    byte[] buffer = new byte[len];
                    for (int i=0; i<len; i++) {
                            buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
                    }
                    return buffer;
            }
    }



    private static byte[] padBytes(byte[] source){
        char paddingChar = ' ';
        int size = 16;
        int x = source.length % size;
        int padLength = size - x;
        int bufferLength = source.length + padLength;
        byte[] ret = new byte[bufferLength];
        int i = 0;
        for ( ; i < source.length; i++){
            ret[i] = source[i];
        }
        for ( ; i < bufferLength; i++){
            ret[i] = (byte)paddingChar;
        }

        return ret;
    }
} // class close

Сторона pHp похожа ... (Я не могу понять, как ввести код pHp здесь !!!!

class MCrypt
{               
private $iv =  'adfdadfgfd'; #Same as in JAVA
private $key = 'adfadfdfdafadfa'; #Same as in JAVA


function __construct()
{
}

function encrypt($str) {
  $iv = $this->iv;
  $td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
  mcrypt_generic_init($td, $this->key, $iv);
  $s = padString(utf8_encode($str));
  $encrypted = mcrypt_generic($td, $s);
    //echo $encrypted;
  mcrypt_generic_deinit($td);
  mcrypt_module_close($td);
  return bin2hex($encrypted);
}

function decrypt($code) {
  $code = $this->hex2bin($code);
  $iv = $this->iv;
  $td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
  mcrypt_generic_init($td, $this->key, $iv);
  $decrypted = mdecrypt_generic($td, $code);
  mcrypt_generic_deinit($td);
  mcrypt_module_close($td);
  return (trim(utf8_decode($decrypted)));
}

protected function hex2bin($hexdata) {
  $bindata = '';
  for ($i = 0; $i < strlen($hexdata); $i += 2) {
    $bindata .= chr(hexdec(substr($hexdata, $i, 2)));
  }
  return $bindata;
}   
}

вот и все, на самом деле довольно просто ... О, кстати, если вы делаете заполнение самостоятельно, то не имеет значения, является ли метод Padding или NoPadding!

mcrypt давно заброшен в PHP, вместо него следует использовать openssl.
2

похоже, что вы используете ECB в одном и CBC в другом.

Оказывается, это был режим шифрования. По умолчанию в Java используется ECB. Однажды я прошел «AES-256-ECB» как Шифр в PHP, который решил это. Спасибо всем! user1375193

Похожие вопросы