diff --git a/ext/awscrt.c b/ext/awscrt.c index c72b758..ef976bc 100644 --- a/ext/awscrt.c +++ b/ext/awscrt.c @@ -11,5 +11,5 @@ #include "http.c" #include "signing.c" #include "stream.c" -// #include "hash.c" +#include "hash.c" #include "crc.c" diff --git a/ext/awscrt.stub.php b/ext/awscrt.stub.php index b7f7a10..2cdee08 100644 --- a/ext/awscrt.stub.php +++ b/ext/awscrt.stub.php @@ -121,4 +121,16 @@ function aws_crt_sign_request_aws(int $signable, int $signing_config, object $on function aws_crt_crc32(string $input, int $prev): int {} -function aws_crt_crc32c(string $input, int $prev): int {} \ No newline at end of file +function aws_crt_crc32c(string $input, int $prev): int {} + +function aws_crt_sha1_new(): int {} + +function aws_crt_sha256_new(): int {} + +function aws_crt_md5_new(): int {} + +function aws_crt_hash_update(int $hash, string $buffer): int{} + +function aws_crt_hash_digest(int $hash, int $truncate_to, int $length): string {} + +function aws_crt_hash_destroy(int $hash): void {} \ No newline at end of file diff --git a/ext/awscrt_arginfo.h b/ext/awscrt_arginfo.h index 7923b3d..b59084e 100644 --- a/ext/awscrt_arginfo.h +++ b/ext/awscrt_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 36d4e512f02a12c10689eb9b0941bcd7837fbf1d */ + * Stub hash: 271adcfe560a474d149e60d7951a45a93a9259d3 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_last_error, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -235,6 +235,28 @@ ZEND_END_ARG_INFO() #define arginfo_aws_crt_crc32c arginfo_aws_crt_crc32 +#define arginfo_aws_crt_sha1_new arginfo_aws_crt_last_error + +#define arginfo_aws_crt_sha256_new arginfo_aws_crt_last_error + +#define arginfo_aws_crt_md5_new arginfo_aws_crt_last_error + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_hash_update, 0, 2, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, hash, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, buffer, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_hash_digest, 0, 3, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, hash, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, truncate_to, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_aws_crt_hash_destroy, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, hash, IS_LONG, 0) +ZEND_END_ARG_INFO() + + ZEND_FUNCTION(aws_crt_last_error); ZEND_FUNCTION(aws_crt_error_name); ZEND_FUNCTION(aws_crt_error_str); @@ -294,6 +316,12 @@ ZEND_FUNCTION(aws_crt_signing_result_apply_to_http_request); ZEND_FUNCTION(aws_crt_sign_request_aws); ZEND_FUNCTION(aws_crt_crc32); ZEND_FUNCTION(aws_crt_crc32c); +ZEND_FUNCTION(aws_crt_sha1_new); +ZEND_FUNCTION(aws_crt_sha256_new); +ZEND_FUNCTION(aws_crt_md5_new); +ZEND_FUNCTION(aws_crt_hash_update); +ZEND_FUNCTION(aws_crt_hash_digest); +ZEND_FUNCTION(aws_crt_hash_destroy); static const zend_function_entry ext_functions[] = { @@ -356,5 +384,11 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(aws_crt_sign_request_aws, arginfo_aws_crt_sign_request_aws) ZEND_FE(aws_crt_crc32, arginfo_aws_crt_crc32) ZEND_FE(aws_crt_crc32c, arginfo_aws_crt_crc32c) + ZEND_FE(aws_crt_sha1_new, arginfo_aws_crt_sha1_new) + ZEND_FE(aws_crt_sha256_new, arginfo_aws_crt_sha256_new) + ZEND_FE(aws_crt_md5_new, arginfo_aws_crt_md5_new) + ZEND_FE(aws_crt_hash_update, arginfo_aws_crt_hash_update) + ZEND_FE(aws_crt_hash_digest, arginfo_aws_crt_hash_digest) + ZEND_FE(aws_crt_hash_destroy, arginfo_aws_crt_hash_destroy) ZEND_FE_END }; diff --git a/ext/hash.c b/ext/hash.c new file mode 100644 index 0000000..acff398 --- /dev/null +++ b/ext/hash.c @@ -0,0 +1,58 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include "php_aws_crt.h" + +PHP_FUNCTION(aws_crt_sha1_new) { + aws_crt_hash *hash = aws_crt_sha1_new(); + RETURN_LONG((zend_ulong)hash); +} + +PHP_FUNCTION(aws_crt_sha256_new) { + aws_crt_hash *hash = aws_crt_sha256_new(); + RETURN_LONG((zend_ulong)hash); +} + +PHP_FUNCTION(aws_crt_md5_new) { + aws_crt_hash *hash = aws_crt_md5_new(); + RETURN_LONG((zend_ulong)hash); +} + +PHP_FUNCTION(aws_crt_hash_update) { + zend_ulong php_hash = 0; + const char * buffer = NULL; + size_t len = 0; + aws_php_parse_parameters("ls", &php_hash, &buffer, &len); + aws_crt_hash *hash = (void *) php_hash; + RETURN_LONG((zend_ulong) aws_crt_hash_update(hash, (uint8_t *)buffer, (uint32_t) len)); +} + +PHP_FUNCTION(aws_crt_hash_digest) { + zend_ulong php_hash = 0; + size_t truncate_to = 0; + size_t length = 0; + aws_php_parse_parameters("lll", &php_hash, &truncate_to, &length); + aws_crt_hash *hash = (void *) php_hash; + if (truncate_to != 0 && length > truncate_to) { + length = truncate_to; + } + uint8_t *output = aws_crt_hash_digest(hash, truncate_to); + size_t len = strlen((const char *)output) + 1; + char arr[len]; // Make sure there's enough space + strcpy(arr, (char *) output); + printf(arr); + zval *php_output = NULL; + ZVAL_STRINGL(php_output, (const char *)output, length); + aws_mem_release(aws_crt_default_allocator(), output); + // copy false, destroy false? + RETURN_ZVAL(php_output, false, false); +} + +PHP_FUNCTION(aws_crt_hash_destroy) { + zend_ulong php_hash = 0; + aws_php_parse_parameters("l", &php_hash); + aws_crt_hash *hash = (void *) php_hash; + aws_crt_hash_destroy(hash); +} \ No newline at end of file diff --git a/src/AWS/CRT/CRT.php b/src/AWS/CRT/CRT.php index 5410496..74b9cc8 100644 --- a/src/AWS/CRT/CRT.php +++ b/src/AWS/CRT/CRT.php @@ -346,11 +346,35 @@ final class CRT { return self::$impl->aws_crt_sign_request_aws($signable, $signing_config, $on_complete, $user_data); } - public static function crc32($input, $previous = 0) { + function sha1_new() { + return self::$impl->aws_crt_sha1_new(); + } + + function sha256_new() { + return self::$impl->aws_crt_sha256_new(); + } + + function md5_new() { + return self::$impl->aws_crt_md5_new(); + } + + function hash_update($hash, $buffer) { + return self::$impl->aws_crt_hash_update($hash, $buffer); + } + + function hash_digest($hash, $truncate_to, $length) { + return self::$impl->aws_crt_hash_digest($hash, $truncate_to, $length); + } + + function hash_destroy($hash) { + return self::$impl->aws_crt_hash_destroy($hash); + } + + public static function crc32($input, $previous) { return self::$impl->aws_crt_crc32($input, $previous); } - public static function crc32c($input, $previous = 0) { + public static function crc32c($input, $previous) { return self::$impl->aws_crt_crc32c($input, $previous); } } diff --git a/src/AWS/CRT/Cal/Hash.php b/src/AWS/CRT/Cal/Hash.php new file mode 100644 index 0000000..1fd4dd8 --- /dev/null +++ b/src/AWS/CRT/Cal/Hash.php @@ -0,0 +1,41 @@ +hash = $hash; + $this->len = $len; + } + + public static function sha1_new() { + return new Hash(self::$crt->sha1_new(), 20); + } + + public static function sha256_new() { + return new Hash(self::$crt->sha256_new(), 32); + } + + public static function md5_new() { + return new Hash(self::$crt->md5_new(), 16); + } + + public function update($buffer) { + self::$crt->hash_update($this->hash, $buffer); + } + + public function digest($truncate_to) { + return self::$crt->hash_digest($this->hash, $truncate_to, $this->len); + } + + function __destruct() { + self::$crt->hash_destroy($this->hash); + parent::__destruct(); + } +} \ No newline at end of file diff --git a/tests/CrcTest.php b/tests/CrcTest.php index 5c4b5af..72717a4 100644 --- a/tests/CrcTest.php +++ b/tests/CrcTest.php @@ -11,7 +11,7 @@ final class CrcTest extends CrtTestCase { public function testCrc32ZeroesOneShot() { $input = implode(array_map("chr", array_fill(0, 32, 0))); - $output = CRT::crc32($input); + $output = CRT::crc32($input, 0); $expected = 0x190A55AD; $this->assertEquals($output, $expected); } @@ -25,6 +25,54 @@ final class CrcTest extends CrtTestCase { $this->assertEquals($output, $expected); } + public function testCrc32ValuesOneShot() { + $input = implode(array_map("chr", range(0, 31))); + $output = CRT::crc32($input, 0); + $expected = 0x91267E8A; + $this->assertEquals($output, $expected); + } + + public function testCrc32ValuesIterated() { + $output = 0; + foreach (range(0, 31) as $n) { + $output = CRT::crc32(chr($n), $output); + } + $expected = 0x91267E8A; + $this->assertEquals($output, $expected); + } + + public function testCrc32cZeroesOneShot() { + $input = implode(array_map("chr", array_fill(0, 32, 0))); + $output = CRT::crc32c($input, 0); + $expected = 0x8A9136AA; + $this->assertEquals($output, $expected); + } + + public function testCrc32cZeroesIterated() { + $output = 0; + for ($i = 0; $i < 32; $i++) { + $output = CRT::crc32c("\x00", $output); + } + $expected = 0x8A9136AA; + $this->assertEquals($output, $expected); + } + + public function testCrc32cValuesOneShot() { + $input = implode(array_map("chr", range(0, 31))); + $output = CRT::crc32c($input, 0); + $expected = 0x46DD794E; + $this->assertEquals($output, $expected); + } + + public function testCrc32ZeroesIterated() { + $output = 0; + for ($i = 0; $i < 32; $i++) { + $output = CRT::crc32("\x00", $output); + } + $expected = 0x190A55AD; + $this->assertEquals($output, $expected); + } + public function testCrc32ValuesOneShot() { $input = implode(array_map("chr", range(0, 31))); $output = CRT::crc32($input); diff --git a/tests/HashTest.php b/tests/HashTest.php new file mode 100644 index 0000000..be237ba --- /dev/null +++ b/tests/HashTest.php @@ -0,0 +1,20 @@ +digest(0); + $expected = '\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55'; + // $expected = 'test2'; + $this->assertEquals($expected, $digest); + } +} \ No newline at end of file