我需要在PHP中与使用ISAAC stream cipher的客户端进行通信。据我所知,没有一个可用于PHP的加密库实现了这个密码。如何在PHP应用程序中实现ISAAC密码?
(我已经找到了一个ISAAC的Java实现,并且几乎成功地将它移植到了PHP。唯一的问题是PHP中的无符号右移。我写了一个方法来实现它,但是当数字在转变是负面的。)
答案 0 :(得分:19)
ISAAC cipher非常简单,因为它是用C语言编写的,所以将它移植到PHP应该不会太难。唯一真正的复杂问题是ISAAC使用带有环绕的32位无符号整数,而PHP的整数可能是32位或64位,并在溢出时自动转换为浮点数。然而,这不是一个大问题,因为我们可以通过在需要强制中间值低至32位的位置应用位掩码来轻松解决这个问题。
无论如何,这是PHP的ISAAC参考代码的相当直接的端口:
截至2017年9月,此代码现在也是available on GitHub。
<?php
/*
------------------------------------------------------------------------------
ISAAC random number generator by Bob Jenkins. PHP port by Ilmari Karonen.
Based on the randport.c and readable.c reference C implementations by Bob
Jenkins, with some inspiration taken from the Perl port by John L. Allen.
This code is released into the public domain. Do whatever you want with it.
HISTORY:
2013-01-20: Initial version. (Typo in version date fixed on 2017-09-19.)
------------------------------------------------------------------------------
*/
class ISAAC {
private $m, $a, $b, $c; // internal state
public $r; // current chunk of results
public function isaac()
{
$c = ++$this->c; // c gets incremented once per 256 results
$b = $this->b += $c; // then combined with b
$a = $this->a;
$m =& $this->m;
$r = array();
for ($i = 0; $i < 256; ++$i) {
$x = $m[$i];
switch ($i & 3) {
case 0: $a ^= ($a << 13); break;
case 1: $a ^= ($a >> 6) & 0x03ffffff; break;
case 2: $a ^= ($a << 2); break;
case 3: $a ^= ($a >> 16) & 0x0000ffff; break;
}
$a += $m[$i ^ 128]; $a &= 0xffffffff;
$m[$i] = $y = ($m[($x >> 2) & 255] + $a + $b) & 0xffffffff;
$r[$i] = $b = ($m[($y >> 10) & 255] + $x) & 0xffffffff;
}
$this->a = $a;
$this->b = $b;
$this->c = $c;
$this->r = $r;
}
public function rand()
{
if (empty($this->r)) $this->isaac();
return array_pop($this->r);
}
private static function mix( &$a, &$b, &$c, &$d, &$e, &$f, &$g, &$h )
{
$a ^= ($b << 11); $d += $a; $b += $c;
$b ^= ($c >> 2) & 0x3fffffff; $e += $b; $c += $d;
$c ^= ($d << 8); $f += $c; $d += $e;
$d ^= ($e >> 16) & 0x0000ffff; $g += $d; $e += $f;
$e ^= ($f << 10); $h += $e; $f += $g;
$f ^= ($g >> 4) & 0x0fffffff; $a += $f; $g += $h;
$g ^= ($h << 8); $b += $g; $h += $a;
$h ^= ($a >> 9) & 0x007fffff; $c += $h; $a += $b;
// 64-bit PHP does something weird on integer overflow; avoid it
$a &= 0xffffffff; $b &= 0xffffffff; $c &= 0xffffffff; $d &= 0xffffffff;
$e &= 0xffffffff; $f &= 0xffffffff; $g &= 0xffffffff; $h &= 0xffffffff;
}
public function __construct ( $seed = null )
{
$this->a = $this->b = $this->c = 0;
$this->m = array_fill(0, 256, 0);
$m =& $this->m;
$a = $b = $c = $d = $e = $f = $g = $h = 0x9e3779b9; // golden ratio
for ($i = 0; $i < 4; ++$i) {
ISAAC::mix($a, $b, $c, $d, $e, $f, $g, $h); // scramble it
}
if ( isset($seed) ) {
if ( is_string($seed) ) {
// emulate casting char* to int* on a little-endian CPU
$seed = array_values(unpack("V256", pack("a1024", $seed)));
}
// initialize using the contents of $seed as the seed
for ($i = 0; $i < 256; $i += 8) {
$a += $seed[$i ]; $b += $seed[$i+1];
$c += $seed[$i+2]; $d += $seed[$i+3];
$e += $seed[$i+4]; $f += $seed[$i+5];
$g += $seed[$i+6]; $h += $seed[$i+7];
ISAAC::mix($a, $b, $c, $d, $e, $f, $g, $h);
$m[$i ] = $a; $m[$i+1] = $b; $m[$i+2] = $c; $m[$i+3] = $d;
$m[$i+4] = $e; $m[$i+5] = $f; $m[$i+6] = $g; $m[$i+7] = $h;
}
// do a second pass to make all of the seed affect all of $m
for ($i = 0; $i < 256; $i += 8) {
$a += $m[$i ]; $b += $m[$i+1]; $c += $m[$i+2]; $d += $m[$i+3];
$e += $m[$i+4]; $f += $m[$i+5]; $g += $m[$i+6]; $h += $m[$i+7];
ISAAC::mix($a, $b, $c, $d, $e, $f, $g, $h);
$m[$i ] = $a; $m[$i+1] = $b; $m[$i+2] = $c; $m[$i+3] = $d;
$m[$i+4] = $e; $m[$i+5] = $f; $m[$i+6] = $g; $m[$i+7] = $h;
}
}
else {
// fill in $m with messy stuff (does anyone really use this?)
for ($i = 0; $i < 256; $i += 8) {
ISAAC::mix($a, $b, $c, $d, $e, $f, $g, $h);
$m[$i ] = $a; $m[$i+1] = $b; $m[$i+2] = $c; $m[$i+3] = $d;
$m[$i+4] = $e; $m[$i+5] = $f; $m[$i+6] = $g; $m[$i+7] = $h;
}
}
// fill in the first set of results
$this->isaac();
}
}
ISAAC
类构造函数采用可选的$seed
参数,该参数应该是32位整数的256元素数组,最多1024字节的字符串(转换为数组)使用unpack()
;请参阅代码)或null
(默认值)。如果种子为null或省略,则使用较短的单遍初始化,这对应于在C参考实现中使用randinit()
调用flag == FALSE
;否则,使用对应于flag == TRUE
的两遍初始化。
该类提供了一个rand()
方法,它返回一个32位数字,就像Jenkins'rand.h
中定义的rand()
宏一样。或者,我已将核心isaac()
方法及其内部结果缓冲区$r
保留为公共,因此那些更喜欢更直接访问生成器的人可以自己调用isaac()
并获取输出办法。请注意,构造函数已经调用isaac()
一次,就像参考实现中的randinit()
一样,因此您只需要在耗尽前256个输出值后再次调用它。
这是两个测试程序,第一个对应于rand.c中包含的测试代码:
<?php
require_once('isaac.php');
$seed = array_fill(0, 256, 0);
$isaac = new ISAAC ( $seed );
for ($i = 0; $i < 2; ++$i) {
$isaac->isaac(); // XXX: the first output block is dropped!
for ($j = 0; $j < 256; ++$j) {
printf("%08x", $isaac->r[$j]);
if (($j & 7) == 7) echo "\n";
}
}
以及randtest.c中的第二个ISAAC challenge:
<?php
require_once('isaac.php');
$seed = "This is <i>not</i> the right mytext.";
$isaac = new ISAAC ( $seed );
for ($j = 0; $j < 10 * 256; ++$j) {
printf("%08x ", $isaac->rand());
if (($j & 7) == 7) echo "\n";
}
这些计划的输出应分别与randvect.txt和randseed.txt匹配。
答案 1 :(得分:0)
AFAIK在PHP中没有公开实施ISAAC。它不是那么受欢迎,因此你无法在PHP中找到现成的实现。
你必须选择:
a)阅读算法papaers并尝试在PHP中实现它,并成为第一个做到这一点的人。
b)使用一些代理,在Java,Ruby等中有一些公共算法实现。你可以通过命令行等来调用它们。