AuroraRuntime/Source/Hashing/AuHashStream.cpp

453 lines
14 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuHashStream.cpp
Date: 2021-6-12
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include <tomcrypt.h>
#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<const unsigned char *>(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<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eMD5:
length = 16;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(md5_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eSHA1:
length = 20;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(sha1_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eSHA2_48:
length = 48;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(sha384_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eSHA2_32:
length = 32;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(sha256_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eSHA2_64:
length = 64;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(sha512_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eSHA3_28:
length = 28;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(sha3_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eSHA3_48:
length = 48;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(sha3_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eSHA3_32:
length = 32;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(sha3_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eSHA3_64:
length = 64;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(sha3_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eTiger:
length = 24;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(tiger_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eRMD128:
length = 16;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(rmd128_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eRMD160:
length = 20;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(rmd160_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eRMD256:
length = 32;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(rmd256_done(&this->state_, reinterpret_cast<unsigned char *>(this->buffer_)));
}
return this->buffer_;
case EHashType::eRMD320:
length = 40;
if (!AuExchange(this->bFinished_, true))
{
DIGEST_CHECK(rmd320_done(&this->state_, reinterpret_cast<unsigned char *>(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<AuMemoryViewRead> 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<HashStreamImpl *>(pStream);
}
AUROXTL_INTERFACE_SOO_SRC(HashStream, HashStreamImpl, (EHashType, type))
}