Вы находитесь на странице: 1из 14

Передача зашифрованных алгоритмом Rijndael (AES)

Симметричный алгоритм шифрования AES......................................................................................................1


Алгоритм..........................................................................................................................................................1
Документированный исходный код....................................................................................................................3
Unit-тесты.........................................................................................................................................................3
Шифрование и дешифрование.......................................................................................................................4
Передача зашифрованного сообщения по сети..........................................................................................12
Принимающая сторона.............................................................................................................................12
Посылающая сторона...............................................................................................................................12
Выполнение программы....................................................................................................................................13
Принимающая сторона..................................................................................................................................13
Посылающая сторона....................................................................................................................................14

Симметричный алгоритм шифрования AES


Advanced Encryption Standard (AES), также известный как Rijndael (произносится [rɛindaːl] (Рэндал[1]) )
— симметричный алгоритм блочного шифрования (размер блока 128 бит, ключ 128/192/256 бит),
принятый в качестве стандарта шифрования правительством США по результатам конкурса AES. Этот
алгоритм хорошо проанализирован и сейчас широко используется, как это было с его
предшественником DES.
Национальный институт стандартов и технологий США (англ. National Institute of Standards and
Technology, NIST) опубликовал спецификацию AES 26 ноября 2001 года после пятилетнего периода, в
ходе которого были созданы и оценены 15 кандидатур. 26 мая 2002 года AES был объявлен стандартом
шифрования. По состоянию на 2009 год AES является одним из самых распространённых алгоритмов
симметричного шифрования.[2][3] Поддержка AES (и только его) введена фирмой Intel в семейство
процессоров x86 начиная с Intel Core i7-980X Extreme Edition, а затем на процессорах Sandy Bridge.

Алгоритм
Основные понятия и методы

последовательность бит, из которых состоит input, output, State и Round


Block
Key. Также под Block можно понимать последовательность байт
секретный, криптографический ключ, который используется Key Expansion
процедурой, чтобы произвести набор ключей для раундов(Round Keys);
Cipher Key
может быть представлен как прямоугольный массив байтов, имеющий
четыре строки и Nk колонок.
Ciphertext выходные данные алгоритма шифрования
Key Expansion процедура используемая для генерации Round Keys из Cipher Key
Round Keys получаются из Cipher Key используя процедуру Key Expansion.
Round Key
Они применяются к State при шифровании и расшифровании
промежуточный результат шифрования, который может быть представлен
State
как прямоугольный массив байтов имеющий 4 строки и Nb колонок
S-box нелинейная таблица замен, использующаяся в нескольких трансформациях
замены байт и в процедуре Key Expansion для взаимнооднозначной замены

1
значения байта. Предварительно рассчитанный S-box можно увидеть ниже.
Nb число столбцов(32-х битных слов), составляющих State. Для AES, Nb = 4
число 32-х битных слов, составляющих шифроключ. Для AES, Nk = 4, 6,
Nk
или 8
число раундов, которое является функцией Nk и Nb. Для AES, Nr = 10, 12,
Nr
14
массив, который состоит из битов 32-х разрядного слова и является
Rcon[] постоянным для данного раунда. Предварительно рассчитанный Rcon[]
можно увидеть ниже.
трансформация при шифровании и обратном шифровании, при которой
AddRoundKey() Round Key XOR’ится c State. Длина RoundKey равна размеру State(то есть,
если Nb = 4, то длина RoundKey равна 128 бит или 16 байт)
трансформация при шифровании, которая берет все столбцы State и
MixColumns() смешивает их данные (независимо друг от друга), чтобы получить новые
столбцы
функция, использующаяся в процедуре Key Expansion, которая берет 4-х
RotWord()
байтное слово и производит над ним циклическую перестановку
трансформации при шифровании, которые обрабатывают State, циклически
ShiftRows()
смещая последние три строки State на разные величины
трансформации при шифровании, которые обрабатывают State используя
SubBytes() нелинейную таблицу замещения байтов(S-box), применяя её независимо к
каждому байту State
функция, используемая в процедуре Key Expansion, которая берет на входе
SubWord() четырёх-байтное слово и, применяя S-box к каждому из четырёх байтов,
выдаёт выходное слово

Шифрование
Cipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)])
begin
byte state[4,Nb]

state = in

AddRoundKey(state, w[0, Nb-1])

for round = 1 step 1 to Nr-1


