在(不太遥远)的过去,(在这里工作时间较长的人)决定在外部通信需要的时候,随时将数据库ID“加密”到其他地方。
现在,我们已经从PHP 5.x转移到PHP 7.0用于我们的主应用程序,而我们在基础架构中分散的微服务正在运行7.0或7.1。 7.1服务器继续抛出mcrypt的弃用警告。没什么大不了的。但是随着PHP 7.2的到来,我们希望不断更新和升级。麦克瑞普正在阻挠。
要在1400个数据库中保存60个表中的所有当前加密值,这是一项艰巨的任务。有没有办法利用OpenSSL,Blowfish和ECB,获得相同的编码和解码值,以使我们陷入虚假的安全感?所以我们可以在很远的情况下规划我们的数据库迁移。
基本上,当前加密的值是:
item:13fb7533bf19399ff114468b194ebfaf
这是ID 123
。它通过以下函数来获取此字符串:
$id = 123;
$type = 'item';
$serialized = serialize('' . $id); // To make sure always a string gets put in
$ivSize = mcrypt_create_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB), MCRYPT_RAND);
$iv = mcrypt_create_iv($ivSize);
$passCrypt = mcrypt_encrypt(MCRYPT_BLOWFISH, $type, $serialized, MCRYPT_MODE_ECB, $iv);
$encoded = bin2hex($passCrypt); // `13fb7533bf19399ff114468b194ebfaf`
$encryptedId = $type . ':' . $encoded;
这给出了最终结果item:13fb7533bf19399ff114468b194ebfaf
。
现在,换句话说:
$encryptedId = 'item:13fb7533bf19399ff114468b194ebfaf';
$type = 'item';
$encryptedIdOnly = substr($encryptedId, strlen($type) + 1); // `13fb...`
$decoded = hex2bin($encryptedIdOnly);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB), MCRYPT_RAND);
$decrypted = mcrypt_decrypt(MCRYPT_BLOWFISH, 'item', $decoded, MCRYPT_MODE_ECB, $iv); // This gives ' `s:3:"123";` '
$unserialized = unserialize($decrypted); // '123'
我已经尝试了几个小时,但我完全被任何加密所困扰(但我想学习!)。我目前的代码是:
$cipher = 'BF-ECB';
//$cipher = 'BF'; (I've tried both, no difference)
$isCtypeXDigit = ctype_xdigit($decipher);
$decoded = hex2bin($decipher);
$ivLength = openssl_cipher_iv_length($cipher);
$randomBytes = openssl_random_pseudo_bytes($ivLength);
$decrypted = openssl_decrypt($decoded, $cipher, $prefix, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $randomBytes);
$unserialized = unserialize($decrypted);
这给了我一千件事,与��IY_Lc�d:�_���
类似。任何人都可以对此发光 - 是否可能?
答案 0 :(得分:8)
这很棘手。你可以使用代码。
# cat a.php
<?php
function mcrypt_blowfish_encrypt_hex($key, $str)
{
$encrypted = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $str, MCRYPT_MODE_ECB);
return bin2hex($encrypted);
}
function make_openssl_blowfish_key($key)
{
if("$key" === '')
return $key;
$len = (16+2) * 4;
while(strlen($key) < $len) {
$key .= $key;
}
$key = substr($key, 0, $len);
return $key;
}
function openssl_blowfish_encrypt_hex($key, $str)
{
$blockSize = 8;
$len = strlen($str);
$paddingLen = intval(($len + $blockSize - 1) / $blockSize) * $blockSize - $len;
$padding = str_repeat("\0", $paddingLen);
$data = $str . $padding;
$key = make_openssl_blowfish_key($key);
$encrypted = openssl_encrypt($data, 'BF-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
return bin2hex($encrypted);
}
function openssl_blowfish_decrypt_hex($key, $hex)
{
$key = make_openssl_blowfish_key($key);
$decrypted = openssl_decrypt(hex2bin($hex), 'BF-ECB', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
return rtrim($decrypted, "\0");
}
function test()
{
for($i = 1; $i < 32; $i++) {
for($j = 1; $j < 32; $j++) {
$key = str_repeat('' . rand(0, 9), $j);
$str = str_repeat('' . rand(0, 9), $i);
$encoded_openssl = openssl_blowfish_encrypt_hex($key, $str);
$decoded_openssl = openssl_blowfish_decrypt_hex($key, $encoded_openssl);
if($decoded_openssl != $str)
die("encrypt($key, $str) wrong: $encoded_openssl: decrypt failed\n");
if(function_exists('mcrypt_encrypt')) {
$encoded_mcrypt = mcrypt_blowfish_encrypt_hex($key, $str);
if($encoded_openssl != $encoded_mcrypt)
die("encrypt($key, $str) wrong: $encoded_openssl, mcrypt=$encoded_mcrypt\n");
}
echo "key='$key', str='$str', encrypted='$encoded_openssl'\n";
}
}
}
echo "openssl: thisismyitemyes:" . openssl_blowfish_encrypt_hex('thisismyitemyes', serialize('6918')) . "\n";
echo "openssl: headphone:" . openssl_blowfish_encrypt_hex('headphone', serialize('581856')) . "\n";
test();
跑步,它有效:
# php a.php
openssl: thisismyitemyes:b192ac0f6105416a710aec3ce92b1085
openssl: headphone:ef057c036eb024865406838c62590a93
key='7', str='3', encrypted='945b638624ecbd5e'
key='22', str='1', encrypted='3daf096bdc744d8a'
key='888', str='0', encrypted='b164bb0b603f439e'
key='2222', str='9', encrypted='d3458df30aef0b4b'
...
...
key='3333333333333333333333333333333', str='11111111111111111111111111111', encrypted='b0c9bf45d6f5c7b3b0c9bf45d6f5c7b3b0c9bf45d6f5c7b363a25777c712f1d5'
key='4444444444444444444444444444444', str='999999999999999999999999999999', encrypted='dd6aaf466121c0f6dd6aaf466121c0f6dd6aaf466121c0f659a2271369ab6731'
key='7777777777777777777777777777777', str='3333333333333333333333333333333', encrypted='6591e9cc92a6473a6591e9cc92a6473a6591e9cc92a6473a208a7a562babc60c'
问题:
在ECB模式下会忽略IV,因此只需删除代码中的所有IV。
由于错误:https://bugs.php.net/bug.php?id=72362。在mcrypt
中,河豚键由短键循环。但是在openssl
中,河豚键被短键填充为零。所以我们需要为openssl创建一个循环密钥来解密mcrypt的加密。
当你使用openssl进行零填充时(保持mcrypt的输出相同),你应该自己进行填充。好吧,我做了一个获得paddingLen的技巧,但这很简单:只考虑我们应该追加多少字节来使总长度为0/8/16/24/32/40等。