Я задал вопрос здесь, почему расшифровка AES java возвращает лишние символы? о получении дополнительных символов при расшифровке зашифрованных данных. Благодаря комментарию пользователя «Ebbe M. Pedersen» теперь я понимаю, что проблема заключается не в использовании одного и того же механизма заполнения как в PHP, так и в коде Java Java. Поэтому я изменил код Java на
public class encryption { private String iv = "fedcba9876543210";//Dummy iv (CHANGE IT!) private IvParameterSpec ivspec; private SecretKeySpec keyspec; private Cipher cipher; private String SecretKey = "0123456789abcdef";//Dummy secretKey (CHANGE IT!) public encryption() { ivspec = new IvParameterSpec(iv.getBytes()); keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES"); try { cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");//"AES/CBC/NoPadding" } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public byte[] encrypt(String text) throws Exception { if(text == null || text.length() == 0) throw new Exception("Empty string"); byte[] encrypted = null; try { cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); encrypted = cipher.doFinal(padString(text).getBytes()); } 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 String padString(String source) { char paddingChar = ' '; int size = 16; int x = source.length() % size; int padLength = size - x; for (int i = 0; i < padLength; i++) { source += paddingChar; } return source; } }
Затем я добавил те же функции PKCS5padding
в свой PHP-класс mcrypt
:
class MCrypt { private $iv = 'fedcba9876543210'; #Same as in JAVA private $key = '0123456789abcdef'; #Same as in JAVA function MCrypt() { } function encrypt($str) { //$key = $this->hex2bin($key); $iv = $this->iv; $td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv); mcrypt_generic_init($td, $this->key, $iv); $encrypted = mcrypt_generic($td, $str); mcrypt_generic_deinit($td); mcrypt_module_close($td); return bin2hex($encrypted); } function decrypt($code) { //$key = $this->hex2bin($key); $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 utf8_encode(trim($decrypted)); } protected function hex2bin($hexdata) { $bindata = ''; for ($i = 0; $i < strlen($hexdata); $i += 2) { $bindata .= chr(hexdec(substr($hexdata, $i, 2))); } return $bindata; } 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); }}
Теперь текущая проблема заключается в отправке / получении UTF-8
, а не в том, как декодировать / кодировать символы UTF-8
. Когда я отправляю арабские / персидские слова, содержащие, например, более 3 или менее 3 символов, он ничего не возвращает. Например: если я отправлю слово «خوب» (который имеет ровно 3 символа), я получаю «خوب», что является правильным; но если я пришлю مچکرم (у которого 5 символов), я ничего не получаю.
Я обнаружил, что проблема заключается в том, что после дешифрования данных в моем php-коде я не использовал функцию-распаковку, поэтому я исправил:
<?php $data =file_get_contents('php://input'); $block_size=mcrypt_get_block_size("rijndael-128",'cbc'); require_once "encryption.php"; $etool=new MCrypt(); $data =$etool->decrypt($data); $data=$etool->pkcs5_unpad($data);// <------ using unpad function $data =json_decode($data, true); $data=$data["request"]; $etool=new MCrypt(); $data=$etool->pkcs5_pad($data,$block_size); $data=$etool->encrypt($data); $array=array('data'=>$data); echo json_encode($array);
JSONObject j=new JSONObject(sb.toString());//sb is string builder result=j.get("data").toString(); result= new String(etool.decrypt( result ),"UTF-8"); result = new String(result.getBytes("ISO-8859-1")); Log.d("success remote ",result);
Теперь проблема обратная! Я могу получить слова, содержащие более или менее трех символов персидского / арабского, но не слова, содержащие ровно 3 символа.
Я думаю, что я должен проверить, не требуется ли отладка? но как это сделать?
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); }
Этот код использует строковые функции PHP, которые по умолчанию работают с необработанным двоичным кодом и игнорируют кодировку.
Смешение ваших расшифрованных сообщений с помощью utf8_encode()
самом деле не имеет смысла. Эта функция переназначает коды ISO-8559-1 (то есть от 0x00
до 0xFF
) к 0x7f
0xc280
UTF-8 (то есть от 0x00
до 0x7f
, затем от 0xc280
до 0xc2bf
и от 0xc380
до 0xc3bf
).
Поскольку PHP работает по необработанному двоичному файлу по умолчанию, вам не нужно применять это преобразование вообще.
Примечание. Я сказал по умолчанию . В PHP есть очень глупая функция, называемая перегрузкой функций, которая контролируется директивой mpstring.func_overload PHP.ini. Если вы используете эту функцию, вам нужно переписать каждый фрагмент криптографического кода, который должен измерять и / или срезать строки, чтобы не использовать strlen()
, substr()
и т. Д.
Defuse Security опубликовала и поддерживает защищенную аутентифицированную библиотеку PHP-шифрования , которая содержит замены для этих функций, которые не могут перегружать функцию .
Уведомление о безопасности
Во-первых: ваш криптокод сломан . Другими словами: НЕ БЕЗОПАСНО .
Второе: избегайте использования mcrypt для чего-либо, если вы можете ему помочь .
Если вам просто нужны ваши данные для шифрования по проводам, просто используйте TLS . Попытка изобретать колесо здесь просто приведет к катастрофе.
Однако, если (например) вам требуется одноранговое шифрование поверх TLS (например, так что ваш сервер никогда не видит данные), не сворачивайте свои собственные. Вместо этого выберите защищенную библиотеку криптографии PHP . Если вам нужен тот, который работает кросс-платформенным, используйте libsodium .
проблема заключается в неправильном использовании функции un-padding в php-коде. на самом деле при шифровании данных в java, несколько раз, потому что текст не соответствует блоку, для которого он используется для заполнения, и если текст подходит, он этого не делает. в PHP-коде, если в java-шифровании использовалось дополнение, un-padding выполняется правильно. но если текст не нуждается в дополнении в java-шифровании, функция un-padding PHP возвращает null, а null передается переменной $ data. так что я ничего не получаю !!! путем изменения нескольких строк кода php каждый думаю, что начать работать правильно.
Код, вызывающий проблему:
$data=$etool->pkcs5_unpad($data);// in some cases null is retuned $data =Json_decode($data,true);
правильная версия кода: проблема исправлена.
$padding=$etool->pkcs5_unpad($data); if($padding!="") { $data=$padding; } $data =json_decode($data, true);