SubBytes(state)
ShiftRows(state)
MixColumns(state)
AddRoundKey(state, w[round*Nb, (round+1)*Nb-1])
end for

SubBytes(state)
ShiftRows(state)
AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1])

out = state
end

Расшифрование

2
InvCipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)])
begin
byte state[4,Nb]

state = in

AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1])

for round = Nr-1 step -1 downto 1


InvShiftRows(state)
InvSubBytes(state)
AddRoundKey(state, w[round*Nb, (round+1)*Nb-1])
InvMixColumns(state)
end for

InvShiftRows(state)
InvSubBytes(state)
AddRoundKey(state, w[0, Nb-1])

out = state
end

Документированный исходный код


Unit-тесты
<?php

namespace awa\secure\symmetric;

/**
* Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2014-05-10 at 18:15:45.
*/
class AesTest extends \PHPUnit_Framework_TestCase{

/**
* @var Aes
*/
protected $object;

/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp(){
$this->object=new Aes;
}

/**
* Tears down the fixture, for example, closes a network connection.
* This method is called after a test is executed.
*/
protected function tearDown(){

/**
* @covers awa\secure\symmetric\Aes::decode
*/
public function testDecode(){

3
$this->assertEquals(
'Hello, World!',
$this->object->decode('3168431', 'FAD1ts0vgFOWg+xYmzcUfKWOXwdo')
);
}

/**
* @covers awa\secure\symmetric\Aes::decode
*/
public function testDecode2(){
$this->assertEquals(
'Это исходный текст',
$this->object->decode(
'PASSPHRASE',
'GwAuUs0vgFMac6cNQ+cmk6X/A9Q60y9HHczCvj2GMbB4jEsEb6jVYgg0'
)
);
}

/**
* @covers awa\secure\symmetric\Aes::encode
*/
public function testEncode(){
$message='Hello, World! Hello, World!';
$key='3168431';
$this->assertEquals($message, $this->object->decode($key, $this->object-
>encode($key, $message)));
}

/**
* @covers awa\secure\symmetric\Aes::encode
*/
public function testEncode2(){
$message='Это исходный текст';
$key='PASSPHRASE###';
$this->assertEquals($message, $this->object->decode($key, $this->object-
>encode($key, $message)));
}

/**
* @covers awa\secure\symmetric\Aes::setup
* @todo Implement testSetup().
*/
public function testSetup(){
// Remove the following lines when you implement this test.
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}

Шифрование и дешифрование
<?php

namespace awa\secure\symmetric;

class Aes implements Encryption{

4
private static $keyNumBits=256;

public function setup(array $config){


if($config){
self::$keyNumBits=(int)$config['key_num_bits'];
}
}

public function decode($key, $message){


return self::decrypt($message, $key, self::$keyNumBits);
}

public function encode($key, $message){


return self::encrypt($message, $key, self::$keyNumBits);
}

/**
* Шифрование
* @param plaintext source text to be encrypted
* @param password the password to use to generate a key
* @param nBits number of bits to be used in the key (128, 192, or 256)
* @return encrypted text
*/
public static function encrypt($message, $pass, $numBits){
self::checkNumBitsStandarts($numBits);
$blockSize=16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
// note PHP (5) gives us plaintext and password in UTF8 encoding!
// use AES itself to encrypt password to get cipher key (using plain password as
source for
// key expansion) - gives us well encrypted key
$numBytes=$numBits/8; // no bytes in key
$pwBytes=array();
for($i=0; $i<$numBytes; $i++){
$pwBytes[$i]=ord(substr($pass, $i, 1))&0xff;
}
$key=self::cipher($pwBytes, self::keyExpansion($pwBytes));
$key=array_merge($key, array_slice($key, 0, $numBytes-16)); // expand key to
16/24/32 bytes long
// initialise 1st 8 bytes of counter block with nonce (NIST SP800-38A §B.2): [0-
1] = millisec,
// [2-3] = random, [4-7] = seconds, giving guaranteed sub-ms uniqueness up to Feb
2106
$counterBlock=array();
$nonce=floor(microtime(true)*1000); // timestamp: milliseconds since 1-Jan-1970
$nonceMs=$nonce%1000;
$nonceSec=floor($nonce/1000);
$nonceRnd=floor(rand(0, 0xffff));
for($i=0; $i<2; $i++){
$counterBlock[$i]=self::urs($nonceMs, $i*8)&0xff;
}
for($i=0; $i<2; $i++){
$counterBlock[$i+2]=self::urs($nonceRnd, $i*8)&0xff;
}
for($i=0; $i<4; $i++){
$counterBlock[$i+4]=self::urs($nonceSec, $i*8)&0xff;
}
// and convert it to a string to go on the front of the ciphertext
$ctrTxt='';
for($i=0; $i<8; $i++){
$ctrTxt .= chr($counterBlock[$i]);
}
// generate key schedule - an expansion of the key into distinct Key Rounds for
each round

5
$keySchedule=self::keyExpansion($key);
//print_r($keySchedule);

$blockCount=ceil(strlen($message)/$blockSize);
$ciphertxt=array(); // ciphertext as array of strings

for($b=0; $b<$blockCount; $b++){


// set counter (block #) in last 8 bytes of counter block (leaving nonce in
1st 8 bytes)
// done in two stages for 32-bit ops: using two words allows us to go past
2^32 blocks (68GB)
for($c=0; $c<4; $c++){
$counterBlock[15-$c]=self::urs($b, $c*8)&0xff;
}
for($c=0; $c<4; $c++){
$counterBlock[15-$c-4]=self::urs($b/0x100000000, $c*8);
}
$cipherCntr=self::cipher($counterBlock, $keySchedule); // -- encrypt counter
block --
// block size is reduced on final block
$blockLength=$b<$blockCount-1 ? $blockSize : (strlen($message)-1)%
$blockSize+1;
$cipherByte=array();

for($i=0; $i<$blockLength; $i++){ // -- xor plaintext with ciphered counter


byte-by-byte --
$cipherByte[$i]=$cipherCntr[$i]^ord(substr($message, $b*$blockSize+$i,
1));
$cipherByte[$i]=chr($cipherByte[$i]);
}
$ciphertxt[$b]=implode('', $cipherByte); // escape troublesome characters in
ciphertext
}

// implode is more efficient than repeated string concatenation


return base64_encode($ctrTxt.implode('', $ciphertxt));
}

/**
* Дешифрование
* @param ciphertext source text to be decrypted
* @param password the password to use to generate a key
* @param nBits number of bits to be used in the key (128, 192, or 256)
* @return decrypted text
*/
public static function decrypt($message, $password, $numBits){
self::checkNumBitsStandarts($numBits);
$blockSize=16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES

$message=base64_decode($message);

// use AES to encrypt password (mirroring encrypt routine)


$numBytes=$numBits/8; // no bytes in key
$pwBytes=array();
for($i=0; $i<$numBytes; $i++){
$pwBytes[$i]=ord(substr($password, $i, 1))&0xff;
}
$key=self::cipher($pwBytes, self::keyExpansion($pwBytes));
$key=array_merge($key, array_slice($key, 0, $numBytes-16)); // expand key to
16/24/32 bytes long
// recover nonce from 1st element of ciphertext
$counterBlock=array();
$ctrTxt=substr($message, 0, 8);
for($i=0; $i<8; $i++){

6
$counterBlock[$i]=ord(substr($ctrTxt, $i, 1));
}
// generate key schedule
$keySchedule=self::keyExpansion($key);

// separate ciphertext into blocks (skipping past initial 8 bytes)


$nBlocks=ceil((strlen($message)-8)/$blockSize);
$ct=array();
for($b=0; $b<$nBlocks; $b++){
$ct[$b]=substr($message, 8+$b*$blockSize, 16);
}
$messageBlocks=$ct; // ciphertext is now array of block-length strings
// plaintext will get generated block-by-block into array of block-length strings
$retArr=array();

for($b=0; $b<$nBlocks; $b++){


// set counter (block #) in last 8 bytes of counter block (leaving nonce in
1st 8 bytes)
for($c=0; $c<4; $c++){
$counterBlock[15-$c]=self::urs($b, $c*8)&0xff;
}
for($c=0; $c<4; $c++){
$counterBlock[15-$c-4]=self::urs(($b+1)/0x100000000-1, $c*8)&0xff;
}
$cipherCntr=self::cipher($counterBlock, $keySchedule); // encrypt counter
block

$retButeArr=array();
for($i=0; $i<strlen($messageBlocks[$b]); $i++){
// -- xor plaintext with ciphered counter byte-by-byte --
$retButeArr[$i]=$cipherCntr[$i]^ord(substr($messageBlocks[$b], $i, 1));
$retButeArr[$i]=chr($retButeArr[$i]);
}
$retArr[$b]=implode('', $retButeArr);
}

// join array of blocks into single plaintext string


return implode('', $retArr);
}

