2009年5月20日 | 标签:

微型加密算法(TEA)及其相关变种(XTEA,Block TEA,XXTEA) 都是分组加密算法,它们很容易被描述,实现也很简单(典型的几行代码)。

TEA 算法最初是由剑桥计算机实验室的 David Wheeler 和 Roger Needham 在 1994 年设计的。该算法使用 128 位的密钥为 64 位的信息块进行加密,它需要进行 64 轮迭代,尽管作者认为 32 轮已经足够了。该算法使用了一个神秘常数δ作为倍数,它来源于黄金比率,以保证每一轮加密都不相同。但δ的精确值似乎并不重要,这里 TEA 把它定义为 δ=「(√5 - 1)231」(也就是程序中的 0×9E3779B9)。

之后 TEA 算法被发现存在缺陷,作为回应,设计者提出了一个 TEA 的升级版本——XTEA(有时也被称为“tean”)。XTEA 跟 TEA 使用了相同的简单运算,但它采用了截然不同的顺序,为了阻止密钥表攻击,四个子密钥(在加密过程中,原 128 位的密钥被拆分为 4 个 32 位的子密钥)采用了一种不太正规的方式进行混合,但速度更慢了。

在跟描述 XTEA 算法的同一份报告中,还介绍了另外一种被称为 Block TEA 算法的变种,它可以对 32 位大小任意倍数的变量块进行操作。该算法将 XTEA 轮循函数依次应用于块中的每个字,并且将它附加于它的邻字。该操作重复多少轮依赖于块的大小,但至少需要 6 轮。该方法的优势在于它无需操作模式(CBC,OFB,CFB 等),密钥可直接用于信息。对于长的信息它可能比 XTEA 更有效率。

在 1998 年,Markku-Juhani Saarinen 给出了一个可有效攻击 Block TEA 算法的代码,但之后很快 David J. Wheeler 和 Roger M. Needham 就给出了 Block TEA 算法的修订版,这个算法被称为 XXTEA。XXTEA 使用跟 Block TEA 相似的结构,但在处理块中每个字时利用了相邻字。它利用一个更复杂的 MX 函数代替了 XTEA 轮循函数,MX 使用 2 个输入量。

XXTEA 算法很安全,而且非常快速,非常适合应用于 Web 开发中。但目前似乎很少有人将该算法用于实际开发中。甚至国内尚无介绍该算法的文章(至少在 Google 上搜索不到这方面的中文文章,关于密码学算法的书中也未见提及)。我在 Google 上搜索到了几个国外的 XXTEA 算法的实现(见参考文献), 但基本上都是 JavaScript 的,但这些 JavaScript 实现也有一些问题,如果加密字符串长度不是 4 的整数倍,则这些实现的在加密后无法真正还原,还原以后的字符串实际上与原字符串不相等,而是后面多了一些 \0 的字符,或者少了一些 \0 的字符。

原因在于 XXTEA 算法只定义了如何对 32 位的信息块数组(实际上是 32 位无符号整数数组)进行加密,而并没有定义如何来将字符串编码为这种数组。而现有的实现中在将字符串编码为整数数组时,都丢失了字符串长度信息,因此还原 出现了问题。另外单纯的 JavaScript 是没有意义的,因为单纯的客户端加密解密是不能有效保证信息的安全性的。因此我写了这个 JavaScript 和 PHP 实现,这两种实现在字符串编码上采用的算法是一致的,因此 JavaScript 加密的内容可以用 PHP 实现的解密算法进行解密,反之亦然。

注意:如果需要在 JavaScript 中加密解密带有汉字的信息, 在加密时,需要先将带加密信息用 utf16to8 进行转换,解密时,需要将解密后的内容再用 utf8to16 还原。如果要在 PHP 和 JavaScript 之间传递带有汉字的加密信息,原信息需要用 UTF-8 字符集。

2006年12月9日 更新
当解密失败时(如未使用正确的密钥),可以返回 null(JavaScript) 或 flase(PHP)。

2006年7月23日 更新
修正了当密钥不足 16 个字节时无法加密/解密的问题。

2006年6月27日 更新
修正了大多数 Linux 系统上 PHP 浮点数到整数转化不正常引起的加密解密不正确的问题。(十分感谢 lynk 和 lishouming 二位的帮助和测试!)

2006年3月7日 更新
修正了在 64 位机上不能正常工作的问题。(十分感谢 大侠鼎力相助测试!)

JavaScript 版本的演示程序:http://test.coolcode.cn/xxtea/

PHP 实现代码

