/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuHashStream.cpp Date: 2021-6-12 Author: Reece ***/ #include #include #include "AuHashStream.hpp" #if defined(AURORA_COMPILER_CLANG) // warning: enumeration values 'kEnumCount' and 'kEnumInvalid' not handled in switch [-Wswitch #pragma clang diagnostic ignored "-Wswitch" // Yea, I don't give a shit. #endif namespace Aurora::Hashing { #define DIGEST_CHECK(n) SysAssert(n == CRYPT_OK) HashStreamImpl::HashStreamImpl(EHashType type) : type_(type) { if (!EHashTypeIsValid(type)) { AU_THROW_CONST_STRING("Invalid Hash Type"); } Init(); } void HashStreamImpl::Ingest(const Memory::MemoryViewRead &input) { if (this->bFinished_) { return; } auto buffer = reinterpret_cast(input.ptr); auto len = input.length; switch (this->type_) { case EHashType::eMD4: DIGEST_CHECK(md4_process(&this->state_, buffer, len)); break; case EHashType::eMD5: DIGEST_CHECK(md5_process(&this->state_, buffer, len)); break; case EHashType::eSHA1: DIGEST_CHECK(sha1_process(&this->state_, buffer, len)); break; case EHashType::eSHA2_32: DIGEST_CHECK(sha256_process(&this->state_, buffer, len)); break; case EHashType::eSHA2_48: DIGEST_CHECK(sha384_process(&this->state_, buffer, len)); break; case EHashType::eSHA2_64: DIGEST_CHECK(sha512_process(&this->state_, buffer, len)); break; case EHashType::eSHA3_28: case EHashType::eSHA3_48: case EHashType::eSHA3_32: case EHashType::eSHA3_64: DIGEST_CHECK(sha3_process(&this->state_, buffer, len)); break; case EHashType::eTiger: DIGEST_CHECK(tiger_process(&this->state_, buffer, len)); break; case EHashType::eRMD128: DIGEST_CHECK(rmd128_process(&this->state_, buffer, len)); break; case EHashType::eRMD160: DIGEST_CHECK(rmd160_process(&this->state_, buffer, len)); break; case EHashType::eRMD256: DIGEST_CHECK(rmd256_process(&this->state_, buffer, len)); break; case EHashType::eRMD320: DIGEST_CHECK(rmd320_process(&this->state_, buffer, len)); break; } } AuUInt8 const* HashStreamImpl::GetBytes(AuUInt32 &length) { switch (this->type_) { case EHashType::eMD4: length = 16; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(md4_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eMD5: length = 16; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(md5_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eSHA1: length = 20; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(sha1_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eSHA2_48: length = 48; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(sha384_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eSHA2_32: length = 32; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(sha256_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eSHA2_64: length = 64; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(sha512_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eSHA3_28: length = 28; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(sha3_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eSHA3_48: length = 48; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(sha3_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eSHA3_32: length = 32; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(sha3_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eSHA3_64: length = 64; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(sha3_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eTiger: length = 24; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(tiger_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eRMD128: length = 16; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(rmd128_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eRMD160: length = 20; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(rmd160_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eRMD256: length = 32; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(rmd256_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; case EHashType::eRMD320: length = 40; if (!AuExchange(this->bFinished_, true)) { DIGEST_CHECK(rmd320_done(&this->state_, reinterpret_cast(this->buffer_))); } return this->buffer_; } return nullptr; } AuMemoryViewRead HashStreamImpl::Finalize() { AuUInt32 length; auto begin = GetBytes(length); return AuMemoryViewRead(begin, length); } Memory::MemoryViewRead HashStreamImpl::PeekFinalize() { if (this->bFinished_) { return this->Finalize(); } hash_state state; AuMemcpy(&state, &this->state_, sizeof(state)); auto view = this->Finalize(); AuMemcpy(&this->state_, &state, sizeof(state)); this->bFinished_ = false; return view; } AuResult HashStreamImpl::Export() { // Defer to HASH_PROCESS defined in the private libtomcrypt header //this->state_.name.length | bits processed #define ADD_EXPORT(name) \ if (this->state_.name.curlen) \ { \ return {}; \ } \ return AuMemoryViewRead {this->state_.name.state, sizeof(this->state_.name.state)}; switch (this->type_) { case EHashType::eMD4: ADD_EXPORT(md4); case EHashType::eMD5: ADD_EXPORT(md5); case EHashType::eSHA1: ADD_EXPORT(sha1); case EHashType::eSHA2_32: ADD_EXPORT(sha256); case EHashType::eSHA2_48: case EHashType::eSHA2_64: ADD_EXPORT(sha512); case EHashType::eSHA3_28: case EHashType::eSHA3_48: case EHashType::eSHA3_32: case EHashType::eSHA3_64: { if (this->state_.sha3.byte_index) { return {}; } return AuMemoryViewRead(this->state_.sha3.s, &this->state_.sha3.s[this->state_.sha3.word_index]); } case EHashType::eTiger: ADD_EXPORT(tiger); case EHashType::eRMD128: ADD_EXPORT(rmd128); case EHashType::eRMD160: ADD_EXPORT(rmd160); case EHashType::eRMD256: ADD_EXPORT(rmd256); case EHashType::eRMD320: ADD_EXPORT(rmd320); default: return {}; } #undef ADD_EXPORT } bool HashStreamImpl::Import(const Memory::MemoryViewRead &view) { this->bFinished_ = false; #define ADD_IMPORT(name) \ if (sizeof(this->state_.name.state) != view.length) \ { \ SysPushErrorCrypt("Invalid hash state length -> mixed ciphers?"); \ return false; \ } \ AuMemset(&this->state_, 0, sizeof(this->state_)); \ AuMemcpy(this->state_.name.state, view.ptr, sizeof(this->state_.name.state)); \ return true; switch (this->type_) { case EHashType::eMD4: ADD_IMPORT(md4); case EHashType::eMD5: ADD_IMPORT(md5); case EHashType::eSHA1: ADD_IMPORT(sha1); case EHashType::eSHA2_32: ADD_IMPORT(sha256); case EHashType::eSHA2_48: case EHashType::eSHA2_64: ADD_IMPORT(sha512); case EHashType::eSHA3_28: case EHashType::eSHA3_48: case EHashType::eSHA3_32: case EHashType::eSHA3_64: { if (this->state_.sha3.byte_index) { return {}; } if (sizeof(this->state_.sha3.s) < view.length) { return {}; } AuMemcpy(this->state_.sha3.s, view.ptr, view.length); this->state_.sha3.word_index = view.length / 8; return true; } case EHashType::eTiger: ADD_IMPORT(tiger); case EHashType::eRMD128: ADD_IMPORT(rmd128); case EHashType::eRMD160: ADD_IMPORT(rmd160); case EHashType::eRMD256: ADD_IMPORT(rmd256); case EHashType::eRMD320: ADD_IMPORT(rmd320); default: return false; } #undef ADD_IMPORT } void HashStreamImpl::Reset() { Init(); } void HashStreamImpl::Init() { this->bFinished_ = false; AuMemset(&this->state_, 0, sizeof(this->state_)); switch (this->type_) { case EHashType::eMD4: DIGEST_CHECK(md4_init(&this->state_)); break; case EHashType::eMD5: DIGEST_CHECK(md5_init(&this->state_)); break; case EHashType::eSHA1: DIGEST_CHECK(sha1_init(&this->state_)); break; case EHashType::eSHA2_32: DIGEST_CHECK(sha256_init(&this->state_)); break; case EHashType::eSHA2_48: DIGEST_CHECK(sha384_init(&this->state_)); break; case EHashType::eSHA2_64: DIGEST_CHECK(sha512_init(&this->state_)); break; case EHashType::eSHA3_28: DIGEST_CHECK(sha3_224_init(&this->state_)); break; case EHashType::eSHA3_32: DIGEST_CHECK(sha3_256_init(&this->state_)); break; case EHashType::eSHA3_48: DIGEST_CHECK(sha3_384_init(&this->state_)); break; case EHashType::eSHA3_64: DIGEST_CHECK(sha3_512_init(&this->state_)); break; case EHashType::eTiger: DIGEST_CHECK(tiger_init(&this->state_)); break; case EHashType::eRMD128: DIGEST_CHECK(rmd128_init(&this->state_)); break; case EHashType::eRMD160: DIGEST_CHECK(rmd160_init(&this->state_)); break; case EHashType::eRMD256: DIGEST_CHECK(rmd256_init(&this->state_)); break; case EHashType::eRMD320: DIGEST_CHECK(rmd320_init(&this->state_)); break; } } AUKN_SYM IHashStream *HashStreamNew(EHashType type) { if (!EHashTypeIsValid(type)) { return {}; } return _new HashStreamImpl(type); } AUKN_SYM void HashStreamRelease(IHashStream *pStream) { AuSafeDelete(pStream); } AUROXTL_INTERFACE_SOO_SRC(HashStream, HashStreamImpl, (EHashType, type)) }