private static function checkNumBitsStandarts($numBits){


if(!($numBits==128||$numBits==192||$numBits==256)){
throw new Exception('standard allows 128/192/256 bit keys');
}
}

/**
* Основная шифрующая функция, основанная на алгоритме Rijndael (Рэндал)
* @param input message as byte-array (16 bytes)
* @param w key schedule as 2D byte-array (Nr+1 x Nb bytes) -
* generated from the cipher key by keyExpansion()
* @return ciphertext as byte-array (16 bytes)
*/
public static function cipher($input, $w){
$Nb=4; // block size (in words): no of columns in state (fixed at
4 for AES)
$Nr=count($w)/$Nb-1; // no of rounds: 10/12/14 for 128/192/256-bit keys

$state=array(); // initialise 4xNb byte-array 'state' with input [§3.4]


for($i=0; $i<4*$Nb; $i++){
$state[$i%4][floor($i/4)]=$input[$i];
}

$state=self::addRoundKey($state, $w, 0, $Nb);

7
for($round=1; $round<$Nr; $round++){ // apply Nr rounds
$state=self::subBytes($state, $Nb);
$state=self::shiftRows($state, $Nb);
$state=self::mixColumns($state, $Nb);
$state=self::addRoundKey($state, $w, $round, $Nb);
}

