Skip to content

Instantly share code, notes, and snippets.

@shonenada
Created August 30, 2014 03:40
Show Gist options
  • Save shonenada/336a8054da7a95457cc7 to your computer and use it in GitHub Desktop.
Save shonenada/336a8054da7a95457cc7 to your computer and use it in GitHub Desktop.
<?php
DEFAULT_KEY = 'abcdefgh';
// $string 明文 或 密文
// $operation: decode =》 解密,其他是加密
// $key: 秘钥
// $expiry: 有效期
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
// 动态密钥长度,相同的明文会生成不同密文就是艺考动态密钥 (初始化向量 IV)
$ckey_length = 4;
// 随机密钥长度取值 0 ~ 32
// 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,
// 增大破解难度(实际上就是 IV)
// 取值越大,密文变动规律越大,密文变化 = 16 的 $ckey_length 次方
// 此值为 0 的时候,则不产生随机秘钥
$key = md5($key ? $key : DEFAULT_KEY);
// 参与加密、解密
$keya = md5(substr($key, 0, 16));
// 做数据完整性验证
$keyb = md5(substr($key, 16, 16));
// 用于变化生成的密文 初始化向量 IV
$keyc = $ckey_length ?
($operation == 'DECODE' ?
substr($string, 0, $ckey_length) :
substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya . md5($keya . $keyc);
$key_length = $strlen($cryptkey);
// 明文,前 10 位用来保存时间戳,解密时验证数据有效性, 10 到 26 位用来保存 $keyb
// 解密时会通过这个密钥验证数据完整性
// 如果是解码的话,会从第 $ckey_length 为开始,因为密文前 $ckey_length 位保存动态密钥
// 以保证解密正确。
$string = $opertaion == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
// 产生密钥簿
for ($i=0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
// 用固定算法打乱密钥簿,增加随机性,实际上不会增加密文强度.
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
// 核心加密、解密部分
for ($a = $i = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$j] = $tmp;
// 从密钥簿得出密钥进行亦或,再转成字符
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if ($operation == 'DECODE') {
if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) &&
substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
// 把动态密钥保存在密文里,这也是为什么同样的明文,产生不同密文后能解密的原因
// 因为加密后的密文可能是 一些特殊字符,复制过程可能是会丢失所以用 base64 编码
return $keyc . str_replace('=', '', base64_encode($result));
}
}
<?php
require 'authcode.php';
$plaintext_1 = 'aaaabbbb';
$plaintext_2 = 'ccccdddd';
echo "plaintext_1 is: " . $plaintext_1 . "<br />";
echo "plaintext_2 is: " . $plaintext_2 . "<br />";
$cipher_1 = base64_decode(substr(authcode($plaintext_1, "ENCODE", DEFAULT_KEY), 0));
echo "Cipher_1 is: " . hex($cipher_1) . "<br /><br />";
$cipher_2 = base64_decode(substr(authcode($plaintext_2), "ENCODE", DEFAULT_KEY), 0));
echo "Cipher_2 is:" . hex($cipher_2) . "<br /><br />";
function hex($str) {
$result = '';
for ($i = 0;$i<strlen($str);$i++) {
$result .= "\\x" . ord($str[$i]);
}
}
echo "crack result is: " . crack($plaintext_1, $cipher_1, $cipher_2);
function crack($plain, $cipher_p, $cipher_t) {
$target = '';
$len = strlen($plain);
$tmp_p = substr($cipher_p, 26);
echo hex($tmp_p) . "<br />";
$tmp_t = substr($cipher_t, 26);
echo hex($tmp_t) . "<br />";
for ($i=0; $i < strlen($plain); $i++) {
$target .= chr(ord($plain[$i]) ^ ord($tmp_p[$i]) ^ ord($tmp_p[$i]));
}
return $target;
}
<?php
require 'authcode.php';
$plaintext_1 = 'aaaabbbb';
$plaintext_2 = 'ccccdddd';
$guess_result = '';
$time_start = time();
$dict = array();
global $ckey_length;
$ckey_length = 4;
echo "Collecting Dictionar (XOR Keys). \n";
$cipher2 = authcode($plaintext_2, 'ENCODE', DEFAULT_KEY);
$counter = 0;
for (;;) {
$counter ++;
$cipher1 = authcode($plaintext1, 'ENCODE', DEFAULT_KEY);
$keyc1 = substr($cipher1, 0, $ckey_length);
$cipher1 = base64_decode(substr($cipher1, $ckey_length));
$dict[$keyc1] = $cipher1;
if ($counter % 1000 == 0) {
echo ".";
if ($guess_result = guess($dict, $cipher)) {
break;
}
}
}
array_unique($dict);
echo "\nDictionary Collecting Finished..\n";
echo "Collected " . count($dict) . " XOR Keys\n";
function guess($dict, $cipher2) {
global $plaintext1, $ckey_length;
$keyc2 = substr($cipher2, 0, $ckey_length);
$cipher2 = base64_decode(substr($cipher2, $ckey_length));
for($i=0;$i<count($dict); $i++) {
if (array_key_exists($keyc2, $dict)) {
echo "\nFound key in dictionary!\n";
echo "keyc is :" . $keyc2 . "\n";
return crack($plaintext1, $dict[$keyc2], $cipher2);
break;
}
}
return False;
}
echo "\ncounter is " . $counter . "\n";
$time_spend = time() - $time_start;
echo "crack time is : " . $time_speed . "seconds \n";
echo "crack result is: " . $guess_result . "\n";
function crack($plain, $cipher_p, $cipher_t) {
$target = '';
$tmp_p = substr($cipher_p, 26);
$tmp_t = substr($cipher_t, 26);
for ($i=0;$i<strlen($plain);$i++) {
$target .= chr(ord($pliain[$i]) ^ ord($tmp_p[$i]) ^ ord($tmp_t[$i]));
}
return $target;
}
function hex($str) {
$result = '';
for ($i=0;$i<strlen($str);$i++) {
$result .= "\\x" . ord($str[$i]);
}
return $result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment