AES PHP Implementation

From Second Life Wiki
Jump to navigation Jump to search

Description

The following is a port of the LSL AES Engine by Haravikk Mistral, allowing you to process Java and LSL compatible AES messages in PHP.

The Crypto class provided performs extremely well on most PHP set-ups, but the cost of including the file can vary with a number of factors. For this reason if you are only using AES encryption within a single script, you may consider entering the Crypto class directly into this script, rather than including it.

NOTE: The PHP implementation includes helper functions for handling strings, which are used in the examples, as the base64_decode() function provided by PHP will attempt to process null-characters produced as a result of the 6-bit to 8-bit conversion process. If you wish to process strings with null-characters at the end, then you will need to use invertPadBase64CipherToString() and call base64_decode yourself on the result.

Class

<php><?php /*******************************************************************************

define('AES_MODE_CBC', 1); define('AES_MODE_CFB', 2);

define('AES_PAD_NONE', 128); define('AES_PAD_RBT', 129); define('AES_PAD_NULLS', 130); define('AES_PAD_NULLS_SAFE', 131); define('AES_PAD_ZEROES', 132); define('AES_PAD_RANDOM', 133);

define('AES_HEX_CHARS', '0123456789abcdef'); define('AES_BASE64_CHARS', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');

define('AES_DEFAULT_PAD', 512);

class Crypto { private static $SBOX = array( 0x637c777b, 0xf26b6fc5, 0x3001672b, 0xfed7ab76, 0xca82c97d, 0xfa5947f0, 0xadd4a2af, 0x9ca472c0, 0xb7fd9326, 0x363ff7cc, 0x34a5e5f1, 0x71d83115, 0x04c723c3, 0x1896059a, 0x071280e2, 0xeb27b275, 0x09832c1a, 0x1b6e5aa0, 0x523bd6b3, 0x29e32f84, 0x53d100ed, 0x20fcb15b, 0x6acbbe39, 0x4a4c58cf, 0xd0efaafb, 0x434d3385, 0x45f9027f, 0x503c9fa8, 0x51a3408f, 0x929d38f5, 0xbcb6da21, 0x10fff3d2, 0xcd0c13ec, 0x5f974417, 0xc4a77e3d, 0x645d1973, 0x60814fdc, 0x222a9088, 0x46eeb814, 0xde5e0bdb, 0xe0323a0a, 0x4906245c, 0xc2d3ac62, 0x9195e479, 0xe7c8376d, 0x8dd54ea9, 0x6c56f4ea, 0x657aae08, 0xba78252e, 0x1ca6b4c6, 0xe8dd741f, 0x4bbd8b8a, 0x703eb566, 0x4803f60e, 0x613557b9, 0x86c11d9e, 0xe1f89811, 0x69d98e94, 0x9b1e87e9, 0xce5528df, 0x8ca1890d, 0xbfe64268, 0x41992d0f, 0xb054bb16 );

private static $RSBOX = array( 0x52096ad5, 0x3036a538, 0xbf40a39e, 0x81f3d7fb, 0x7ce33982, 0x9b2fff87, 0x348e4344, 0xc4dee9cb, 0x547b9432, 0xa6c2233d, 0xee4c950b, 0x42fac34e, 0x082ea166, 0x28d924b2, 0x765ba249, 0x6d8bd125, 0x72f8f664, 0x86689816, 0xd4a45ccc, 0x5d65b692, 0x6c704850, 0xfdedb9da, 0x5e154657, 0xa78d9d84, 0x90d8ab00, 0x8cbcd30a, 0xf7e45805, 0xb8b34506, 0xd02c1e8f, 0xca3f0f02, 0xc1afbd03, 0x01138a6b, 0x3a911141, 0x4f67dcea, 0x97f2cfce, 0xf0b4e673, 0x96ac7422, 0xe7ad3585, 0xe2f937e8, 0x1c75df6e, 0x47f11a71, 0x1d29c589, 0x6fb7620e, 0xaa18be1b, 0xfc563e4b, 0xc6d27920, 0x9adbc0fe, 0x78cd5af4, 0x1fdda833, 0x8807c731, 0xb1121059, 0x2780ec5f, 0x60517fa9, 0x19b54a0d, 0x2de57a9f, 0x93c99cef, 0xa0e03b4d, 0xae2af5b0, 0xc8ebbb3c, 0x83539961, 0x172b047e, 0xba77d626, 0xe1691463, 0x55210c7d );

private static function getSBoxByte($n) { $v = self::$SBOX[$n / 4]; return ($v >> ((3 - ($n % 4)) * 8)) & 0xFF; }

private static function getSBoxInvertedByte($n) { $v = self::$RSBOX[$n / 4]; return ($v >> ((3 - ($n % 4)) * 8)) & 0xFF; }

public static $NULL_BLOCK = array(0, 0, 0, 0); public static $NULL_STATE = array( array(0, 0, 0, 0), array(0, 0, 0, 0), array(0, 0, 0, 0), array(0, 0, 0, 0) );

private $mode = AES_MODE_CBC; private $modeHandle = null;

private $padType = AES_PAD_RBT; private $padSize = AES_DEFAULT_PAD;

private $roundKey = array(); private $rounds = 0;

private $iv = array();

public function Crypto($mode=0, $padType=0, $padSize=0) { if ($padSize >= 128) $this->padSize = $padSize; if (($padType >= 128) && ($padType <= 133)) $this->padType = $padType;

if (($mode >= 1) && ($mode <= 2)) { $this->mode = $mode;

if ($this->mode == AES_MODE_CBC) $this->modeHandle = new CryptoAESCBC(); else $this->modeHandle = new CryptoAESCFB(); } }

public function setHexKey(&$key) { return $this->keyExpansion(self::hexToBytes($key)); }

public function setBase64Key(&$key) { return $this->keyExpansion(self::base64ToBytes($key)); }

public function setHexIV(&$iv) { $iv = self::hexToBytes($iv); if (is_array($iv) && (count($iv) > 4)) $this->iv = array_slice($iv, 1); else $this->iv = self::$NULL_BLOCK; }

public function padHexCipherToHex(&$cipher) { return self::bytesToHex( $this->padCipher(self::hexToBytes($cipher))); }

public function padHexCipherToBase64(&$cipher) { return self::bytesToBase64( $this->padCipher(self::hexToBytes($cipher))); }

public function padStringCipherToBase64(&$cipher) { return self::bytesToBase64( $this->padCipher( self::base64ToBytes(base64_encode($cipher)))); }

public function invertPadBase64CipherToString(&$cipher) { $s = self::bytesToBase64( $this->invertPadCipher(self::base64ToBytes($cipher)));

if ($this->padType != AES_PAD_NULLS_SAFE) { // Trim null-characters (A's), since php's base64 // functions don't trim them like they should. $l = $o = mb_strlen($s); while (($l) >= 0) { $c = mb_substr($s, $l - 1, 1); $e = ($c == '='); if ($e) --$o; // ignore pad characters

if (($c != 'A') && !$e) break; --$l; }

if ($l != $o) { $s = mb_substr($s, 0, $l);

$l %= 4; if ($l) { if ($l == 2) $s .= '=='; else if ($l == 1) $s .= '='; } } }

return base64_decode($s); }

public function padBase64CipherToHex(&$cipher) { return self::bytesToHex( $this->padCipher(self::base64ToBytes($cipher))); }

public function padBase64CipherToBase64(&$cipher) { return self::bytesToBase64( $this->padCipher(self::base64ToBytes($cipher))); }

private function padCipher(&$data) { $bits = $data[0]; $data = array_slice($data, 1); $count = count($data);

$padding = $this->padType; if ($padding == AES_PAD_NONE) { if ($this->mode == AES_MODE_CFB) return array_merge( (array)$bits, $this->cipher($data) ); $padding = AES_PAD_RBT; }

$blockSize = $this->padSize; if ($padding == AES_PAD_RBT) $blockSize = 128;

$blocks = (integer)($bits / $blockSize); $extra = $bits % $blockSize;

if ($padding == AES_PAD_RBT) { $final = array(); if ($extra > 0) { $words = $extra >> 5; if (($words << 5) < $extra) ++$words;

$pos = $count - $words; $t = array_slice($data, $pos, $words);

$lb = array(); if ($blocks < 1) { $data = array(); $lb = $this->cipher($this->cipher($iv)); } else { $data = $this->cipher( array_slice($data, 0, $pos) );

$lb = $this->cipher( array_slice($data, $pos - 4, 4) ); }

$l = count($t); for ($i = 0; $i < $l; ++$i) $final[] = $t[$i] ^ $lb[$i];

return array_merge((array)$bits, $data, $final); } return array_merge((array)$bits, $this->cipher($data)); } else { $extra = $blockSize - $extra;

if ($padding == AES_PAD_NULLS_SAFE) { ++$bits; $words = $bits >> 5; $bit = $bits % 32;

if ($words < count($data)) $data[$words] |= (1 << (32 - $bit)); else $data[] = 0x80000000;

if ((--$extra) < 0) $extra += $blockSize; $padding = AES_PAD_NULLS; }

$bytes = $extra >> 3; if ($bytes <= 0) { if ($padding == AES_PAD_NULLS) return array_merge( (array)$bits, $this->cipher($data) );

$bytes = $blockSize >> 3; $extra += $blockSize; }

$bits += $extra; $words = $bytes >> 2; $extra = $bytes % 4;

if ($extra > 0) { $i = 0; $index = count($data) - 1; $v = $data[$index];

if (($extra == $bytes) && ($padding != AES_PAD_NULLS)) { $v |= $bytes; $i = 1; }

$byte = 0; for (; $i < $extra; ++$i) { if ($padding == AES_PAD_RANDOM) { $byte = mt_rand(0, 255); $v |= ($byte << ($i << 3)); } }

$data[$index] = $v; }

$w = array(); if ($words > 0) { $final = -1; if ($padding != AES_PAD_NULLS) $final = $words - 1;

$word = 0; $byte = 0; for ($i = 0; $i < $words; ++$i) { $word = 0; for ($j = 0; $j < 4; ++$j) { if (($padding != AES_PAD_NULLS) && ($i == $final) && !$j) $byte = $bytes; else if ($padding == AES_PAD_RANDOM) $byte = mt_rand(0, 255);

$word |= ($byte << ($j << 3)); }

$w[] = $word; }

$data = array_merge($data, $w); }

return array_merge((array)$bits, $this->cipher($data)); } }

public function invertPadHexCipherToHex(&$cipher) { return self::bytesToHex($this->invertPadCipher(self::hexToBytes($cipher))); }

public function invertPadHexCipherToBase64(&$cipher) { return self::bytesToBase64($this->invertPadCipher(self::hexToBytes($cipher))); }

public function invertPadBase64CipherToHex(&$cipher) { return self::bytesToHex($this->invertPadCipher(self::base64ToBytes($cipher))); }

public function invertPadBase64CipherToBase64(&$cipher) { return self::bytesToBase64($this->invertPadCipher(self::base64ToBytes($cipher))); }

private function invertPadCipher(&$data) { $bits = $data[0]; $data = array_slice($data, 1);

$padding = $this->padType; if ($padding == AES_PAD_NONE) { if ($this->mode == AES_MODE_CFB) return array_merge( (array)$bits, $this->invertCipher($data) ); $padding = AES_PAD_RBT; }

$blockSize = $this->padSize; if ($padding == AES_PAD_RBT) $blockSize = 128;

$blocks = (integer)($bits / $blockSize); $extra = $bits % $blockSize;

if ($padding == AES_PAD_RBT) { $final = array(); if ($extra > 0) { $words = $extra >> 5; if (($words << 5) < $extra) ++$words;

$pos = $count - $words; $t = array_slice($data, $pos, $words);

$lb = array(); if ($blocks < 1) $lb = $this->cipher( $this->cipher($this->iv) ); else { $start = $count - (4 + $words); $lb = $this->cipher( array_slice( $data, $start, 4 ) );

$data = $this->invertCipher( array_slice($data, 0, $pos) ); }

$l = count($t); for ($i = 0; $i < $l; ++$i) $final[] = $t[$i] ^ $lb[$i]; }

return array_merge((array)$bits, $data, $final); } else { if ($extra > 0) { $bits -= $extra;

$e = $extra >> 5; if (($e << 5) < $extra) ++$e; $extra = $e;

if ($extra <= 0) $extra = 1;

$count = count($data); if ($extra > $count) return (array)0;

$data = array_slice($data, 0, $count - $extra); }

$data = $this->invertCipher($data);

$count = count($data); $bytes = 0; $words = 0; $excessBits = 0;

if (($padding == AES_PAD_NULLS) || ($padding == AES_PAD_NULLS_SAFE)) { $v = 0; $continue = true;

while ($continue && ($words < $count)) { $v = $data[$count - ($words + 1)];

if ($v == 0) { ++$words; $bytes += 4; } else { for ($j = 0; $j < 4; ++$j) { $byte = ($v >> ($j << 3)) & 0xFF;

if ($byte == 0) ++$bytes; else { $continue = false; break; } } } }

if ($padding == AES_PAD_NULLS_SAFE) { $i = 1; while ($i < 0xFF) { ++$excessBits; if ($byte & $i) break; $i <<= 1; } } } else { $bytes = $data[$count - 1] & 0xFF; if (($bytes << 3) >= $bits) return (array)0; $words = $bytes >> 2; }

if ($words > 0) $data = array_slice($data, 0, $count - $words);

$bits -= ($bytes << 3) + $excessBits;

return array_merge((array)$bits, $data); } }

public function performInvertCipher(&$state) { $this->addRoundKey($state, $this->rounds);

$j = $this->rounds - 1; while ($j > 0) { $this->invertShiftRows($state); $this->invertSubBytes($state); $this->addRoundKey($state, $j--); $this->invertMixColumns($state); }

$this->invertShiftRows($state); $this->invertSubBytes($state); $this->addRoundKey($state, 0); }

private function invertCipher($data) { return $this->modeHandle->invertCipher($this, $data); }

public function performCipher(&$state) { $this->addRoundKey($state, 0);

for ($j = 1; $j < $this->rounds; ++$j) { $this->subBytes($state); $this->shiftRows($state); $this->mixColumns($state); $this->addRoundKey($state, $j); }

$this->subBytes($state); $this->shiftRows($state); $this->addRoundKey($state, $this->rounds); }

private function cipher($data) { return $this->modeHandle->cipher($this, $data); }

private function keyExpansion(&$key) { if (!is_array($key)) return false;

$count = count($key); if (($count <= 4) || ($count > 9)) return false;

$len = --$count; $this->roundKey = array_slice($key, 1);

$this->rounds = $len + 6; $x = ($len * 3) + 28;

$i = 0; $t = $this->roundKey[$len - 1];

do { if (!($i % $len)) $t = (((self::getSBoxByte(($t >> 16) & 0xFF) ^ (0x000D8080 >> (7 ^ ($i / $len)))) & 0xFF) << 24) | (self::getSBoxByte(($t >> 8) & 0xFF) << 16) | (self::getSBoxByte(($t ) & 0xFF) << 8) | (self::getSBoxByte(($t >> 24) & 0xFF) ); else if (($len > 6) && (($i % $len) == 4)) $t = ((self::getSBoxByte(($t >> 24) & 0xFF) << 24) | (self::getSBoxByte(($t >> 16) & 0xFF) << 16) | (self::getSBoxByte(($t >> 8) & 0xFF) << 8) | (self::getSBoxByte(($t ) & 0xFF) ));

$this->roundKey[] = ($t = ($t ^ $this->roundKey[$i]) & 0xFFFFFFFF); } while ((++$i) < $x);

return true; }

private function addRoundKey(&$state, $round) { $round <<= 2;

for ($i = 0; $i < 4; ++$i, ++$round) { $state[$i][0] ^= (($this->roundKey[$round] >> 24) & 0xFF); $state[$i][1] ^= (($this->roundKey[$round] >> 16) & 0xFF); $state[$i][2] ^= (($this->roundKey[$round] >> 8) & 0xFF); $state[$i][3] ^= (($this->roundKey[$round] ) & 0xFF); } }

private function subBytes(&$state) { for ($i = 0; $i < 4; ++$i) for ($j = 0; $j < 4; ++$j) $state[$i][$j] = self::getSBoxByte($state[$i][$j]); }

private function invertSubBytes(&$state) { for ($i = 0; $i < 4; ++$i) for ($j = 0; $j < 4; ++$j) $state[$i][$j] = self::getSBoxInvertedByte($state[$i][$j]); }

private function shiftRows(&$state) { $t = $state[0][1]; $state[0][1] = $state[1][1]; $state[1][1] = $state[2][1]; $state[2][1] = $state[3][1]; $state[3][1] = $t;

$t = $state[0][2]; $state[0][2] = $state[2][2]; $state[2][2] = $t;

$t = $state[1][2]; $state[1][2] = $state[3][2]; $state[3][2] = $t;

$t = $state[0][3]; $state[0][3] = $state[3][3]; $state[3][3] = $state[2][3]; $state[2][3] = $state[1][3]; $state[1][3] = $t; }

private function invertShiftRows(&$state) { $t = $state[3][1]; $state[3][1] = $state[2][1]; $state[2][1] = $state[1][1]; $state[1][1] = $state[0][1]; $state[0][1] = $t;

$t = $state[0][2]; $state[0][2] = $state[2][2]; $state[2][2] = $t;

$t = $state[1][2]; $state[1][2] = $state[3][2]; $state[3][2] = $t;

$t = $state[0][3]; $state[0][3] = $state[1][3]; $state[1][3] = $state[2][3]; $state[2][3] = $state[3][3]; $state[3][3] = $t; }


private function xTimes($x) { return (($x << 1) ^ ((($x >> 7) & 1) * 0x1b)) & 0xFF; }

private function multiply($x, $y) { $xT = $this->xTimes($x); $xT2 = $this->xTimes($xT); $xT3 = $this->xTimes($xT2);

return ((($y & 1) * $x) ^ ((($y >> 1) & 1) * $xT) ^ ((($y >> 2) & 1) * $xT2) ^ ((($y >> 3) & 1) * $xT3) ^ ((($y >> 4) & 1) * $this->xTimes($xT3))) & 0xFF; }

private function mixColumns(&$state) { for ($i = 0; $i < 4; ++$i) { $t = $state[$i][0]; $t1 = $state[$i][0] ^ $state[$i][1] ^ $state[$i][2] ^ $state[$i][3];

for ($j = 0; $j < 3; ++$j) $state[$i][$j] ^= $this->xTimes($state[$i][$j] ^ $state[$i][$j + 1]) ^ $t1;

$state[$i][3] ^= $this->xTimes($state[$i][3] ^ $t) ^ $t1; } }

private function invertMixColumns(&$state) { for ($i = 0; $i < 4; ++$i) { $a = $state[$i][0]; $b = $state[$i][1]; $c = $state[$i][2]; $d = $state[$i][3];

$state[$i][0] = $this->multiply($a, 0x0e) ^ $this->multiply($b, 0x0b) ^ $this->multiply($c, 0x0d) ^ $this->multiply($d, 0x09); $state[$i][1] = $this->multiply($a, 0x09) ^ $this->multiply($b, 0x0e) ^ $this->multiply($c, 0x0b) ^ $this->multiply($d, 0x0d); $state[$i][2] = $this->multiply($a, 0x0d) ^ $this->multiply($b, 0x09) ^ $this->multiply($c, 0x0e) ^ $this->multiply($d, 0x0b); $state[$i][3] = $this->multiply($a, 0x0b) ^ $this->multiply($b, 0x0d) ^ $this->multiply($c, 0x09) ^ $this->multiply($d, 0x0e); } }

private static function base64ToBytes(&$base64Data) { $x = mb_strpos($base64Data, '='); if ($x > 0) $base64Data = mb_substr($base64Data, 0, $x); return self::stringToBytes($base64Data, 6, AES_BASE64_CHARS); }

private static function hexToBytes(&$hexData) { $hexData = mb_strtolower($hexData); if (mb_substr($hexData, 0, 1) == '0x') $hexData = mb_substr($hexData, 2); return self::stringToBytes($hexData, 4, AES_HEX_CHARS); }

private static function stringToBytes(&$string, $width, $alphabet) { $l = mb_strlen($string);

$n = (array)($l * $width); $bitbuf = 0; $adjust = 32;

for ($i = 0; $i < $l; ++$i) { $val = mb_strpos($alphabet, mb_substr($string, $i, 1)); if ($val === false) return "Invalid character at index $i";

if (($adjust -= $width) <= 0) { $bitbuf = ($bitbuf | ($val >> -$adjust)) & 0xFFFFFFFF; $n[] = $bitbuf;

$adjust += 32; if ($adjust < 32) $bitbuf = ($val << $adjust) & 0xFFFFFFFF; else $bitbuf = 0; } else $bitbuf = ($bitbuf | ($val << $adjust)) & 0xFFFFFFFF; }

if ($adjust < 32) $n[] = $bitbuf;

return $n; }

private static function bytesToBase64(&$bytes) { $s = self::bytesToString($bytes, 6, AES_BASE64_CHARS);

$l = mb_strlen($s) % 4; if ($l) { if ($l == 2) $s .= '=='; else if ($l == 1) $s .= '='; } return $s; }

private static function bytesToHex(&$bytes) { return '0x' . self::bytesToString($bytes, 4, AES_HEX_CHARS); }

private static function bytesToString(&$bytes, $width, $alphabet) { $bits = $bytes[0];

$mask = ~(-1 << $width); $shift = 32 - $width;

$available = $prev = $i = 0; $s = ;

while (($bits -= 32) > -32) { $available += 32 + ($bits * (0 > $bits)); $buf = $bytes[++$i];

if ($available >= $width) { if ($prev) { $s .= mb_substr( $alphabet, $value = ( $extra | ( ($buf >> ($shift + $prev)) & ~(-1 << ($width - $prev)) ) ), 1 );

$buf <<= ($width - $prev); $available -= $width; }

while ($available >= $width) { $s .= mb_substr( $alphabet, $value = (($buf >> $shift) & $mask), 1 ); $buf <<= $width; $available -= $width; }

if ($prev = $available) $extra = ($buf >> $shift) & $mask; } else break; }

if ($available) { $buf &= 0xFFFFFFFF; $mask = -1 << ($width - $prev); $s .= mb_substr( $alphabet, $value = (($extra & $mask) | ( ($buf >> ($shift + $prev)) & ((-1 << ($width - $available)) ^ $mask)) ), 1 ); }

return $s; }

public function expandIV() { $iv = array(); for ($i = 0; $i < 4; ++$i) { $iv[$i][0] = (($this->iv[$i] >> 24) & 0xFF); $iv[$i][1] = (($this->iv[$i] >> 16) & 0xFF); $iv[$i][2] = (($this->iv[$i] >> 8) & 0xFF); $iv[$i][3] = (($this->iv[$i] ) & 0xFF); } return $iv; } }

class CryptoAESCBC { function invertCipher(&$crypto, &$data) { $state = Crypto::$NULL_STATE;

$next = array(); $prev = $crypto->expandIV();

$l = count($data); $output = array();

while ($l > 0) { for ($i = 0; $i < 4; ++$i) { $next[$i][0] = $state[$i][0] = (($data[$i] >> 24) & 0xFF); $next[$i][1] = $state[$i][1] = (($data[$i] >> 16) & 0xFF); $next[$i][2] = $state[$i][2] = (($data[$i] >> 8) & 0xFF); $next[$i][3] = $state[$i][3] = (($data[$i] ) & 0xFF); }

$crypto->performInvertCipher($state);

for ($i = 0; $i < 4; ++$i) $output[] = (($prev[$i][0] ^ $state[$i][0]) << 24) | (($prev[$i][1] ^ $state[$i][1]) << 16) | (($prev[$i][2] ^ $state[$i][2]) << 8) | (($prev[$i][3] ^ $state[$i][3]) );

$prev = $next;

$data = array_slice($data, 4); $l -= 4; }

return $output; }

function cipher(&$crypto, &$data) { $state = $crypto->expandIV();

$l = count($data); $output = array();

while ($l > 0) { for ($i = 0; $i < 4; ++$i) { $state[$i][0] ^= (($data[$i] >> 24) & 0xFF); $state[$i][1] ^= (($data[$i] >> 16) & 0xFF); $state[$i][2] ^= (($data[$i] >> 8) & 0xFF); $state[$i][3] ^= (($data[$i] ) & 0xFF); }

$crypto->performCipher($state);

for ($i = 0; $i < 4; ++$i) $output[] = ($state[$i][0] << 24) | ($state[$i][1] << 16) | ($state[$i][2] << 8) | ($state[$i][3] );

$data = array_slice($data, 4); $l -= 4; }

return $output; } }

class CryptoAESCFB { function invertCipher(&$crypto, &$data) { $prev = $crypto->expandIV();

$l = count($data); $output = array();

while ($l > 0) { $state = $prev;

$crypto->performCipher($state);

for ($i = 0; $i < 4; ++$i) { $prev[$i][0] = (($data[$i] >> 24) & 0xFF); $prev[$i][1] = (($data[$i] >> 16) & 0xFF); $prev[$i][2] = (($data[$i] >> 8) & 0xFF); $prev[$i][3] = (($data[$i] ) & 0xFF);

$output[] = (($prev[$i][0] ^ $state[$i][0]) << 24) | (($prev[$i][1] ^ $state[$i][1]) << 16) | (($prev[$i][2] ^ $state[$i][2]) << 8) | (($prev[$i][3] ^ $state[$i][3]) ); }

$data = array_slice($data, 4); $l -= 4; }

return $output; }

function cipher(&$crypto, &$data) { $state = $crypto->expandIV();

$l = count($data); $output = array();

while ($l > 0) { $crypto->performCipher($state);

for ($i = 0; $i < 4; ++$i) { $state[$i][0] ^= (($data[$i] >> 24) & 0xFF); $state[$i][1] ^= (($data[$i] >> 16) & 0xFF); $state[$i][2] ^= (($data[$i] >> 8) & 0xFF); $state[$i][3] ^= (($data[$i] ) & 0xFF);

$output[] = ($state[$i][0] << 24) | ($state[$i][1] << 16) | ($state[$i][2] << 8) | ($state[$i][3] ); }

$data = array_slice($data, 4); $l -= 4; }

return $output; } }

?></php>

Examples

The following are simple examples, and do not demonstrate real-world usage. They do not handle reading the message from Second Life, of which note, you will need to remember that PHP replaces any '+' characters (part of the base64 character-set) with spaces, unless you first replace them using URI encoding in your LSL script. The easiest solution is to use str_replace($base64data, ' ', '+') assuming your data contains only base64 encoded characters.

Importantly the examples below do not handle input-validation, or key-generation, which are both critical to maintaining security. It is up to the developer to determine how they wish to verify the identify of their in-world objects from malicious attackers, and how they will generate a key, and keep it updated.

Encryption

<php><?php include 'aes.php';

$myKey = '1234567890ABCDEF0123456789ABCDEF'; $myIV = '89ABCDEF0123456789ABCDEF01234567'; $myMsg = 'Hello world! I am a lovely message waiting to be encrypted!';

$aes = new Crypto(AES_MODE_CFB, AES_PAD_NONE, 512); $aes->setHexKey($myKey); $aes->setHexIV ($myIV);

die ($aes->padStringCipherToBase64($myMsg)); ?></php>

Decryption

<php><?php include 'aes.php';

$myKey = '1234567890ABCDEF0123456789ABCDEF'; $myIV = '89ABCDEF0123456789ABCDEF01234567'; $myMsg = 'Mdn6jGTwRPMOKTYTTdDKGm9KScz26LIz96KVOGAeMw3hpwByPfa07PDRHxRW4TIh5dmu5LlhKpTQChi=';

$aes = new Crypto(AES_MODE_CFB, AES_PAD_NONE, 512); $aes->setHexKey($myKey); $aes->setHexIV ($myIV);

die ($aes-> invertPadBase64CipherToString($myMsg)); ?></php>