$state=self::subBytes($state, $Nb);
$state=self::shiftRows($state, $Nb);
$state=self::addRoundKey($state, $w, $Nr, $Nb);

$output=array(4*$Nb); // convert state to 1-d array before returning [§3.4]


for($i=0; $i<4*$Nb; $i++){
$output[$i]=$state[$i%4][floor($i/4)];
}

return $output;
}

/**
* Трансформация при шифровании и обратном шифровании, при которой
* Round Key XOR’ится c State. Длина RoundKey равна размеру
* State(то есть, если Nb = 4, то длина RoundKey равна 128 бит или 16 байт)
* @param int[][] $state таблица State
* @param int[][] $w
* @param int $rnd
* @param int $Nb размер таблицы State
* @return int[][] таблица State
*/
private static function addRoundKey($state, $w, $rnd, $Nb){ // xor Round Key into
state S [§5.1.4]
for($r=0; $r<4; $r++){
for($c=0; $c<$Nb; $c++){
$state[$r][$c] ^= $w[$rnd*4+$c][$r];
}
}
return $state;
}

/**
* Трансформации при шифровании, которые обрабатывают State используя
* нелинейную таблицу замещения байтов(S-box), применяя её независимо к каждому байту
State
* @param int[][] $state таблица State
* @param int $Nb
* @return int[][] таблица State
*/
private static function subBytes($state, $Nb){
for($r=0; $r<4; $r++){
for($c=0; $c<$Nb; $c++){
$state[$r][$c]=self::$sBox[$state[$r][$c]];
}
}
return $state;
}

/**
* Трансформации при шифровании, которые обрабатывают State,
* циклически смещая последние три строки State на разные величины
* @param int[][] $state таблица State
* @param int $Nb
* @return int[][] таблица State
*/

8
private static function shiftRows($state, $Nb){
$t=array(4);
for($r=1; $r<4; $r++){
for($c=0; $c<4; $c++){
$t[$c]=$state[$r][($c+$r)%$Nb]; // shift into temp copy
}

for($c=0; $c<4; $c++){


$state[$r][$c]=$t[$c]; // and copy back
}

} // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for
AES):
return $state; // see
fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
}

