PHP中的AES解密
Posted
技术标签:
【中文标题】PHP中的AES解密【英文标题】:AES decryption in PHP 【发布时间】:2013-10-28 16:57:16 【问题描述】:我有一个需要使用 php 解密的 base64 加密字符串,加密字符串是由我反转的闪存应用程序生成的,我发现它使用 AES。问题是我不知道我得到的 AES 实现是否是我可以在 PHP 中复制的标准。如果有一个我可以在不安装 mcrypt 的情况下使用的 PHP 类会更好。 以下是 Flash 应用程序解密字符串的示例:
var encrypted:String = AES.encrypt("hello world","my great key",AES.BIT_KEY_256); // "06/0/6Ojo6ObeIEZaHcxAinbjD=="
// I need to do this in php
var decrypted:String = AES.decrypt("06/0/6Ojo6ObeIEZaHcxAinbjD==","my great key",AES.BIT_KEY_256); // "hello world"
反向 AES 类:
public class AES
public static const BIT_KEY_128:int = 128;
public static const BIT_KEY_192:int = 192;
public static const BIT_KEY_256:int = 0x0100;
private static const SBOX:Array = [
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 0xFF, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22];
private static const RCON:Array = [
[0, 0, 0, 0],
[1, 0, 0, 0],
[2, 0, 0, 0],
[4, 0, 0, 0],
[8, 0, 0, 0],
[16, 0, 0, 0],
[32, 0, 0, 0],
[64, 0, 0, 0],
[128, 0, 0, 0],
[27, 0, 0, 0],
[54, 0, 0, 0]
];
public static function encrypt(_arg1:String, _arg2:String, _arg3:int):String
var _local19:int;
var _local20:Array;
var _local21:int;
var _local22:Array;
var _local4 = 16;
if (!(((((_arg3 == BIT_KEY_128)) || ((_arg3 == BIT_KEY_192)))) || ((_arg3 == BIT_KEY_256))))
throw (new Error("Must be a key mode of either 128, 192, 256 bits"));
;
_arg1 = Utf8.encode(_arg1);
_arg2 = Utf8.encode(_arg2);
var _local5:int = (_arg3 / 8);
var _local6:Array = new Array(_local5);
var _local7:int;
while (_local7 < _local5)
_local6[_local7] = ((isNaN(_arg2.charCodeAt(_local7))) ? 0 : _arg2.charCodeAt(_local7));
_local7++;
;
var _local8:Array = cipher(_local6, keyExpansion(_local6));
_local8 = cipher(_local6, keyExpansion(_local6)).concat(_local8.slice(0, (_local5 - 16)));
var _local9:Array = new Array(_local4);
var _local10:int = new Date().getTime();
var _local11:int = Math.floor((_local10 / 1000));
var _local12:int = (_local10 % 1000);
_local7 = 0;
while (_local7 < 4)
_local9[_local7] = ((_local11 >>> (_local7 * 8)) & 0xFF);
_local7++;
;
_local7 = 0;
while (_local7 < 4)
_local9[(_local7 + 4)] = (_local12 & 0xFF);
_local7++;
;
var _local13 = "";
_local7 = 0;
while (_local7 < 8)
_local13 = (_local13 + String.fromCharCode(_local9[_local7]));
_local7++;
;
var _local14:Array = keyExpansion(_local8);
var _local15:int = Math.ceil((_arg1.length / _local4));
var _local16:Array = new Array(_local15);
var _local17:int;
while (_local17 < _local15)
_local19 = 0;
while (_local19 < 4)
_local9[(15 - _local19)] = ((_local17 >>> (_local19 * 8)) & 0xFF);
_local19++;
;
_local19 = 0;
while (_local19 < 4)
_local9[((15 - _local19) - 4)] = ((_local17 / 4294967296) >>> (_local19 * 8));
_local19++;
;
_local20 = cipher(_local9, _local14);
_local21 = (((_local17 < (_local15 - 1))) ? _local4 : (((_arg1.length - 1) % _local4) + 1));
_local22 = new Array(_local21);
_local7 = 0;
while (_local7 < _local21)
_local22[_local7] = (_local20[_local7] ^ _arg1.charCodeAt(((_local17 * _local4) + _local7)));
_local22[_local7] = String.fromCharCode(_local22[_local7]);
_local7++;
;
_local16[_local17] = _local22.join("");
_local17++;
;
var _local18:String = (_local13 + _local16.join(""));
_local18 = Base64.encode(_local18);
return (_local18);
public static function decrypt(_arg1:String, _arg2:String, _arg3:int):String
var _local16:int;
var _local18:int;
var _local19:Array;
var _local20:Array;
var _local4 = 16;
if (!(((((_arg3 == BIT_KEY_128)) || ((_arg3 == BIT_KEY_192)))) || ((_arg3 == BIT_KEY_256))))
throw (new Error("Must be a key mode of either 128, 192, 256 bits"));
;
_arg1 = Base64.decode(_arg1);
_arg2 = Utf8.encode(_arg2);
var _local5:int = (_arg3 / 8);
var _local6:Array = new Array(_local5);
var _local7:int;
while (_local7 < _local5)
_local6[_local7] = ((isNaN(_arg2.charCodeAt(_local7))) ? 0 : _arg2.charCodeAt(_local7));
_local7++;
;
var _local8:Array = cipher(_local6, keyExpansion(_local6));
_local8 = cipher(_local6, keyExpansion(_local6)).concat(_local8.slice(0, (_local5 - 16)));
var _local9:Array = new Array(8);
var _local10:String = _arg1.slice(0, 8);
_local7 = 0;
while (_local7 < 8)
_local9[_local7] = _local10.charCodeAt(_local7);
_local7++;
;
var _local11:Array = keyExpansion(_local8);
var _local12:int = Math.ceil(((_arg1.length - 8) / _local4));
var _local13:Array = new Array(_local12);
_local16 = 0;
while (_local16 < _local12)
_local13[_local16] = _arg1.slice((8 + (_local16 * _local4)), ((8 + (_local16 * _local4)) + _local4));
_local16++;
;
var _local14:Array = _local13;
var _local15:Array = new Array(_local14.length);
_local16 = 0;
while (_local16 < _local12)
_local18 = 0;
while (_local18 < 4)
_local9[(15 - _local18)] = ((_local16 >>> (_local18 * 8)) & 0xFF);
_local18++;
;
_local18 = 0;
while (_local18 < 4)
_local9[((15 - _local18) - 4)] = (((((_local16 + 1) / 4294967296) - 1) >>> (_local18 * 8)) & 0xFF);
_local18++;
;
_local19 = cipher(_local9, _local11);
_local20 = new Array(String(_local14[_local16]).length);
_local7 = 0;
while (_local7 < String(_local14[_local16]).length)
_local20[_local7] = (_local19[_local7] ^ String(_local14[_local16]).charCodeAt(_local7));
_local20[_local7] = String.fromCharCode(_local20[_local7]);
_local7++;
;
_local15[_local16] = _local20.join("");
_local16++;
;
var _local17:String = _local15.join("");
_local17 = Utf8.decode(_local17);
return (_local17);
private static function cipher(_arg1:Array, _arg2:Array):Array
var _local3 = 4;
var _local4:int = ((_arg2.length / _local3) - 1);
var _local5:Array = [
[],
[],
[],
[]
];
var _local6:int;
while (_local6 < (4 * _local3))
_local5[(_local6 % 4)][Math.floor((_local6 / 4))] = _arg1[_local6];
_local6++;
;
_local5 = addRoundKey(_local5, _arg2, 0, _local3);
var _local7 = 1;
while (_local7 < _local4)
_local5 = subBytes(_local5, _local3);
_local5 = shiftRows(_local5, _local3);
_local5 = mixColumns(_local5);
_local5 = addRoundKey(_local5, _arg2, _local7, _local3);
_local7++;
;
_local5 = subBytes(_local5, _local3);
_local5 = shiftRows(_local5, _local3);
_local5 = addRoundKey(_local5, _arg2, _local4, _local3);
var _local8:Array = new Array((4 * _local3));
var _local9:int;
while (_local9 < (4 * _local3))
_local8[_local9] = _local5[(_local9 % 4)][Math.floor((_local9 / 4))];
_local9++;
;
return (_local8);
private static function keyExpansion(_arg1:Array):Array
var _local8:Array;
var _local9:int;
var _local2 = 4;
var _local3:int = (_arg1.length / 4);
var _local4:int = (_local3 + 6);
var _local5:Array = new Array((_local2 * (_local4 + 1)));
var _local6:Array = new Array(4);
var _local7:int;
while (_local7 < _local3)
_local8 = [_arg1[(4 * _local7)], _arg1[((4 * _local7) + 1)], _arg1[((4 * _local7) + 2)], _arg1[((4 * _local7) + 3)]];
_local5[_local7] = _local8;
_local7++;
;
_local7 = _local3;
while (_local7 < (_local2 * (_local4 + 1)))
_local5[_local7] = new Array(4);
_local9 = 0;
while (_local9 < 4)
_local6[_local9] = _local5[(_local7 - 1)][_local9];
_local9++;
;
if ((_local7 % _local3) == 0)
_local6 = subWord(rotWord(_local6));
_local9 = 0;
while (_local9 < 4)
_local6[_local9] = (_local6[_local9] ^ RCON[(_local7 / _local3)][_local9]);
_local9++;
;
else
if ((((_local3 > 6)) && (((_local7 % _local3) == 4))))
_local6 = subWord(_local6);
;
;
_local9 = 0;
while (_local9 < 4)
_local5[_local7][_local9] = (_local5[(_local7 - _local3)][_local9] ^ _local6[_local9]);
_local9++;
;
_local7++;
;
return (_local5);
private static function subBytes(_arg1:Array, _arg2:int):Array
var _local4:int;
var _local3:int;
while (_local3 < 4)
_local4 = 0;
while (_local4 < _arg2)
_arg1[_local3][_local4] = SBOX[_arg1[_local3][_local4]];
_local4++;
;
_local3++;
;
return (_arg1);
private static function shiftRows(_arg1:Array, _arg2:int):Array
var _local5:int;
var _local3:Array = new Array(4);
var _local4 = 1;
while (_local4 < 4)
_local5 = 0;
while (_local5 < 4)
_local3[_local5] = _arg1[_local4][((_local5 + _local4) % _arg2)];
_local5++;
;
_local5 = 0;
while (_local5 < 4)
_arg1[_local4][_local5] = _local3[_local5];
_local5++;
;
_local4++;
;
return (_arg1);
private static function mixColumns(_arg1:Array):Array
var _local3:Array;
var _local4:Array;
var _local5:int;
var _local2:int;
while (_local2 < 4)
_local3 = new Array(4);
_local4 = new Array(4);
_local5 = 0;
while (_local5 < 4)
_local3[_local5] = _arg1[_local5][_local2];
_local4[_local5] = (((_arg1[_local5][_local2] & 128)) ? ((_arg1[_local5][_local2] << 1) ^ 283) : (_arg1[_local5][_local2] << 1));
_local5++;
;
_arg1[0][_local2] = ((((_local4[0] ^ _local3[1]) ^ _local4[1]) ^ _local3[2]) ^ _local3[3]);
_arg1[1][_local2] = ((((_local3[0] ^ _local4[1]) ^ _local3[2]) ^ _local4[2]) ^ _local3[3]);
_arg1[2][_local2] = ((((_local3[0] ^ _local3[1]) ^ _local4[2]) ^ _local3[3]) ^ _local4[3]);
_arg1[3][_local2] = ((((_local3[0] ^ _local4[0]) ^ _local3[1]) ^ _local3[2]) ^ _local4[3]);
_local2++;
;
return (_arg1);
private static function addRoundKey(_arg1:Array, _arg2:Array, _arg3:int, _arg4:int):Array
var _local6:int;
var _local5:int;
while (_local5 < 4)
_local6 = 0;
while (_local6 < _arg4)
_arg1[_local5][_local6] = (_arg1[_local5][_local6] ^ _arg2[((_arg3 * 4) + _local6)][_local5]);
_local6++;
;
_local5++;
;
return (_arg1);
private static function subWord(_arg1:Array):Array
var _local2:int;
while (_local2 < 4)
_arg1[_local2] = SBOX[_arg1[_local2]];
_local2++;
;
return (_arg1);
private static function rotWord(_arg1:Array):Array
var _local2:int = _arg1[0];
var _local3:int;
while (_local3 < 3)
_arg1[_local3] = _arg1[(_local3 + 1)];
_local3++;
;
_arg1[3] = _local2;
return (_arg1);
上面的代码是我在我的应用程序中使用的 Flash 工具的一部分,现在我需要在服务器中复制它来解密一个由这个 AES 算法加密的 URL,它不是密码黑客(谁使用 aes 作为密码和一个已知密钥)也不需要工具,它了解 AES 实现并在 PHP 中重现相同的行为。
我尝试了phpseclib
,但我无法产生与使用 Actionscript 代码相同的输出,我使用了 lib,但我的输出总是不同。按照前面的示例,在 AS 中使用密钥 my great key
加密文本 hello world
我得到 06/0/6Ojo6ObeIEZaHcxAinbjD==
,然后在 PHP 中我尝试类似:
$cipher = new Crypt_AES();
$cipher->setKeyLength(256);
$cipher->setKey('my great key');
echo base64_encode($cipher->encrypt('hello world'));
它会打印出v/Uc20nSNRNnJr0D15wBzA==
。
【问题讨论】:
所以要么这不是主题,因为它要求工具或库,要么它是主题,因为它是关于黑客或密码破解,或两者兼而有之。 【参考方案1】:要解码 base 64,您可以使用 base64_decode 将字符串解码为原始字节。对于解密,这个library (phpseclib) 似乎没问题。他们有关于如何设置所有内容的示例here。它可以选择使用 mcrypt,但如果你没有它就不会。
【讨论】:
以上是关于PHP中的AES解密的主要内容,如果未能解决你的问题,请参考以下文章
从 Java 生成的数据中解密 PHP 中的 AES-128
php中的AES加密,然后用Javascript(cryptojs)解密