将我的encryption库从Mcrypt升级到OpenSSL
我正在使用下面通常引用的库进行encryption。 我想从Mcrypt升级到OpenSSL,这样我不再使用废弃的库。
我试图找出这是甚至可能的。 我已经做了一些研究,但是我发现有矛盾的信息:
这篇文章说,使用Mcryptencryption的OpenSSL来解密数据是不可能的。 https://stackoverflow.com/a/19748494/5834657
不过,这个post说可以使用填充。 看来,我的function使用填充。 这是需要使这项工作的正确types的填充? https://stackoverflow.com/a/31614770/5834657
<?php namespace Utilities\Encryption; /** * A class to handle secure encryption and decryption of arbitrary data * * Note that this is not just straight encryption. It also has a few other * features in it to make the encrypted data far more secure. Note that any * other implementations used to decrypt data will have to do the same exact * operations. * * Security Benefits: * * - Uses Key stretching * - Hides the Initialization Vector * - Does HMAC verification of source data * */ class Encryption { /** * @var string $cipher The mcrypt cipher to use for this instance */ protected $cipher = ''; /** * @var int $mode The mcrypt cipher mode to use */ protected $mode = ''; /** * @var int $rounds The number of rounds to feed into PBKDF2 for key generation */ protected $rounds = 100; /** * Constructor! * * @param string $cipher The MCRYPT_* cypher to use for this instance * @param int $mode The MCRYPT_MODE_* mode to use for this instance * @param int $rounds The number of PBKDF2 rounds to do on the key */ public function __construct($cipher, $mode, $rounds = 100) { $this->cipher = $cipher; $this->mode = $mode; $this->rounds = (int) $rounds; } /** * Decrypt the data with the provided key * * @param string $data The encrypted datat to decrypt * @param string $key The key to use for decryption * * @returns string|false The returned string if decryption is successful * false if it is not */ public function decrypt($data, $key) { $salt = substr($data, 0, 128); $enc = substr($data, 128, -64); $mac = substr($data, -64); list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key); if ($mac !== hash_hmac('sha512', $enc, $macKey, true)) { return false; } $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv); $data = $this->unpad($dec); return $data; } /** * Encrypt the supplied data using the supplied key * * @param string $data The data to encrypt * @param string $key The key to encrypt with * * @returns string The encrypted data */ public function encrypt($data, $key) { $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM); list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key); $data = $this->pad($data); $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv); $mac = hash_hmac('sha512', $enc, $macKey, true); return $salt . $enc . $mac; } /** * Generates a set of keys given a random salt and a master key * * @param string $salt A random string to change the keys each encryption * @param string $key The supplied key to encrypt with * * @returns array An array of keys (a cipher key, a mac key, and a IV) */ protected function getKeys($salt, $key) { $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode); $keySize = mcrypt_get_key_size($this->cipher, $this->mode); $length = 2 * $keySize + $ivSize; $key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length); $cipherKey = substr($key, 0, $keySize); $macKey = substr($key, $keySize, $keySize); $iv = substr($key, 2 * $keySize); return array($cipherKey, $macKey, $iv); } /** * Stretch the key using the PBKDF2 algorithm * * @see http://en.wikipedia.org/wiki/PBKDF2 * * @param string $algo The algorithm to use * @param string $key The key to stretch * @param string $salt A random salt * @param int $rounds The number of rounds to derive * @param int $length The length of the output key * * @returns string The derived key. */ protected function pbkdf2($algo, $key, $salt, $rounds, $length) { $size = strlen(hash($algo, '', true)); $len = ceil($length / $size); $result = ''; for ($i = 1; $i <= $len; $i++) { $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true); $res = $tmp; for ($j = 1; $j < $rounds; $j++) { $tmp = hash_hmac($algo, $tmp, $key, true); $res ^= $tmp; } $result .= $res; } return substr($result, 0, $length); } protected function pad($data) { $length = mcrypt_get_block_size($this->cipher, $this->mode); $padAmount = $length - strlen($data) % $length; if ($padAmount == 0) { $padAmount = $length; } return $data . str_repeat(chr($padAmount), $padAmount); } protected function unpad($data) { $length = mcrypt_get_block_size($this->cipher, $this->mode); $last = ord($data[strlen($data) - 1]); if ($last > $length) return false; if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) { return false; } return substr($data, 0, -1 * $last); } }
更新:我一直试图通过使用OpenSSL将库转换为OpenSSL来解密用Mcryptencryption的string。
然后,我使用上面的代码使用密钥对string进行encryption,并尝试使用下面的代码和相同的密钥对该值进行解密。 不过,我只是得到一个空白的回应。 如果我评论一下:
$ data = $ this-> unpad($ dec)
在解密函数中,我得到一个string,但它只是混淆了字符(很像它看起来什么时候它是第一次encryption)。
<?php namespace Utilities\Encryption; /** * A class to handle secure encryption and decryption of arbitrary data * * Note that this is not just straight encryption. It also has a few other * features in it to make the encrypted data far more secure. Note that any * other implementations used to decrypt data will have to do the same exact * operations. * * Security Benefits: * * - Uses Key stretching * - Hides the Initialization Vector * - Does HMAC verification of source data * */ class EncryptionOpenSsl { /** * @var string $cipher The mcrypt cipher to use for this instance */ protected $cipher = ''; /** * @var int $mode The mcrypt cipher mode to use */ protected $mode = ''; /** * @var int $rounds The number of rounds to feed into PBKDF2 for key generation */ protected $rounds = 100; /** * Constructor! * * @param string $cipher The MCRYPT_* cypher to use for this instance * @param int $mode The MCRYPT_MODE_* mode to use for this instance * @param int $rounds The number of PBKDF2 rounds to do on the key */ public function __construct($cipher, $rounds = 100) { $this->cipher = $cipher; // $this->mode = MCRYPT_MODE_CBC; $this->rounds = (int) $rounds; } /** * Decrypt the data with the provided key * * @param string $data The encrypted datat to decrypt * @param string $key The key to use for decryption * * @returns string|false The returned string if decryption is successful * false if it is not */ public function decrypt($data, $key) { $salt = substr($data, 0, 128); $enc = substr($data, 128, -64); $mac = substr($data, -64); list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key); if ($mac !== hash_hmac('sha512', $enc, $macKey, true)) { return false; } $dec = openssl_decrypt($enc, $this->cipher, $key, OPENSSL_RAW_DATA, $iv); // $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv); $data = $this->unpad($dec); return $data; } /** * Encrypt the supplied data using the supplied key * * @param string $data The data to encrypt * @param string $key The key to encrypt with * * @returns string The encrypted data */ public function encrypt($data, $key) { $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM); list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key); $data = $this->pad($data); $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv); $mac = hash_hmac('sha512', $enc, $macKey, true); return $salt . $enc . $mac; } /** * Generates a set of keys given a random salt and a master key * * @param string $salt A random string to change the keys each encryption * @param string $key The supplied key to encrypt with * * @returns array An array of keys (a cipher key, a mac key, and a IV) */ protected function getKeys($salt, $key) { $ivSize = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC); $keySize = mcrypt_get_key_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC); $length = 2 * $keySize + $ivSize; $key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length); $cipherKey = substr($key, 0, $keySize); $macKey = substr($key, $keySize, $keySize); $iv = substr($key, 2 * $keySize); return array($cipherKey, $macKey, $iv); } /** * Stretch the key using the PBKDF2 algorithm * * @see http://en.wikipedia.org/wiki/PBKDF2 * * @param string $algo The algorithm to use * @param string $key The key to stretch * @param string $salt A random salt * @param int $rounds The number of rounds to derive * @param int $length The length of the output key * * @returns string The derived key. */ protected function pbkdf2($algo, $key, $salt, $rounds, $length) { $size = strlen(hash($algo, '', true)); $len = ceil($length / $size); $result = ''; for ($i = 1; $i <= $len; $i++) { $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true); $res = $tmp; for ($j = 1; $j < $rounds; $j++) { $tmp = hash_hmac($algo, $tmp, $key, true); $res ^= $tmp; } $result .= $res; } return substr($result, 0, $length); } protected function pad($data) { $length = mcrypt_get_block_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC); $padAmount = $length - strlen($data) % $length; if ($padAmount == 0) { $padAmount = $length; } return $data . str_repeat(chr($padAmount), $padAmount); } protected function unpad($data) { $length = mcrypt_get_block_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC); $last = ord($data[strlen($data) - 1]); if ($last > $length) return false; if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) { return false; } return substr($data, 0, -1 * $last); } }
这个解密程序的代码适用于我:
public function decrypt($data, $key) { $salt = substr($data, 0, 128); $enc = substr($data, 128, -64); $mac = substr($data, -64); list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key); if ($mac !== hash_hmac('sha512', $enc, $macKey, true)) { return false; } $dec = openssl_decrypt($enc, $this->cipher, $cipherKey, OPENSSL_RAW_DATA, $iv); return $dec; }
testing:
$keys = [ 'this is a secret key.', 'G906m70p(IhzA5T&5x7(w0%a631)u)%D6E79cIYJQ!iP2U(xT13q6)tJ6gZ3D2wi&0")7cP5', chr(6) . chr(200) . chr(16) . 'my key ' . chr(3) . chr(4) . chr(192) . chr(254) . ' zyx0987!!', 'and finally one more key to test with here:', ]; $data = [ 'A', 'This is a test', 'now test encrypting something a little bit longer with 1234567890.', '$length = mcrypt_get_block_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC); $last = ord($data[strlen($data) - 1]);', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sit amet pharetra urna. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Ut fringilla, quam sed eleifend eleifend, justo turpis consectetur tellus, quis tristique eros erat at nibh. Nunc dictum neque vel diam molestie fermentum. Pellentesque dignissim dui quis tortor eleifend, ut maximus elit egestas. Donec posuere odio et auctor porta. Quisque placerat condimentum maximus. Curabitur luctus dolor eget sem luctus, in dignissim tortor venenatis. Mauris eget nulla nisl.', ]; $failures = 0; foreach ($data as $datum) { foreach ($keys as $key) { $enc = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC); $encrypted = $enc->encrypt($datum, $key); $dec = new EncryptionOpenSsl('bf-cbc'); $decrypted = $dec->decrypt($encrypted, $key); if (strcmp($datum, $decrypted) !== 0) { echo "Encryption with key '$key' of '$datum' failed. '$decrypted' != '$datum'<br><br>\n\n"; $failures++; } } } if ($failures) { echo "$failures tests failed.<br>\n"; } else { echo "ALL OKAY<br>\n"; }
如果你能确认它也适用于你,我可以收拾答案,并添加最终的工作代码。