Дешифрование PHP происходит с ошибкой на некоторых строках с помощью trim ()

У меня возникают проблемы с расшифровкой значений, которые заканчиваются% 3D% 3D. После дешифрования я получаю возвращаемое значение, которое совершенно неразборчиво. Зашифрованное значение передается через querystring, но я проверил цикл цикла с значениями от 0 до 200, чтобы исключить проблемы с кодировкой url.

Функции шифрования и дешифрования:

function encryptValue($encrypt) { $key = variable_get_local("privateKey", $default = ""); $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND); $passcrypt = trim(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, trim($encrypt), MCRYPT_MODE_ECB, $iv)); $encode = urlencode(base64_encode($passcrypt)); return $encode; } function decryptValue($decrypt) { $key = variable_get_local("privateKey", $default = ""); $decoded = base64_decode(urldecode($decrypt)); $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND); $decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, trim($decoded), MCRYPT_MODE_ECB, $iv)); return $decrypted; } 

Я попытался сохранить значение iv одинаковым для шифрования и дешифрования, но это не меняет результат. Я также попытался удалить trim() вокруг trim($decoded) но это ничего не изменило.

Ниже приводится то, что я использовал для определения проблемы. Между 0 и 200 шифрованием будет выдаваться значение, оканчивающееся на% 3D% 3D 9 раз и приводящее к сбою дешифрования.

 for($i=0;$i<200;$i++) { echo encryptValue($i) . "<br/>"; echo decryptValue(encryptValue($i)) . "<br/><hr/>"; } 

Спасибо за прочтение.

Ваша проблема связана со всеми функциями trim , которые не должны использоваться. Вы не обрезаете закодированные данные, поскольку данные будут удалены, могут быть жизненно важными для ключа, как вы заметили.

Он работает следующим образом:

 function encryptValue($encrypt) { $key = variable_get_local("privateKey", $default = ""); $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND); $passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, trim($encrypt), MCRYPT_MODE_ECB, $iv); $encode = urlencode(base64_encode($passcrypt)); return $encode; } function decryptValue($decrypt) { $key = variable_get_local("privateKey", $default = ""); $decoded = base64_decode(urldecode($decrypt)); $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND); $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_ECB, $iv); return $decrypted; } 

Вот несколько замечаний в текущем скрипте:

  • Режим ECB небезопасен, CBC вместо использования CBC
  • MCRYPT_RAND – это то же самое, что и rand см. Str_shuffle, а случайность использует MCRYPT_DEV_URANDOM вместо
  • Для лучшей безопасности используйте шифрование + аутентификацию с использованием HMAC для предотвращения предотвращения атаки оракула
  • Используйте надлежащую тестированную библиотеку, а также Zend\Crypt а не создавайте свой синус. Вы не специалист по безопасности

Пример :

 // Encription Key $encryptionKey = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM); // Stored securely // Signature Key $signatureKey = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM); // Stored securely // Start DataEncryption Object $obj = new DataEncryption($encryptionKey, $signatureKey); $obj->setEncoding(DataEncryption::ENCODE_BASE64); // Test for($i = 0; $i < 200; $i ++) { printf("%s = %s\n", $encode = $obj->encrypt($i), $obj->decrypt($encode)); } 

Вывод

 eSCknmsoMHY2oo5lpW3NpQhDigs4+Fw8aObeIhK+wPyUImQbvlh/aUrW = 0 qFswb3VO5+Foi4kjVn6s5lpZbiWgdKmfObh37/xjPyqB4ZFfAXNUeYYX = 1 WKG0BCKUxOXWU6S3YJ/dNL46Lcn7lt+ihG4tEoZuORDoJXSjz6Vrcepn = 2 K24QqkGYC86btzGQ5HKKMewVhiEIdKOajpgLx8SMKVKfCwlOJlbRwpaz = 3 0DbJycPZ24FOAhQrhQJmgMsP0p2nFzYUlFVOFlbQ8zhLTXkcdnNOhVfi = 4 l7saQG2BTPAZR2EnYjxfNmTxEBBaAh+n9+8eOCITDGzEVShw9wOxP7Pt = 5 eUhvvHJOFsy6ZaBu40XgU+N5VtuFBesRVx0ryfManIXva5y7J0ShiKcE = 6 TaX+172N60X1UTVmMWYcdcn7YzN7xoAOVEPpaD7r1pE3OtX5Erg4nja8 = 7 0LM3W0pkQ73IsmqAgRiQvqL0/rdkk7YvuwcVwoe1NI+qZo7Jq8gyFIvn = 8 .... 38m8fEoUhoTyPPBukg3KVhrmwVDyVCcnWx/5erAslUDzEP7Bddzj5y8Y = 196 Dwi6t7sX30bxjbVXMKCWEZs0FxTUZM4IPHKR3VD6kygi7op0Q6ARCZJW = 197 TJ/faDaIuE0mDPHmGar1BeIyAnfVD0Z47ZtCcHjz5AZzaQ1YWH8kF1bU = 198 FYh+8Kts4ubVvTT5o0vZYfKC+8ExhpD5pWgHK3EhvGWkcPwKerSIvkK0 = 199 

