web-base/test/AesStream.test.php
2022-02-20 16:53:26 +01:00

172 lines
6.2 KiB
PHP

<?php
use Objects\AesStream;
class AesStreamTest extends PHPUnit\Framework\TestCase {
static string $TEMP_FILE;
public static function setUpBeforeClass(): void {
AesStreamTest::$TEMP_FILE = tempnam(sys_get_temp_dir(), 'aesTest');
}
public static function tearDownAfterClass(): void {
unlink(AesStreamTest::$TEMP_FILE);
}
public function testConstructorInvalidKey1() {
$this->expectExceptionMessage("Invalid Key Size");
$this->expectException(\Exception::class);
new AesStream("", "");
}
public function testConstructorInvalidKey2() {
$this->expectExceptionMessage("Invalid Key Size");
$this->expectException(\Exception::class);
new AesStream(str_repeat("A",15), "");
}
public function testConstructorInvalidKey3() {
$this->expectExceptionMessage("Invalid Key Size");
$this->expectException(\Exception::class);
new AesStream(str_repeat("A",33), "");
}
public function testConstructorInvalidIV1() {
$this->expectExceptionMessage("Invalid IV Size");
$this->expectException(\Exception::class);
new AesStream(str_repeat("A",32), str_repeat("B", 17));
}
public function testConstructorValid() {
$key = str_repeat("A",32);
$iv = str_repeat("B", 16);
$aesStream = new AesStream($key, $iv);
$this->assertInstanceOf(AesStream::class, $aesStream);
$this->assertEquals($key, $aesStream->getKey());
$this->assertEquals($iv, $aesStream->getIV());
$this->assertEquals("aes-256-ctr", $aesStream->getCipherMode());
}
private function getOutput(string $chunk, string &$data) {
$data .= $chunk;
}
public function testEncrypt() {
$key = str_repeat("A", 32);
$iv = str_repeat("B", 16);
$aesStream = new AesStream($key, $iv);
$data = [
"43" => "8c", # small block test 1 (1 byte)
"abcd" => "6424", # small block test 2 (2 byte)
"a37c599429cfdefde6546ad6d7082a" => "6c9539264abc8cae39308dbc86e768", # small block test 3 (15 byte)
"43b3504077482bd9bf8c3c08ad3c937f" => "8c5a30f2143b798a60e8db62fcd3d1f7", # one block (16 byte)
"9b241a3d7e9f03f6e66a8fa0cba3221008eda86f465e3fbfb0f3a4d3527cffb7"
=> "54cd7a8f1dec51a5390e68ca9a4c60986aaafadd42b6960a09deedfa7f2cf1c3" # two blocks (16 byte)
];
foreach ($data as $pt => $ct) {
$output = "";
file_put_contents(AesStreamTest::$TEMP_FILE, hex2bin($pt));
$aesStream->setInputFile(AesStreamTest::$TEMP_FILE);
$aesStream->setOutput(function($chunk) use (&$output) { $this->getOutput($chunk, $output); });
$aesStream->start();
$this->assertEquals($ct, bin2hex($output), $ct . " != " . bin2hex($output));
}
}
private function openssl(AesStream $aesStream) {
// check if openssl util produce the same output
$cmd = ["/usr/bin/openssl", $aesStream->getCipherMode(), "-K", bin2hex($aesStream->getKey()), "-iv", bin2hex($aesStream->getIV()), "-in", AesStreamTest::$TEMP_FILE];
$proc = proc_open($cmd, [1 => ["pipe", "w"]], $pipes);
$this->assertTrue(is_resource($proc));
$this->assertTrue(is_resource($pipes[1]));
$output = stream_get_contents($pipes[1]);
proc_close($proc);
return $output;
}
private function testEncryptDecrypt($key, $iv, $inputData) {
$aesStream = new AesStream($key, $iv);
$inputSize = strlen($inputData);
file_put_contents(AesStreamTest::$TEMP_FILE, $inputData);
$output = "";
$aesStream->setInputFile(AesStreamTest::$TEMP_FILE);
$aesStream->setOutput(function($chunk) use (&$output) { $this->getOutput($chunk, $output); });
$aesStream->start();
$this->assertEquals($inputSize, strlen($output));
$this->assertNotEquals($inputData, $output);
// check if openssl util produce the same output
$this->assertEquals($this->openssl($aesStream), $output);
file_put_contents(AesStreamTest::$TEMP_FILE, $output);
$output = "";
$aesStream->setInputFile(AesStreamTest::$TEMP_FILE);
$aesStream->setOutput(function($chunk) use (&$output) { $this->getOutput($chunk, $output); });
$aesStream->start();
$this->assertEquals($inputData, $output);
// check if openssl util produce the same output
$this->assertEquals($this->openssl($aesStream), $output);
}
public function testEncryptDecryptRandom() {
$chunkSize = 65536;
$key = random_bytes(32);
$iv = random_bytes(16);
$inputSize = 10 * $chunkSize;
$inputData = random_bytes($inputSize);
$this->testEncryptDecrypt($key, $iv, $inputData);
}
public function testEncryptDecryptLargeIV() {
$chunkSize = 65536;
$key = random_bytes(32);
$iv = hex2bin(str_repeat("FF", 16));
$inputSize = 10 * $chunkSize;
$inputData = random_bytes($inputSize);
$this->testEncryptDecrypt($key, $iv, $inputData);
}
public function testEncryptDecryptZeroIV() {
$chunkSize = 65536;
$key = random_bytes(32);
$iv = hex2bin(str_repeat("00", 16));
$inputSize = 10 * $chunkSize;
$inputData = random_bytes($inputSize);
$this->testEncryptDecrypt($key, $iv, $inputData);
}
public function testEncryptDecryptPartial() {
$key = random_bytes(32);
$iv = hex2bin(str_repeat("00", 16));
$chunkSize = 65536;
$ranges = [[500,100,200],[10*$chunkSize,100,5*$chunkSize+100],[10*$chunkSize,0,10*$chunkSize],[10*$chunkSize,$chunkSize-1,3*$chunkSize-1]];
foreach ($ranges as $range) {
list ($total, $offset, $length) = $range;
$inputData = random_bytes($total);
file_put_contents(AesStreamTest::$TEMP_FILE, $inputData);
$output = "";
$aesStream = new AesStream($key, $iv);
$aesStream->setRange($offset, $length);
$aesStream->setInputFile(AesStreamTest::$TEMP_FILE);
$aesStream->setOutput(function($chunk) use (&$output) { $this->getOutput($chunk, $output); });
$aesStream->start();
$outputComplete = "";
$aesStream = new AesStream($key, $iv);
$aesStream->setInputFile(AesStreamTest::$TEMP_FILE);
$aesStream->setOutput(function($chunk) use (&$outputComplete) { $this->getOutput($chunk, $outputComplete); });
$aesStream->start();
$this->assertEquals($length, strlen($output), "total=$total offset=$offset length=$length");
$this->assertEquals(substr($outputComplete, $offset, $length), $output, "total=$total offset=$offset length=$length");
}
}
}