Skip to content

Instantly share code, notes, and snippets.

@abiusx
Created August 15, 2019 16:45
Show Gist options
  • Save abiusx/9f47e60f9f8ddca4631f8869bb28f70b to your computer and use it in GitHub Desktop.
Save abiusx/9f47e60f9f8ddca4631f8869bb28f70b to your computer and use it in GitHub Desktop.
AES 256 CTR based on AES 256 ECB on PHP
<?php
function bin2text($binary)
{
return implode(" ", str_split(bin2hex($binary), 32));
}
function aes_256_ctr($data, $key, $iv, &$counter = 0)
{
assert(strlen($data)%32 == 0);
assert(strlen($iv) == 16);
assert(strlen($key) == 32);
$res = "";
$chunks = str_split($data, 32); //256 bit blocks
foreach ($chunks as $chunk)
{
// Construct 256 bit $nonce_with_counter
$nonce_with_counter = "";
for ($j=0; $j<2;++$j)
{
$nonce = $iv;
$add = $counter;
// adding counter to nonce
for ($i=15; $i>=0 and $add; --$i)
{
if (ord($nonce[$i]) + $add >= 256)
{
$t = (ord($nonce[$i]) + $add);
$nonce[$i] = chr( $t%256 );
$add = (int)($t/256);
}
else
{
$nonce[$i] = chr( ord($nonce[$i]) + $add);
$add = 0;
}
}
$counter++;
$nonce_with_counter.=$nonce;
}
$ecb = openssl_encrypt($nonce_with_counter, 'aes-256-ecb', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
$res .= ($ecb ^ $chunk);
}
return $res;
}
// Testing:
$data = 'A000000000000000000000000000000000000000000000000000000000000000'
. '0000000000000000000000000000000000000000000000000000000000000000'
;
$data=hex2bin($data);
$data = random_bytes(32*100);
$iv = 'A000000000000000000000000000000A'; // 16 bytes
$iv = hex2bin($iv);
$iv = random_bytes(16);
$key = 'A000000000000000000000000000000000F00000000000000000000000000000'; //32 bytes
$key = hex2bin($key);
$key = random_bytes(32);
$ctr = openssl_encrypt($data, 'aes-256-ctr', $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv);
$custom_ctr = aes_256_ctr($data, $key, $iv, $counter);
echo bin2text($custom_ctr), PHP_EOL;
echo "Should be:\n";
echo bin2text($ctr), PHP_EOL;
var_dump($custom_ctr==$ctr);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment