ISAACストリーム暗号を使用しているクライアントとPHPで通信する必要があります。私の知る限り、PHPで利用可能な暗号ライブラリはどれもこの暗号を実装していません。PHPアプリケーションにISAAC暗号をどのように実装できますか?
(ISAACのJava実装を見つけ、PHPへの移植にほぼ成功しました。唯一の問題はPHPでの符号なし右シフトです。これを行うメソッドを作成しましたが、シフトの数値がネガティブ。)
ISAACストリーム暗号を使用しているクライアントとPHPで通信する必要があります。私の知る限り、PHPで利用可能な暗号ライブラリはどれもこの暗号を実装していません。PHPアプリケーションにISAAC暗号をどのように実装できますか?
(ISAACのJava実装を見つけ、PHPへの移植にほぼ成功しました。唯一の問題はPHPでの符号なし右シフトです。これを行うメソッドを作成しましたが、シフトの数値がネガティブ。)
ISAAC暗号はかなり単純であり、Cで記述されているため、PHPに移植するのはそれほど難しくありません。唯一の実際の問題は、ISAACがラップアラウンドで32ビットの符号なし整数を使用するのに対し、PHPの整数は32ビットまたは64ビットであり、オーバーフロー時に浮動小数点数に自動変換されることです。ただし、これはそれほど大きな問題ではありません。中間値を32ビットに強制するために必要な場所にビットマスクを適用することで簡単に回避できるためです。
とにかく、これがISAAC参照コードのPHPへのかなり直接的な移植です。
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();
}
}
ISAAC
クラスコンストラクターはオプションのパラメーターを取ります。$seed
これは、32ビット整数の256要素配列、最大1024バイトの文字列(;を使用して配列に変換されunpack()
ます;コードを参照)またはnull
(デフォルト)のいずれかである必要があります。シードがnullまたは省略されている場合は、短いシングルパス初期化が使用されます。これは、Cリファレンス実装でのrandinit()
withの呼び出しに対応します。flag == FALSE
それ以外の場合は、に対応する2パス初期化flag == TRUE
が使用されます。
このクラスは、Jenkinsで定義されているマクロrand()
と同様に、単一の32ビット数を返すメソッドを提供します。または、コアメソッドとその内部結果バッファーをパブリックのままにして、ジェネレーターへのより直接的なアクセスを好む人が自分自身を呼び出して、その方法で出力を取得できるようにします。リファレンス実装の場合と同様に、コンストラクターはすでに1回呼び出しているため、最初の256個の出力値を使い果たした後でのみコンストラクターを再度呼び出す必要があることに注意してください。rand()
rand.h
isaac()
$r
isaac()
isaac()
randinit()
これが2つのテストプログラムです。最初のプログラムは、 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";
}
}
ISAACチャレンジからの2番目の 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";
}
これらのプログラムの出力は、それぞれrandvect.txtおよびrandseed.txtと一致する必要があります。
AFAIKには、PHPでのISAACの公開実装はありません。それほど人気がないため、PHPで既製の実装を見つけることはできません。
オプションが必要です:
a)アルゴリズムのペーパーを読み、PHPで実装して、最初にそれを実行してみてください。
b)いくつかのプロキシを使用し、Java、Rubyなどでアルゴリズムのパブリック実装があります。コマンドラインなどを介してそれらを呼び出すことができます。