/**
* Трансформация при шифровании, которая берет все столбцы State и смешивает
* их данные (независимо друг от друга), чтобы получить новые столбцы
* @param int[][] $state таблица State
* @param int $Nb
* @return int[][] таблица State
*/
private static function mixColumns($state, $Nb){
for($c=0; $c<4; $c++){
$a=array(4); // 'a' is a copy of the current column from 's'
$b=array(4); // 'b' is a•{02} in GF(2^8)
for($i=0; $i<4; $i++){
$a[$i]=$state[$i][$c];
$b[$i]=$state[$i][$c]&0x80 ? $state[$i][$c]<<1^0x011b : $state[$i]
[$c]<<1;
}
// a[n] ^ b[n] is a•{03} in GF(2^8)
$state[0][$c]=$b[0]^$a[1]^$b[1]^$a[2]^$a[3]; // 2*a0 + 3*a1 + a2 + a3
$state[1][$c]=$a[0]^$b[1]^$a[2]^$b[2]^$a[3]; // a0 * 2*a1 + 3*a2 + a3
$state[2][$c]=$a[0]^$a[1]^$b[2]^$a[3]^$b[3]; // a0 + a1 + 2*a2 + 3*a3
$state[3][$c]=$a[0]^$b[0]^$a[1]^$a[2]^$b[3]; // 3*a0 + a1 + a2 + 2*a3
}
return $state;
}

/**
* Key expansion for Rijndael cipher(): performs key expansion on cipher key
* to generate a key schedule
*
* @param key cipher key byte-array (16 bytes)
* @return key schedule as 2D byte-array (Nr+1 x Nb bytes)
*/
public static function keyExpansion($key){ // generate Key Schedule from Cipher Key
[§5.2]
$Nb=4; // block size (in words): no of columns in state (fixed at 4
for AES)
$Nk=count($key)/4; // key length (in words): 4/6/8 for 128/192/256-bit keys
$Nr=$Nk+6; // no of rounds: 10/12/14 for 128/192/256-bit keys

$w=array();
$temp=array();

for($i=0; $i<$Nk; $i++){


$r=array($key[4*$i], $key[4*$i+1], $key[4*$i+2], $key[4*$i+3]);
$w[$i]=$r;
}

9
for($i=$Nk; $i<($Nb*($Nr+1)); $i++){
$w[$i]=array();
for($t=0; $t<4; $t++){
$temp[$t]=$w[$i-1][$t];
}
if($i%$Nk==0){
$temp=self::subWord(self::rotWord($temp));
for($t=0; $t<4; $t++){
$temp[$t] ^= self::$rCon[$i/$Nk][$t];
}
}else if($Nk>6&&$i%$Nk==4){
$temp=self::subWord($temp);
}
for($t=0; $t<4; $t++){
$w[$i][$t]=$w[$i-$Nk][$t]^$temp[$t];
}
}
return $w;
}

/**
* Функция, используемая в процедуре Key Expansion, которая берет на входе
* четырёх-байтное слово и, применяя S-box к каждому из четырёх байтов, выдаёт
выходное слово
* @param int[] $w
* @return int[]
*/
private static function subWord($w){
for($i=0; $i<4; $i++){
$w[$i]=self::$sBox[$w[$i]];
}
return $w;
}

/**
* Функция, использующаяся в процедуре Key Expansion, которая берет 4-х
* байтное слово и производит над ним циклическую перестановку
* @param int[] $w
* @return int[] результат
*/
private static function rotWord($w){
$tmp=$w[0];
for($i=0; $i<3; $i++){
$w[$i]=$w[$i+1];
}
$w[3]=$tmp;
return $w;
}

/**
* Нелинейная таблица замен, использующаяся в нескольких трансформациях
* замены байт и в процедуре Key Expansion для взаимнооднозначной замены значения
байта.
* @var int[]
*/
private static $sBox=array(
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe,
0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c,
0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71,
0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb,
0x27, 0xb2, 0x75,

10
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29,
0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a,
0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50,
0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10,
0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64,
0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde,
0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91,
0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65,
0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b,
0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86,
0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce,
0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0,
0x54, 0xbb, 0x16
);

/**
* Массив, который состоит из битов 32-х разрядного слова и является постоянным для
данного раунда
* @var int[]
*/
private static $rCon=array(
array(0x00, 0x00, 0x00, 0x00),
array(0x01, 0x00, 0x00, 0x00),
array(0x02, 0x00, 0x00, 0x00),
array(0x04, 0x00, 0x00, 0x00),
array(0x08, 0x00, 0x00, 0x00),
array(0x10, 0x00, 0x00, 0x00),
array(0x20, 0x00, 0x00, 0x00),
array(0x40, 0x00, 0x00, 0x00),
array(0x80, 0x00, 0x00, 0x00),
array(0x1b, 0x00, 0x00, 0x00),
array(0x36, 0x00, 0x00, 0x00)
);

