自己写的一个简单的可逆加密算法
时间:2007-09-26
来源:互联网
开始打算使用比较经典的AzDGCrypt可逆加密算法,发现在flash使用的时候有个问题,在php中两个相同的值异或之后结果是0,保存到字符串的时候就是chr(0),这个时候这个字符是存在的,长度也为1,而在flash两个相同的值异或之后就彻底消失了,导致解密之后结果不对。无奈之下只好自己写了一个可逆的算法,没有使用异或的。大家帮忙看看这个算法安全性高不高,也就是说在知道算法但不知道key的情况下能否破解?
/*
* 加密,可逆
* 可接受任何字符
* 安全度非常高
*/
function encrypt($txt, $key = 'anihc ctI')
{
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
$ikey ="-x6g6ZWm2G9g_vr0Bo.pOq3kRIxsZ6rm";
$nh1 = rand(0,64);
$nh2 = rand(0,64);
$nh3 = rand(0,64);
$ch1 = $chars{$nh1};
$ch2 = $chars{$nh2};
$ch3 = $chars{$nh3};
$nhnum = $nh1 + $nh2 + $nh3;
$knum = 0;$i = 0;
while(isset($key{$i})) $knum +=ord($key{$i++});
$mdKey = substr(md5(md5(md5($key.$ch1).$ch2.$ikey).$ch3),$nhnum%8,$knum%8 + 16);
$txt = base64_encode($txt);
$txt = str_replace(array('+','/','='),array('-','_','.'),$txt);
$tmp = '';
$j=0;$k = 0;
$tlen = strlen($txt);
$klen = strlen($mdKey);
for ($i=0; $i<$tlen; $i++) {
$k = $k == $klen ? 0 : $k;
$j = ($nhnum+strpos($chars,$txt{$i})+ord($mdKey{$k++}))%64;
$tmp .= $chars{$j};
}
$tmplen = strlen($tmp);
$tmp = substr_replace($tmp,$ch3,$nh2 % ++$tmplen,0);
$tmp = substr_replace($tmp,$ch2,$nh1 % ++$tmplen,0);
$tmp = substr_replace($tmp,$ch1,$knum % ++$tmplen,0);
return $tmp;
}
/*
* 解密
*
*/
function decrypt($txt, $key = 'anihc ctI')
{
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
$ikey ="-x6g6ZWm2G9g_vr0Bo.pOq3kRIxsZ6rm";
$knum = 0;$i = 0;
$tlen = strlen($txt);
while(isset($key{$i})) $knum +=ord($key{$i++});
$ch1 = $txt{$knum % $tlen};
$nh1 = strpos($chars,$ch1);
$txt = substr_replace($txt,'',$knum % $tlen--,1);
$ch2 = $txt{$nh1 % $tlen};
$nh2 = strpos($chars,$ch2);
$txt = substr_replace($txt,'',$nh1 % $tlen--,1);
$ch3 = $txt{$nh2 % $tlen};
$nh3 = strpos($chars,$ch3);
$txt = substr_replace($txt,'',$nh2 % $tlen--,1);
$nhnum = $nh1 + $nh2 + $nh3;
$mdKey = substr(md5(md5(md5($key.$ch1).$ch2.$ikey).$ch3),$nhnum % 8,$knum % 8 + 16);
$tmp = '';
$j=0; $k = 0;
$tlen = strlen($txt);
$klen = strlen($mdKey);
for ($i=0; $i<$tlen; $i++) {
$k = $k == $klen ? 0 : $k;
$j = strpos($chars,$txt{$i})-$nhnum - ord($mdKey{$k++});
while ($j<0) $j+=64;
$tmp .= $chars{$j};
}
$tmp = str_replace(array('-','_','.'),array('+','/','='),$tmp);
return base64_decode($tmp);
}
//谢谢achun.shx 指正错误,已经做了修改
[ 本帖最后由 sentrychen 于 2008-9-27 16:46 编辑 ]
作者: sentrychen 发布时间: 2007-09-26
强顶一下表示支持!
作者: londit.cn 发布时间: 2007-09-26
作者: londit.cn 发布时间: 2007-09-26
[php]
/**
* Passport 加密函数
*
* @param string 等待加密的原字串
* @param string 私有密匙(用于解密和加密)
*
* @return string 原字串经过私有密匙加密后的结果
*/
function passport_encrypt($txt, $key) {
// 使用随机数发生器产生 0~32000 的值并 MD5()
srand((double)microtime() * 1000000);
$encrypt_key = md5(rand(0, 32000));
// 变量初始化
$ctr = 0;
$tmp = '';
// for 循环,$i 为从 0 开始,到小于 $txt 字串长度的整数
for($i = 0; $i < strlen($txt); $i++) {
// 如果 $ctr = $encrypt_key 的长度,则 $ctr 清零
$ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;
// $tmp 字串在末尾增加两位,其第一位内容为 $encrypt_key 的第 $ctr 位,
// 第二位内容为 $txt 的第 $i 位与 $encrypt_key 的 $ctr 位取异或。然后 $ctr = $ctr + 1
$tmp .= $encrypt_key[$ctr].($txt[$i] ^ $encrypt_key[$ctr++]);
}
// 返回结果,结果为 passport_key() 函数返回值的 base65 编码结果
return base64_encode(passport_key($tmp, $key));
}
/**
* Passport 解密函数
*
* @param string 加密后的字串
* @param string 私有密匙(用于解密和加密)
*
* @return string 字串经过私有密匙解密后的结果
*/
function passport_decrypt($txt, $key) {
// $txt 的结果为加密后的字串经过 base64 解码,然后与私有密匙一起,
// 经过 passport_key() 函数处理后的返回值
$txt = passport_key(base64_decode($txt), $key);
// 变量初始化
$tmp = '';
// for 循环,$i 为从 0 开始,到小于 $txt 字串长度的整数
for ($i = 0; $i < strlen($txt); $i++) {
// $tmp 字串在末尾增加一位,其内容为 $txt 的第 $i 位,
// 与 $txt 的第 $i + 1 位取异或。然后 $i = $i + 1
$tmp .= $txt[$i] ^ $txt[++$i];
}
// 返回 $tmp 的值作为结果
return $tmp;
}
/**
* Passport 密匙处理函数
*
* @param string 待加密或待解密的字串
* @param string 私有密匙(用于解密和加密)
*
* @return string 处理后的密匙
*/
function passport_key($txt, $encrypt_key) {
// 将 $encrypt_key 赋为 $encrypt_key 经 md5() 后的值
$encrypt_key = md5($encrypt_key);
// 变量初始化
$ctr = 0;
$tmp = '';
// for 循环,$i 为从 0 开始,到小于 $txt 字串长度的整数
for($i = 0; $i < strlen($txt); $i++) {
// 如果 $ctr = $encrypt_key 的长度,则 $ctr 清零
$ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;
// $tmp 字串在末尾增加一位,其内容为 $txt 的第 $i 位,
// 与 $encrypt_key 的第 $ctr + 1 位取异或。然后 $ctr = $ctr + 1
$tmp .= $txt[$i] ^ $encrypt_key[$ctr++];
}
// 返回 $tmp 的值作为结果
return $tmp;
}
[/php]
在对一个长度为12980字节的字符串中,
我的算法加密和解密一共用了1.1882820129395秒
AzDGCrypt用了1.6753888130188秒
作者: sentrychen 发布时间: 2007-09-26
建议有时间多看看关于 RSA DES等算法.
呵呵。。还没看过,反正我只要求无法破解就行了。
作者: sentrychen 发布时间: 2007-09-26
作者: sentrychen 发布时间: 2007-09-26
lz的那个算法的强度至少比AzDGCrypt好多了。
作者: 神仙 发布时间: 2007-09-26
作者: szy_session1987 发布时间: 2007-09-26
作者: leehui1983 发布时间: 2007-09-26
去网上搜一个叫 PHPRPC 的东东. 可以拿来学习学习
里面也有一个可逆的加密算法,发出来给大家研究。
[php]
function long2str($v, $w) {
$len = count($v);
$n = ($len - 1) << 2;
if ($w) {
$m = $v[$len - 1];
if (($m < $n - 3) || ($m > $n)) return false;
$n = $m;
}
$s = array();
for ($i = 0; $i < $len; $i++) {
$s[$i] = pack("V", $v[$i]);
}
if ($w) {
return substr(join('', $s), 0, $n);
}
else {
return join('', $s);
}
}
function str2long($s, $w) {
$v = unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4) & 3));
$v = array_values($v);
if ($w) {
$v[count($v)] = strlen($s);
}
return $v;
}
function int32($n) {
while ($n >= 2147483648) $n -= 4294967296;
while ($n <= -2147483649) $n += 4294967296;
return (int)$n;
}
function xxtea_encrypt($str, $key) {
if ($str == "") {
return "";
}
$v = str2long($str, true);
$k = str2long($key, false);
if (count($k) < 4) {
for ($i = count($k); $i < 4; $i++) {
$k[$i] = 0;
}
}
$n = count($v) - 1;
$z = $v[$n];
$y = $v[0];
$delta = 0x9E3779B9;
$q = floor(6 + 52 / ($n + 1));
$sum = 0;
while (0 < $q--) {
$sum = int32($sum + $delta);
$e = $sum >> 2 & 3;
for ($p = 0; $p < $n; $p++) {
$y = $v[$p + 1];
$mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$z = $v[$p] = int32($v[$p] + $mx);
}
$y = $v[0];
$mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$z = $v[$n] = int32($v[$n] + $mx);
}
return long2str($v, false);
}
function xxtea_decrypt($str, $key) {
if ($str == "") {
return "";
}
$v = str2long($str, false);
$k = str2long($key, false);
if (count($k) < 4) {
for ($i = count($k); $i < 4; $i++) {
$k[$i] = 0;
}
}
$n = count($v) - 1;
$z = $v[$n];
$y = $v[0];
$delta = 0x9E3779B9;
$q = floor(6 + 52 / ($n + 1));
$sum = int32($q * $delta);
while ($sum != 0) {
$e = $sum >> 2 & 3;
for ($p = $n; $p > 0; $p--) {
$z = $v[$p - 1];
$mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$y = $v[$p] = int32($v[$p] - $mx);
}
$z = $v[$n];
$mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$y = $v[0] = int32($v[0] - $mx);
$sum = int32($sum - $delta);
}
return long2str($v, true);
}
[/php]
呵呵,这是xxtea的可逆加密算法,代码比较复杂,看起来头痛。我用一个字节数为2万的字符串测试了一下,还是我写的算法速度快。
//测试结果
加密字符串字节数:20000
ntk算法加密后字符串长度:26669 加密所用时间:1.2221281528473 秒
解密所用时间:1.4950909614563 秒合计:2.7172191143036 秒
xxtea算法加密后字符串长度:20004 加密所用时间:4.4340929985046 秒
解密所用时间:4.4368131160736 秒合计:8.8709061145782 秒
作者: sentrychen 发布时间: 2007-09-26
作者: dx_andy 发布时间: 2007-09-27
[php]
$i=0;$j=0;$k = 0;
for ($i=0; $i<strlen($txt); $i++) {
$k = $k == strlen($mdKey) ? 0 : $k;
$j = ($nh+strpos($chars,$txt[$i])+ord($mdKey[$k]))%64;
$tmp .= $chars[$j];
}
[/php]
那岂不是$k永远都是0,等价于
[php]
$i=0;$j=0;
for ($i=0; $i<strlen($txt); $i++) {
$j = ($nh+strpos($chars,$txt[$i])+ord($mdKey[0]))%64;
$tmp .= $chars[$j];
}
[/php]
我不熟悉加密,不过凭感觉
这个强度就不怎么样了吧!
作者: achun.shx 发布时间: 2007-09-27
对加密没有研究,不过看了你的代码
[php]
$i=0;$j=0;$k = 0;
for ($i=0; $i
呵呵,谢谢指正bug,我没有仔细检查代码,正确的应该是
$mdKey[$k++]的,再次谢谢
作者: sentrychen 发布时间: 2007-09-27
作者: l80d 发布时间: 2007-09-27
呵呵,这是xxtea的可逆加密算法,代码比较复杂,看起来头痛。我用一个字节数为2万的字符串测试了一下,还是我写的算法速度快。
//测试结果
加密字符串字节数:20000
ntk算法加密后字符串长度:26669 加密所用时间:1.2221281528473 秒
解密所用时间:1.4950909614563 秒合计:2.7172191143036 秒
xxtea算法加密后字符串长度:20004 加密所用时间:4.4340929985046 秒
解密所用时间:4.4368131160736 秒合计:8.8709061145782 秒
...
xxtea 有个 for PHP 的 PECL(c语言的实现)扩展,速度比用纯 PHP 的实现快的多得多,纯 PHP 实现速度慢的原因是 PHP 没有无符号整形数,所以,需要对数字进行校正,这个运算消耗了大部分的时间,其它语言没有这个问题。所以,PHP 如果用 xxtea 算法,最好是使用它的 PECL 扩展,而不是它的纯 PHP 实现。
作者: andot 发布时间: 2007-10-26
作者: ajaxer 发布时间: 2008-08-25
作者: kindge 发布时间: 2008-08-25
我忘记在哪里看过一篇文章,说加密和解密的时间随机数有很大的关系,楼主的$nh = rand(0,64);是0-64之间,而AzDGCrypt的算法$encrypt_key = md5(rand(0, 32000));在0-32000之间,肯定楼主的快咯=。= tukiz29 ,个人见 ...
呵呵,这个是之前写的,现在我已经修改了。对于每一个加密的字符串,能生成26万多种不同的加密结果,并且每一种结果都能解密回来,效率也高了很多。加密一个2万长度的字符串和解密加起来只需要0.3秒左右。修改后的算法还使得字符可以安全用于url传输,不用考虑urlencode的问题。
呵呵,对于这次修改后的算法,我可以毫不夸张的说,即使是世界上技术最好的高手在不知道key的情况下也无法破解我的加密算法。当然如果知道了key,就直接用我的函数就能解密了。
/*
* 加密,可逆
* 可接受任何字符
* 安全度非常高
*/
function encrypt($txt, $key = 'anihc ctI')
{
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
$ikey ="-x6g6ZWm2G9g_vr0Bo.pOq3kRIxsZ6rm";
$nh1 = rand(0,64);
$nh2 = rand(0,64);
$nh3 = rand(0,64);
$ch1 = $chars{$nh1};
$ch2 = $chars{$nh2};
$ch3 = $chars{$nh3};
$nhnum = $nh1 + $nh2 + $nh3;
$knum = 0;$i = 0;
while(isset($key{$i})) $knum +=ord($key{$i++});
$mdKey = substr(md5(md5(md5($key.$ch1).$ch2.$ikey).$ch3),$nhnum%8,$knum%8 + 16);
$txt = base64_encode($txt);
$txt = str_replace(array('+','/','='),array('-','_','.'),$txt);
$tmp = '';
$j=0;$k = 0;
$tlen = strlen($txt);
$klen = strlen($mdKey);
for ($i=0; $i<$tlen; $i++) {
$k = $k == $klen ? 0 : $k;
$j = ($nhnum+strpos($chars,$txt{$i})+ord($mdKey{$k++}))%64;
$tmp .= $chars{$j};
}
$tmplen = strlen($tmp);
$tmp = substr_replace($tmp,$ch3,$nh2 % ++$tmplen,0);
$tmp = substr_replace($tmp,$ch2,$nh1 % ++$tmplen,0);
$tmp = substr_replace($tmp,$ch1,$knum % ++$tmplen,0);
return $tmp;
}
/*
* 解密
*
*/
function decrypt($txt, $key = 'anihc ctI')
{
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.";
$ikey ="-x6g6ZWm2G9g_vr0Bo.pOq3kRIxsZ6rm";
$knum = 0;$i = 0;
$tlen = strlen($txt);
while(isset($key{$i})) $knum +=ord($key{$i++});
$ch1 = $txt{$knum % $tlen};
$nh1 = strpos($chars,$ch1);
$txt = substr_replace($txt,'',$knum % $tlen--,1);
$ch2 = $txt{$nh1 % $tlen};
$nh2 = strpos($chars,$ch2);
$txt = substr_replace($txt,'',$nh1 % $tlen--,1);
$ch3 = $txt{$nh2 % $tlen};
$nh3 = strpos($chars,$ch3);
$txt = substr_replace($txt,'',$nh2 % $tlen--,1);
$nhnum = $nh1 + $nh2 + $nh3;
$mdKey = substr(md5(md5(md5($key.$ch1).$ch2.$ikey).$ch3),$nhnum % 8,$knum % 8 + 16);
$tmp = '';
$j=0; $k = 0;
$tlen = strlen($txt);
$klen = strlen($mdKey);
for ($i=0; $i<$tlen; $i++) {
$k = $k == $klen ? 0 : $k;
$j = strpos($chars,$txt{$i})-$nhnum - ord($mdKey{$k++});
while ($j<0) $j+=64;
$tmp .= $chars{$j};
}
$tmp = str_replace(array('-','_','.'),array('+','/','='),$tmp);
return trim(base64_decode($tmp));
}
[ 本帖最后由 sentrychen 于 2008-8-30 17:46 编辑 ]
作者: sentrychen 发布时间: 2008-08-30
作者: sentrychen 发布时间: 2008-08-30
作者: fatpotato 发布时间: 2008-08-30
作者: renlang119 发布时间: 2008-09-20
奇了怪了!
作者: fly1983 发布时间: 2008-09-27
作者: fatpotato 发布时间: 2008-09-27
咋看不到源代码呢?
奇了怪了!
奇怪,我也看不到
作者: sentrychen 发布时间: 2008-09-27
纯顶。
作者: imkow 发布时间: 2008-09-27
作者: imkow 发布时间: 2008-09-27
请楼主谈谈自己的算法相对与其他算法的优势?夸一夸宝!
夸耀就没有必要了,其实我对加密没有什么研究,也没看过什么加密理论,因此不敢在众多安全专家面前班门弄斧。我还是简单说说这个算法的原理吧,真的很简单,完全是md5的功劳。
首先,我根据公key、私key和一个rand(64×64×64)的随机数,利用md5函数制造了一个字符串序列。
然后将要加密的字符串转为base64编码。
再根据这个字符串序列的字符位置对base64编码后的字符串进行逐个字符替换。
最后根据公key的字符ascii码之和将几个随机因子插入到替换后的字符串里面。
解密就是倒过来运算。
如果说这个算法的一点优势,那就是速度比AzDGCrypt和xxtea的算法快,然后加密后的字符长度相当于AzDGCrypt的1/2,但比xxtea的长了大概1/4。另外加密后的字符串在url里面传送很稳定,不会被转义。安全性方面就很难比较了,我设置了一个公key(在函数调用传入),一个私key,直接写在函数里面。如果不知道这两个key还是很难破解的。
作者: sentrychen 发布时间: 2008-09-27
初学PHP,代码不懂
加密那里好像有点问题,多刷新几次,有时会有运行错误,加密中文时好像多点
作者: snxu 发布时间: 2008-11-26
作者: liexusong 发布时间: 2008-11-26
作者: xudongding 发布时间: 2008-12-11
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28