Helical Alpha Code

SAF: a secure ARCFour implementation in PHP


#!/usr/bin/php
<?

$usage = 'Usage: saf [e,d] filename key [IV length] [mix iterations]
'
;

$mode = $argv[1];
$target = $argv[2];
$rawkey = $argv[3];
$ivlen = $argv[4];
$nMixes = $argv[5];

if($mode == 'e') {
 if(file_exists($target)) {
  encryptDoc($target,$rawkey,$ivlen,$nMixes);
  }
 else {
  echo("File $target does not exist or was not specified.\n");
  echo($usage);
  }
 }
elseif($mode = 'd') {
 if(file_exists($target)) {
  decryptDoc($target,$rawkey);
  }
 else {
  echo("File $target does not exist or was not specified.\n");
  echo($usage);
  }
 }
else {
 echo($usage);
 }


/*********************
 HERE THERE BE DRAGONS
 *********************/



// UTILITY FUNCTIONS //

function vprint($vector) {
 foreach($vector as $value) {
  echo(ord($value."\t"));
  }
 echo("\n");
 }

function vsprint($string) {
 $length = strlen($string);
 for($i=0; $i<$length; $i++) {
  echo(ord($string{$i})."\t");
  }
 echo("\n");
 }

function viprint($vector) {
 foreach($vector as $value) {
  echo($value."\t");
  }
 echo("\n");
 }


// KEY FUNCTIONS //

function keyVec($rawkey) {
/*
 Convert key string to int vector
 */


 // Convert the key to an integer vector
 for($i=0x00; $i<strlen($rawkey); $i++) {
  $key[$i] = ord($rawkey{$i});
  }
 return($key);
 }


function keyBuild($rawkey,$rawiv) {
 $key = array_merge(keyVec($rawkey),ivVec($rawiv));
 return($key);
 }


// INITIALIZATION VECTOR FUNCTIONS //

function ivGen($ivlen) {
/*
 Create the $ivlen-byte initialization vector
 */

 for($i=0x00; $i<$ivlen; $i++) {
  $iv[] = mt_rand(0x00,0xFF);
  }
 return($iv);
 }


function ivRaw($iv) {
 foreach($iv as $ivi) {
  $rawiv .= chr($ivi);
  }
 return($rawiv);
 }


function ivVec($rawiv) {
/*
Converts a raw ascii initialization string to an int vector.

Note: $iv must be set with ord()'d characters. Otherwise, every iv
  will be identical other than those containing the null byte (therefore
  an empty string), since when PHP evaluates each character as an int
  later on, those ascii characters will be evaluated as 1 (or 0 in the
  case of 0x00). This would introduce a serious weakness into the cypher.
 */

 $ivlen = strlen($rawiv);
 for($i=0x00; $i<$ivlen; $i++) {
  $iv[] = ord($rawiv{$i});
  }
 return($iv);
 }


// STATE FUNCTIONS //

function stateInit() {
 for($i=0x00; $i<0x0100; $i++) {
  $state[] = $i;
  }
 return($state);
 }


function stateGen($keyVector,$nMixes) {

 // Initialize state array
 $state = stateInit();
# for($i=0x00; $i<0x0100; $i++) {
#  $state[] = $i;
#  }

 // Mix the state array
 $j=0x00;
 $klen = count($keyVector);

 for($k=0x00; $k<$nMixes; $k++) {

  for($i=0x00; $i<0x0100; $i++) {
   $j = ($j + $state[$i] + $keyVector[$i % $klen]) % 0x0100;
   $swap = $state[$i];
   $state[$i] = $state[$j];
   $state[$j] = $swap;
   }
  }
 return($state);
 }


// CYPHERSABRE FUNCTIONS //

function cCypher($state,$input) {
 
 $j = 0x00;
 $ilen = strlen($input);
 for($i=0x00; $i<$ilen; $i++) {
  $j = ($j + $state[$i % 0x0100]) % 0x0100;
   $swap = $state[$i];
   $state[$i] = $state[$j];
   $state[$j] = $swap;
  $output .= chr($state[($state[$i] + $state[$j]) % 0x0100] ^ ord($input{$i}));
  }
 return($output);
 }


function csEnDeCrypt($rawkey,$rawiv,$nMixes,$input) {
 $key = keyBuild($rawkey,$rawiv);
 $state = stateGen($key,$nMixes);
 $output = cCypher($state,$input);
 return($output);
 }


// SECUREARC FUNCTIONS //
// Unfortunately, this is takes about 30.995% as much time as Cyphersabre,
// due to the extra round of stream generation.

function genStream($state,$length,$i,$j) {
 for($iorig=$i; $i<$length+$iorig; $i++) {
  $j = ($j + $state[$i % 0x0100]) % 0x0100;
  // The array stream seems to work slightly faster: see bCypher()
  #$stream .= chr($state[($state[$i] + $state[$j]) % 0x0100]); // is using a string that later needs ord()ing faster?
  $stream[] = $state[($state[$i] + $state[$j]) % 0x0100]; // could be either way . . .
  }
 $output = array(
  'position' => $i % 0x0100,
  'permutation' => $j,
  'stream' => $stream
  );
 return($output);
 }


function bCypher($state,$input) {
 $length = strlen($input);
 $streamdata = genStream($state,$length,0x00,0x00);
 for($i=0x00; $i<$length; $i++) {
  // The overhead of an array seems to be justified in the time saved
  // not processing ord() so many times: see genStream();
  #$output .= chr(ord($streamdata['stream']{$i}) ^ ord($input{$i}));
  $output .= chr($streamdata['stream'][$i] ^ ord($input{$i}));
  }
 return($output);
 }


function bsEnDeCrypt($rawkey,$rawiv,$nMixes,$input) {
 $key = keyBuild($rawkey,$rawiv);
 $output = bCypher(stateGen($key,$nMixes),$input);
 return($output);
 }


// DOCUMENT FUNCTIONS //

function decryptDoc($fn,$rawkey) {
 $file = fopen($fn,'r');
 $data = base64_decode(fread($file,filesize($fn)));
 
 $nMixes = ord($data{0}) % 64;
 $ivlen = ord($data{1});
 $output = $ivlen;
 $rawiv = substr($data,2,$ivlen);
 $input = substr($data,2+$ivlen,filesize($fn));
 $output = bsEnDeCrypt($rawkey,$rawiv,$nMixes,$input);
 fclose($file);
 echo($output);
 }


function encryptDoc($fn,$rawkey,$ivlen,$nMixes) {
 $file = fopen($fn,'r');
 $input = fread($file,filesize($fn));
 fclose($file);
 $rawiv = ivRaw(ivGen($ivlen));
 $cypher = bsEnDeCrypt($rawkey,$rawiv,$nMixes,$input);
 $output = base64_encode(chr($nMixes).chr($ivlen).$rawiv.$cypher);
 echo($output);
 }
?>

Generated by GNU enscript 1.6.1 and enscriptclean.

SAF | Download Source | View Source