Как шифровать AES CBC с помощью pidCrypt, а затем расшифровывать с помощью phpseclib?
Мне нужно зашифровать короткую строку с помощью Javascript ( pidCrypt AES CBC), а затем расшифровать ее с помощью PHP ( phpseclib Crypt_AES CBC).
Существует так много несовместимостей между различными библиотеками (перепробовал многие из них, некоторые из которых я даже не смог использовать из-за отсутствия документации), что я очень стараюсь понять и преодолеть их (текущие "стандарты" просто не понимают Покройте отладку, а бред или просто false
будет возвращено с неправильным использованием).
pidCrypt AES CBC говорит, что использует OpenSSL-совместимую кодировку.
Пока я не могу понять, почему вывод из pidCrypt не будет расшифрован в phpseclib:
pidCrypt
var aes=new pidCrypt.AES.CBC();
aes.encryptText("abcdefg", "secret", {nBits: 128});
console.log(aes.pidcrypt.getParams());
/**
A0_PAD: true
UTF8: true
blockSize: 16
clear: true
dataIn: "abcdefg"
dataOut: "U2FsdGVkX19p8dJctoZSgamat+UBHMWM/Zx64fBDYJY="
decryptIn: ""
decryptOut: ""
encryptIn: Array[16]
encryptOut: "©·åÅýzáðC`"
iv: "e314f8ebbcc5a1e0ae6c27033dd6725f"
key: "49f9bd99b7952b68b3bfa47404455fa7"
nBits: 128
salt: "69f1d25cb6865281"
*/
phpseclib
function hex2raw($strHexString)
{
$strRawBytes="";
$arrChunks=str_split($strHexString, 2);
for($i=0; $i<count($arrChunks); $i++)
$strRawBytes.=chr(hexdec($arrChunks[$i]));
return $strRawBytes;
}
require_once("Crypt/AES.php");
$aes=new Crypt_AES(CRYPT_AES_MODE_CBC);
$aes->setPassword("secret");
$aes->setIV(hex2raw("e314f8ebbcc5a1e0ae6c27033dd6725f"));
var_export($aes->decrypt(base64_decode("U2FsdGVkX19p8dJctoZSgamat+UBHMWM/Zx64fBDYJY=")));
/**
false
*/
Я также попробовал пример phpseclib AES CBC "Key Derivation: None" (setKey и setIV вместо setPassword) с теми же результатами.
Как я могу получить phpseclib для декодирования вышеприведенного вывода pidCrypt AES CBC?
или же
Существуют ли альтернативы phpseclib, которые могут расшифровать вышеприведенный вывод pidCrypt (у которого есть API кода; примеры использования OpenSSL недопустимы)?
Пожалуйста, не читайте лекций о безопасности Javascript и сетевой безопасности. Это не предназначено для защиты от перехвата интернета / сети.
2 ответа
В комментарии к php.net нашли решение для расшифровки с использованием OpenSSL, удалили часть OpenSSL и заменили ее на phpseclib (которая, в свою очередь, использует php mcrypt или его собственную программную реализацию).
require_once("Crypt/AES.php");
//https://www.pidder.com/pidcrypt/?page=demo_aes-cbc
//"U2FsdGVkX18KqDRV4bSqJCauxP7004rQmPu3HD1FUrgbXEGpjJAKAfgYvxtWJ6iJ"
//Used the password: "password".
var_export(pidCryptAESCBCDecrypt("U2FsdGVkX18KqDRV4bSqJCauxP7004rQmPu3HD1FUrgbXEGpjJAKAfgYvxtWJ6iJ", "password"));
//Outputs: "Some text to encrypt..."
function pidCryptAESCBCDecrypt($strBase64OpenSSLCompatibleCipher, $strPassword)
{
$data=base64_decode($strBase64OpenSSLCompatibleCipher);
$salt=substr($data, 8, 8);
$ct=substr($data, 16);
/**
* From https://github.com/mdp/gibberish-aes
*
* Number of rounds depends on the size of the AES in use
* 3 rounds for 256
* 2 rounds for the key, 1 for the IV
* 2 rounds for 128
* 1 round for the key, 1 round for the IV
* 3 rounds for 192 since it's not evenly divided by 128 bits
*/
$rounds = 3;
$data00 = $strPassword.$salt;
$md5_hash = array();
$md5_hash[0] = md5($data00, true);
$result = $md5_hash[0];
for ($i = 1; $i < $rounds; $i++) {
$md5_hash[$i] = md5($md5_hash[$i - 1].$data00, true);
$result .= $md5_hash[$i];
}
$key = substr($result, 0, 32);
$iv = substr($result, 32,16);
$aes=new Crypt_AES(CRYPT_AES_MODE_CBC);
$aes->setKey($key);
$aes->setIV($iv);
echo $aes->decrypt($ct);
}
Обновление: еще проще (не могу поверить, что я его не видел), отправьте на phpseclib pidCryptUtil.encodeBase64(aes.pidcrypt.getParams().encryptOut)
, aes.pidcrypt.getParams().iv
а также aes.pidcrypt.getParams().key
,
Хорошо, так что после МНОГО царапин и ударов по стенам, я думаю, что мне наконец-то удалось найти решение, которое работает ОБА, но я все еще сталкиваюсь со странной аномалией и хочу выяснить, действительно ли я делаю что-то не так. То, чего я пытался добиться, - это возможность AES 256 зашифровать строку в PHP (я хотел сделать это, используя только MCrypt, но увы), а затем расшифровать эту же строку, используя PidCrypt (JQuery). Найти решения, отвечающие моим потребностям, было практически невозможно, пока я не открыл эту тему.
НО даже после успешной реализации функции DECRYPT (используя как библиотеку PHP Crypt_AES, так и просто используя openssl_decrypt/encrypt) я все еще не мог должным образом расшифровать сообщения в PidCrypt, которые были зашифрованы в PHP.
Вот что у меня есть (обратите внимание, что я использовал демонстрационную страницу AES по адресу https://sourceforge.net/projects/pidcrypt/ для шифрования / дешифрования сообщений с помощью PidCrypt - 256 AES).
Это код PHP, который работает для меня:
//for those who can't use openssl_encrypt because they don't have PHP >= 5.3.X
//the only solution I've found is to install phpseclib.sourceforge.net/crypt
require_once("Crypt/AES.php");
echo decrypt('TEST', 'U2FsdGVkX1/yPcPIrEGSGvkII+qMeyrOY+l3t09Gylc1td80g0VFtzRw1MbjYJZ3I1JJOW9G6wMlUxpu2gjHq68fwxo3Bds+PlpCnjgDBwL+VZe8QSOwS/CMPh9A+cOkyGQ+fCNp/KnKwgkqTziCpSWjgbFSlcOHtMWPoy1ecMM+CjhzyUZQ6SfJs+K8x9tj');
echo '<br />';
echo encrypt('TEST', 'TESTING RANDOM DATA PLEASE EXPLAIN WHY I HAVE TO PUT AN ADDITIONAL BYTE ON THE END OF THE DATA TO DECRYPT THE ORIGINAL STRING?');
function decrypt($password, $edata) {
$data = base64_decode($edata);
$salt = substr($data, 8, 8);
$ct = substr($data, 16);
$rounds = 3;
$data00 = $password . $salt;
$md5_hash = array();
$md5_hash[0] = md5($data00, true);
$result = $md5_hash[0];
for($i = 1; $i < $rounds; $i++) {
$md5_hash[$i] = md5($md5_hash[$i - 1] . $data00, true);
$result .= $md5_hash[$i];
}
$key = substr($result, 0, 32);
$iv = substr($result, 32, 16);
//phpseclib specifics
$aes = new Crypt_AES(CRYPT_AES_MODE_CBC);
$aes->setKey($key);
$aes->setIV($iv);
return $aes->decrypt($ct);
//instead of using phpseclib with openssl_decrypt you would do the following
//return openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv);
}
function encrypt($password, $data) {
//my randomly generated 8 byte salt
$salt = substr(time(), -8);
//alternatively with openssl you would use
//$salt = openssl_random_pseudo_bytes(8);
$salted = '';
$dx = '';
while(strlen($salted) < 48) {
$dx = md5($dx . $password . $salt, true);
$salted .= $dx;
}
$key = substr($salted, 0, 32);
$iv = substr($salted, 32, 16);
//phpseclib specifics
$aes = new Crypt_AES(CRYPT_AES_MODE_CBC);
$aes->setKey($key);
$aes->setIV($iv);
$encrypted_data = $aes->encrypt($data . "\n");
//alternatively with openssl you would do the following
//$encrypted_data = openssl_encrypt($data . "\n", 'aes-256-cbc', $key, true, $iv);
return base64_encode('Salted__' . $salt . $encrypted_data);
}
СЕЙЧАС кто-то ПОЖАЛУЙСТА скажет мне, почему я должен добавить дополнительный символ, неважно, что это такое, просто нужно добавить его в конец моих $ data, которые должны быть зашифрованы, в противном случае, когда я иду расшифровывать строку на на сайте PidCrypt, если я не включил дополнительный символ (в моем случае это перевод строки), то он будет отрезать последний символ зашифрованной строки?
Я могу жить с добавлением дополнительного символа, если я не делаю что-то не так. Если это ошибка между PHP и PidCrypt, то я оставлю это в покое, пока он работает...