xxtea.php
<?php
/* XXTEA encryption arithmetic library.
*
* Copyright (C) 2006 Ma Bingyao <andot@ujn.edu.cn>
* Version:      1.5
* LastModified: Dec 5, 2006
* This library is free.  You can redistribute it and/or modify it.
*/
 
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 = 0×9E3779B9;
    $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 & 0×07ffffff) ^ $y << 2) + (($y >> 3 & 0×1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
            $z = $v[$p] = int32($v[$p] + $mx);
        }
        $y = $v[0];
        $mx = int32((($z >> 5 & 0×07ffffff) ^ $y << 2) + (($y >> 3 & 0×1fffffff) ^ $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 = 0×9E3779B9;
    $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 & 0×07ffffff) ^ $y << 2) + (($y >> 3 & 0×1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
            $y = $v[$p] = int32($v[$p] - $mx);
        }
        $z = $v[$n];
        $mx = int32((($z >> 5 & 0×07ffffff) ^ $y << 2) + (($y >> 3 & 0×1fffffff) ^ $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);
}
?>


作者:andot
原文网址:http://www.coolcode.cn/show-128-1.html

PS:
关于这一篇内容,我也会收藏到我自己的博客里面,用andot的话来说,他在不同的系统下面进行测试,xxtea算法的效率是相对挺高的(由于分类的关系,在这里我只显示了PHP相关的代码,JS的代码请到官方网站查看)

2009年4月17日 | 标签:

关于P3P,还是有必要讲一下。好像之前我和朋友讨论网易那个跨域实现的时候忘记讲清楚了,那个P3P头是必须要的,后面的 set-cookie 才能成功。

对于IE来说(默认安全级别下),iframe、img、link等标签都是只发送session cookie(又叫 第一方cookie),拦截本地cookie发送(又叫第三方cookie)。当这些标签跨域引用一个页面,实际上是发起了一次GET请求。

如果这个跨域的请求,HTTP返回头中带有Set-Cookie , 那么这个cookie对浏览器来说,实际上是无效的。

看如下测试

假设有 www.a.com    与 www.b.com 两个域

在 www.b.com 上有一个页面,其中包含一个指向 www.a.com 的iframe

http://www.b.com/test.html 的内容为:
———————————————————————-

<iframe width=300 height=300 src="http://www.a.com/test.php" ></iframe>

———————————————————————-

http://www.a.com/test.php 是一个对 a.com 域设置 cookie的页面,其内容为:
———————————————————————-

<?php

header("Set-Cookie: test=axis; domain=.a.com; path=/");

?>

<script>
    alert(document.cookie);
</script>

———————————————————————-

此时我们请求 http://www.b.com/test.html , 他包含一个iframe,会去跨域请求 www.a.com/test.php ,该php页面会尝试 set-cookie

第一次请求, test.php 会 set-cookie,所以浏览器会收到一个cookie。

如果 set-cookie 成功,再次请求该页面,浏览器应该会 sent 刚才 recieve 到的cookie。可是由于前面说的跨域限制,在IE里的iframe标签是 set-cookie不成功的,所以无法sent刚才收到的cookie。 这里无论是 session cookie 还是本地cookie都是一样。

601bb01a1615ea078618bf09

可以看到,第二次发包,还是没能sent出去cookie

但是这种情况在加入了P3P header 后会改变。

P3P header允许跨域访问隐私数据,从而可以跨域set-cookie成功

我们修改 www.a.com/test.php 为
———————————————————————-

<?php

header("P3P: CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR");

header("Set-Cookie: test=axis; expires=Sun, 23-Dec-2018 08:13:02 GMT; domain=.a.com; path=/");

?>

<script>
    alert(document.cookie);
</script>

———————————————————————-

再次访问两次上面的测试过程

f43d5a83b9fbc2bc0cf4d210

可以看到第二个包已经发送出了收到的cookie

而我们写的javascript也能够弹出cookie了。

值得注意的是,P3P header只需要设置一次,这样跟在这个P3P header后面的所有 set-cookie,都可以跨域访问了。也就是说: 被P3P header设置过一次后,之后的请求不再需要P3P header,也能够在iframe里跨域发送这些cookie。

但是如果用 set-cookie 去改变设置好的cookie,则不再具有这种跨域访问特性。

P3P header 还有一个特点就是同一个包里只能设置一次,后面的P3P Header不会覆盖前面的P3P header,浏览器只认第一个。

P3P 是 The Platform for Privacy Preferences 的简称

更多具体的内容可以参阅W3C的标准 http://www.w3.org/TR/P3P/

在这里,我们看到的很乱的 P3P header里的东西,都不知道是什么乱七八糟的策略内容,实际上这是一些简写

比如 上面用到的

P3P: CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR

CP 是 Compact Policy 的简写

CURa 中 CUR 是 <current/> 的简写, a 是 always 的简写

定义很多,我这里摘部分标准中的内容

[57]
compact-purpose
=
"CUR"        | ; for <current/>
"ADM" [creq] | ; for <admin/>
"DEV" [creq] | ; for <develop/>
"TAI" [creq] | ; for <tailoring/>
"PSA" [creq] | ; for <pseudo-analysis/>
"PSD" [creq] | ; for <pseudo-decision/>
"IVA" [creq] | ; for <individual-analysis/>
"IVD" [creq] | ; for <individual-decision/>
"CON" [creq] | ; for <contact/>
"HIS" [creq] | ; for <historical/>
"TEL" [creq] | ; for <telemarketing/>
"OTP" [creq]   ; for <other-purpose/>
[58]
creq
=
"a"| ;"always"
"i"| ;"opt-in"
"o"  ;"opt-out"

更多的内容可以参考上面提到的标准

当然P3P header也可以直接 引用一个 xml 策略文件

比如这么写

HTTP/1.1 200 OK
P3P: policyref="http://catalog.example.com/P3P/PolicyReferences.xml"
Content-Type: text/html
Content-Length: 7413
Server: CC-Galaxy/1.3.18

使用P3P的方法还有很多,这里不一一列举了。

最后,利用P3P Header 的这种特性,在实际攻击中,还是可以利用一下的。

比如利用CRLF插入一个P3P header后,改变一个本地cookie的值,该cookie在之后的过程中可以被iframe引用到,也许会发生一些很奇妙的事情。

具体会变成什么样我也不知道,毕竟web应用安全和环境的关系是越来越紧密了。

2009年3月22日 | 标签:

e58da1e9809ae7bb93e5a99ae79bb8

2009年3月21日 | 标签:

var type_interval = null;
function type(obj, str, func) { //打字函数,字符串以打字的形式输出。
 if (type_interval)
  clearInterval(type_interval);
 var i_typed = 0;
 var matchs = str.match(/(?:&[0-9A-Za-z]+?;)|(?:<.*?>)/g);
 str = str.replace(/(?:&[0-9A-Za-z]+?;)|(?:<.*?>)/g, "~");
 var str_out = "";
 var m = 0;
 type_interval = setInterval(function() {
  i_typed += 1;
  var tmp = str.charAt(i_typed - 1);
  if (tmp == "~") {
   str_out += matchs[m];
   m += 1;
  }
  else {
   str_out += tmp;
  }
  if (i_typed % 2 == 1)
   obj.innerHTML = str_out + '_';
  else
   obj.innerHTML = str_out;
  if (i_typed == str.length) {
   clearInterval(type_interval);
   type_interval = null;
   obj.innerHTML = str_out;
   try {
    func();
   }
   catch (e) {}
  }
 }
 , 70);
}

2009年3月19日 | 标签:

最后一星期

2009年2月24日 | 标签:

getfacl:取得某个档案/目录的acl设定规范,例:

getfacl filename.txt

 

setfacl:设定某个目录/文档的acl规范,用法与函数:

setfacl [-bdhkn] [-m entries] [-M file] [-x entries] [-X file] [file ...]

其实我还没完全清楚那些参数的意思和怎么用,我就把我会用的写出来了。

setfacl -m u:rain:rwx,g:groupname:r-x filename.txt   #对文件filename.txt 给用户rain赋上“读写执行”权限,给组groupname赋上“读执行”权限。

setfacl -x u:rain:rwx filename.txt   #删除一条ACL记录

setfacl -b filename.txt #清除文件或文件夹的全部ACL记录

setfacl -dm u:rain:rwx,g::r-x,o::r dirname #设置文件夹的默认ACL

setfacl -k dirname #删除文件夹的默认ACL

2009年2月24日 | 标签:

function getEvent() {
 if (window.event)
  return window.event;
 
 c = getEvent.caller;
 while (c != null) {
  if (c.arguments[0].toString().indexOf("Event") != -1)
   return c.arguments[0];
  c = c.caller;
 }
 return null;
}

2009年1月18日 | 标签:

php_memcache224这个是2.2.4版,稳定一点

php_memcache302这个是3.0.2版,目前最新版,但是测试版

2009年1月11日 | 标签:

    之前试过参与团队开发,由于每个人的想法、做事(主要是写程序)风格都不一样,在多地方要求统一,就会给团队的队员带来很多的协调和牵制问题。虽然把代码写成统一,给人感觉有条有绪,但可读性其实是比较差的,非作者本人去看,很可能要花好多时间。
    少用统一的东西,就可以避免过多的协调和牵制。

2009年1月9日 | 标签:

凡是一笔写成的字,五笔输入法规则是: 
点名+第一笔画字根+L+L 
点名是指敲字根所在键。 
“乙”的字根是折,字根键是——N 
“乙”的第一笔画也是折,字根键当然也是——N 
所以“乙”的五笔编辑是——NNLL。 
试试: 
一 
丨 
丿