Используемый класс

 class DataEncryption { private $keyEncryption; private $keySignature; private $ivSize; private $cipher = MCRYPT_RIJNDAEL_128; private $mode = MCRYPT_MODE_CBC; private $signatureLength = 10; private $encoding = 2; // I prefer hex const ENCODE_BASE64 = 1; const ENCODE_HEX = 2; function __construct($encryptionKey = null, $signatureKey = null) { // Set Keys $this->keyEncryption = empty($encryptionKey) ? mcrypt_create_iv(32, MCRYPT_DEV_URANDOM) : $encryptionKey; $this->keySignature = empty($signatureKey) ? mcrypt_create_iv(32, MCRYPT_DEV_URANDOM) : $signatureKey; // Get IV Size $this->ivSize = mcrypt_get_iv_size($this->cipher, $this->mode); } public function getKeys() { return array( "encryption" => $this->keyEncryption, "signature" => $this->keySignature ); } public function setMode($mode) { $this->mode = $mode; } public function setCipher($cipher) { $this->cipher = $cipher; } public function setEncoding($encode) { $this->encoding = $encode; } public function encrypt($data) { // add PKCS7 padding to data $block = mcrypt_get_block_size($this->cipher, $this->mode); $pad = $block - (strlen($data) % $block); $data .= str_repeat(chr($pad), $pad); $iv = $this->rand($this->ivSize); $cipherData = mcrypt_encrypt($this->cipher, $this->keyEncryption, $data, $this->mode, $iv); $finalData = $iv . $cipherData; // protected against padding oracle attacks $finalData = $this->sign($finalData) . $finalData; return $this->encode($finalData); } public function decrypt($data) { $data = $this->decode($data); // Check Integrity if (! $this->check($data)) { return false; } $data = substr($data, $this->signatureLength); // Break Data $iv = substr($data, 0, $this->ivSize); $cipherData = substr($data, $this->ivSize); $data = mcrypt_decrypt($this->cipher, $this->keyEncryption, $cipherData, $this->mode, $iv); // Remove PKCS7 padding $block = mcrypt_get_block_size($this->cipher, $this->mode); $pad = ord($data[($len = strlen($data)) - 1]); // $data = rtrim($data, "\0..\32"); return substr($data, 0, $len - $pad); } public function encode($data) { return $this->encoding === self::ENCODE_BASE64 ? base64_encode($data) : bin2hex($data); } public function decode($data) { return $this->encoding === self::ENCODE_BASE64 ? base64_decode($data) : pack("H*", $data); } public function sign($data) { $hash = hash_hmac('sha256', $data, $this->keySignature, true); return substr($hash, 0, $this->signatureLength); } public function check($data) { $signature = substr($data, 0, $this->signatureLength); $data = substr($data, $this->signatureLength); $hash = hash_hmac('sha256', $data, $this->keySignature, true); // return $signature === substr($hash, 0, $this->signatureLength); return $this->compare($signature, substr($hash, 0, $this->signatureLength)); } public function rand($no) { return mcrypt_create_iv($no, MCRYPT_DEV_URANDOM); } /** * Prevent Timing Attacks * @param string $a * @param string $b * @return boolean */ public function compare($a, $b) { if (strlen($a) !== strlen($b)) { return false; } $result = 0; for($i = 0; $i < strlen($a); $i ++) { $result |= ord($a[$i]) ^ ord($b[$i]); } return $result == 0; } }