/**
* Unsigned right shift function, since PHP has neither >>> operator nor unsigned
ints
*
* @param a number to be shifted (32-bit integer)
* @param b number of bits to shift a to the right (0..31)
* @return a right-shifted and zero-filled by b bits
*/
private static function urs($a, $b){
$a &= 0xffffffff;
$b &= 0x1f; // (bounds check)
if($a&0x80000000&&$b>0){ // if left-most bit set
$a=($a>>1)&0x7fffffff; // right-shift one bit & clear left-most bit
$a=$a>>($b-1); // remaining right-shifts
}else{ // otherwise
$a=($a>>$b); // use normal right-shift
}
return $a;
}

11
}

Передача зашифрованного сообщения по сети


Принимающая сторона
<?php

require_once './config.php';

use awa\util\csm\Server;
use awa\util\csm\Socket;
use awa\secure\symmetric\Encryption;

initAutoload('./classes');

/**
* @param string[] $args
*/
function main($args){

$server=Server::createLocal($args[1]);
/* @var $encryption Encryption */
$encryption=newEncryptInstance($args[2]);
$key=$args[3];

$server->setBlockMode(true);
$server->setTimeout(86400);

$server->setOnAccept(function(Socket $client)use($encryption, $key){


echo 'Подключился клиент. Ожидаем зашифрованное сообщение... ';
$message=$client->read();
echo 'Сообщение получено:'."\n---";
echo binaryToHexString($message, true)."\n---\n\n";

echo 'Дешифрованное сообщение'."\n---\n";


echo $encryption->decode($key, $message)."\n---\n\n";

echo 'Закрываем соединение с клиентом... ';


$client->close();
echo 'Соединение закрыто'."\n";
});

echo 'Сервер запущен.'."\n";


$server->start();

main($argv);

Посылающая сторона
<?php

require_once './config.php';

12
use awa\util\csm\Client;
use awa\secure\symmetric\Encryption;

initAutoload('./classes');

/**
* @param string[] $args
*/
function main($args){

echo 'Подключаемся к серверу... ';


$client=new Client($args[1], $args[2]);
/* @var $encryption Encryption */
$encryption=newEncryptInstance($args[3]);

$message=$encryption->encode($args[4], $args[5]);

$client->setBlockMode(true);
echo 'Соединение с сервером установлено.'."\n";
echo 'Зашифрованное сообщение:'."\n---";
echo binaryToHexString($message, true)."\n---\n\n";
echo 'Отправляем сообщение... ';
$client->write($message);
echo 'Сообщение отправлено.'."\n";
}

main($argv);

Выполнение программы
Клиент был запущен 2 раза

Принимающая сторона
Команда на выполнение:
php client.php 127.0.0.1 8696 awa.secure.symmetric.Aes awesome_key "Это секретное
послание"

Вывод:
Сервер запущен.
Подключился клиент. Ожидаем зашифрованное сообщение... Сообщение получено:
---
5677477a 454b6373 67464e38 6f395942
2b6b736c 5a71624e 4e477335 3148422f
7959656e 336b3965 30764671 486d6674
47517663 7a357454 4e6b676e 65655177
414f303d
---

Дешифрованное сообщение
---
Это секретное послание
---

Закрываем соединение с клиентом... Соединение закрыто


Подключился клиент. Ожидаем зашифрованное сообщение... Сообщение получено:
---

13
74414539 53634173 67464d7a 45614962
36624b73 45445842 4757576a 79425868
4b744944 33433947 4b715832 77647a36
6e777248 68384878 38466435 65747853
6f79413d
---

Дешифрованное сообщение
---
Это секретное послание
---

Закрываем соединение с клиентом... Соединение закрыто

Посылающая сторона
Команда на выполнение:
php server.php 8696 awa.secure.symmetric. Aes awesome_key

Вывод:
Подключаемся к серверу... Соединение с сервером установлено.
Зашифрованное сообщение:
---
5677477a 454b6373 67464e38 6f395942
2b6b736c 5a71624e 4e477335 3148422f
7959656e 336b3965 30764671 486d6674
47517663 7a357454 4e6b676e 65655177
414f303d
---

Отправляем сообщение... Сообщение отправлено.

Подключаемся к серверу... Соединение с сервером установлено.


Зашифрованное сообщение:
---
74414539 53634173 67464d7a 45614962
36624b73 45445842 4757576a 79425868
4b744944 33433947 4b715832 77647a36
6e777248 68384878 38466435 65747853
6f79413d
---

Отправляем сообщение... Сообщение отправлено.

14