缘起
由于需要,引入了rc4加密算法,网上搜到了一些PHP实现,Java实现,当然,对于PHP来讲,还有openssl的实现。
网址: http://zhiwei.li/text/2011/08/7777777777777777777/
上还证明了PHP的实现和openssl的实现是相同的,由于该网址有测试例子,自己执行一边,果然如该网址所言。
由于存在java实现的需要 ,于是就测试一下,java实现和PHP实现是否相同,由于PHP的实现和openssl的实现相同,于是只比较了openssl 和java的解密结果,果然不让人省心,结果是:不同!
开始折腾
好在rc4的算法比较简单,怀疑可能是网上找到的java版本实现有问题,参考PHP的实现,自己实现了一遍java版本,结果让人纠结,自己实现的和网上找到的结果完全一样,问题在哪里?
当我再次比较openssl和php的加密结果时:发现加密结果100%不同。事情进展到这个地步,更显扑朔迷离,怀疑自己原来测试的有问题,再次测试N边,依然没有问题,其不叫人发疯。
最后,再拿出 http://zhiwei.li/text/2011/08/7777777777777777777/ 来研究;发现里面的key是md5一个密钥字符串后再pack得到的,这个也有关系?试试吧,果然有关系。至此,想起来自己两次测试使用的key是不同的,成功的那次测试,key刚好也是16字节的,而失败的那次测试的key是“testkey”,才想起来,openssl在做加密时,如果key不够长(16字节),则会在后面补 “\0″(是零,不是圈儿),但是自己实现的RC4算法,是没有在key后面补 “\0” 的。
真相大白。
郁闷啊
附测试脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
<?php function RC4($key, $pt) { $s = array(); for ($i=0; $i<256; $i++) { $s[$i] = $i; } $j = 0; $key_len = strlen($key); for ($i=0; $i<256; $i++) { $j = ($j + $s[$i] + ord($key[$i % $key_len])) % 256; //swap $x = $s[$i]; $s[$i] = $s[$j]; $s[$j] = $x; } $i = 0; $j = 0; $ct = ''; $data_len = strlen($pt); for ($y=0; $y< $data_len; $y++) { $i = ($i + 1) % 256; $j = ($j + $s[$i]) % 256; //swap $x = $s[$i]; $s[$i] = $s[$j]; $s[$j] = $x; $ct .= $pt[$y] ^ chr($s[($s[$i] + $s[$j]) % 256]); } return $ct; } $text = 'This is a test string.'; $md5 = md5('password'); echo $md5 . "\n"; $key = pack('H*', $md5); //嫌的话,让 $key = 'testkey'; 试试 print bin2hex(RC4($key, $text)); echo "\n"; echo bin2hex(openssl_encrypt($text, "RC4", $key, true)); echo "\n"; |