Mit*_*l M -6 php random encryption stream-cipher
我需要在PHP中与使用ISAAC流密码的客户端进行通信.据我所知,没有一个可用于PHP的加密库实现了这个密码.如何在PHP应用程序中实现ISAAC密码?
(我已经找到了一个ISAAC的Java实现,几乎成功地将它移植到了PHP.唯一的问题是PHP中的无符号右移.我写了一个方法来实现它,但是当移位中的数字是负.)
Ilm*_*nen 21
该ISAAC密码是相当简单,因为它是用C写的,它不应该太硬将它移植到PHP.唯一真正的复杂问题是ISAAC使用带有环绕的32位无符号整数,而PHP的整数可能是32位或64位,并在溢出时自动转换为浮点数.然而,这并不是一个大问题,因为我们可以通过在需要强制中间值低至32位的位置应用位掩码来轻松解决这个问题.
无论如何,这是PHP的ISAAC参考代码的相当直接的端口:
截至2017年9月,此代码现在也可以在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();
}
}
Run Code Online (Sandbox Code Playgroud)
的ISAAC类的构造有一个可选$seed参数,该参数应该是一个的32位整数256元件阵列,最多1024个字节的字符串(它被转换为使用阵列unpack();见代码)或null(缺省值).如果种子为空或省略,较短的单通初始化时,其对应于调用randinit()与flag == FALSE在C参考实施; 否则,flag == TRUE使用对应的两次通过初始化.
该类提供了一个rand()返回单个32位数字的方法,就像rand()在Jenkins中定义的宏一样rand.h.或者,我将核心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";
}
}
Run Code Online (Sandbox Code Playgroud)
来自ISAAC挑战的第二个 randtest.c:
<?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";
}
Run Code Online (Sandbox Code Playgroud)
这些程序的输出应分别与randvect.txt和randseed.txt匹配.