diff --git a/Foundation/Makefile b/Foundation/Makefile index 82a460929..d9c7af191 100644 --- a/Foundation/Makefile +++ b/Foundation/Makefile @@ -21,7 +21,7 @@ objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel \ NullStream NumberFormatter NumberParser NumericString AbstractObserver \ Path PatternFormatter Process PurgeStrategy RWLock Random RandomStream \ DirectoryIteratorStrategy RegularExpression RefCountedObject Runnable RotateStrategy \ - SHA1Engine Semaphore SharedLibrary SimpleFileChannel \ + SHA1Engine SHA2Engine Semaphore SharedLibrary SimpleFileChannel \ SignalHandler SplitterChannel SortedDirectoryIterator Stopwatch StreamChannel \ StreamConverter StreamCopier StreamTokenizer String StringTokenizer SynchronizedObject \ Task TaskManager TaskNotification TeeStream Hash HashStatistic \ @@ -30,7 +30,7 @@ objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel \ FileStreamFactory URIStreamFactory URIStreamOpener UTF32Encoding UTF16Encoding UTF8Encoding UTF8String \ Unicode UnicodeConverter Windows1250Encoding Windows1251Encoding Windows1252Encoding \ UUID UUIDGenerator Void Var VarHolder VarIterator Format Pipe PipeImpl PipeStream SharedMemory \ - MemoryStream FileStream AtomicCounter + MemoryStream FileStream AtomicCounter zlib_objects = adler32 compress crc32 deflate \ infback inffast inflate inftrees trees zutil diff --git a/Foundation/include/Poco/SHA2Engine.h b/Foundation/include/Poco/SHA2Engine.h new file mode 100644 index 000000000..803cdff70 --- /dev/null +++ b/Foundation/include/Poco/SHA2Engine.h @@ -0,0 +1,72 @@ +// +// SHA2Engine.h +// +// Library: Foundation +// Package: Crypt +// Module: SHA2Engine +// +// Definition of class SHA2Engine. +// +// Secure Hash Standard SHA-2 algorithm +// (FIPS 180-4, see http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf) +// +// Based on the implementation of mbed TLS (Apache 2.0) +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Copyright (c) 2017, Applied Informatics Software Engineering GmbH +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Foundation_SHA2Engine_INCLUDED +#define Foundation_SHA2Engine_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/DigestEngine.h" + + +namespace Poco { + + +class Foundation_API SHA2Engine: public DigestEngine + /// This class implements the SHA-2 message digest algorithm. + /// (FIPS 180-4, see http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf) +{ +public: + enum ALGORITHM + { + SHA_224 = 224, + SHA_256 = 256, + SHA_384 = 384, + SHA_512 = 512 + }; + + SHA2Engine(ALGORITHM algorithm = SHA_256); + ~SHA2Engine(); + + std::size_t digestLength() const; + void reset(); + const DigestEngine::Digest& digest(); + +protected: + void updateImpl(const void* data, std::size_t length); + +private: + void transform(); + + void* _context; + ALGORITHM _algorithm; + DigestEngine::Digest _digest; + + SHA2Engine(const SHA2Engine&); + SHA2Engine& operator = (const SHA2Engine&); +}; + + +} // namespace Poco + + +#endif // Foundation_SHA2Engine_INCLUDED diff --git a/Foundation/src/SHA2Engine.cpp b/Foundation/src/SHA2Engine.cpp new file mode 100644 index 000000000..7ab454218 --- /dev/null +++ b/Foundation/src/SHA2Engine.cpp @@ -0,0 +1,487 @@ +// +// SHA2Engine.cpp +// +// Library: Foundation +// Package: Crypt +// Module: SHA2Engine +// +// Code of class SHA2Engine. +// +// Secure Hash Standard SHA-2 algorithm +// (FIPS 180-4, see http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf) +// +// Based on the implementation of mbed TLS (Apache 2.0) +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Copyright (c) 2017, Applied Informatics Software Engineering GmbH +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "Poco/SHA2Engine.h" +#include + + +namespace Poco { + + +typedef struct +{ + union + { + Poco::UInt32 total32[4]; + Poco::UInt64 total64[2]; + } total; + + union + { + Poco::UInt32 state32[16]; + Poco::UInt64 state64[8]; + } state; + + SHA2Engine::ALGORITHM size; + unsigned char buffer[128]; +} HASHCONTEXT; + + +static const Poco::UInt32 K32[] = +{ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, +}; + + +#if defined(_MSC_VER) || defined(__WATCOMC__) +#define UL64(x) x##ui64 +#else +#define UL64(x) x##ULL +#endif + + +static const Poco::UInt64 K64[80] = +{ + UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD), + UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC), + UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019), + UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118), + UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE), + UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2), + UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1), + UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694), + UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3), + UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65), + UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483), + UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5), + UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210), + UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4), + UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725), + UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70), + UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926), + UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF), + UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8), + UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B), + UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001), + UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30), + UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910), + UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8), + UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53), + UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8), + UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB), + UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3), + UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60), + UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC), + UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9), + UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B), + UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207), + UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178), + UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6), + UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B), + UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493), + UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C), + UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A), + UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817) +}; + + +static const unsigned char padding[128] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + +#define SHR32(x,n) ((x & 0xFFFFFFFF) >> n) +#define SHR64(x,n) (x >> n) +#define ROTR32(x,n) (SHR32(x,n) | (x << (32 - n))) +#define ROTR64(x,n) (SHR64(x,n) | (x << (64 - n))) +#define S320(x) (ROTR32(x, 7) ^ ROTR32(x,18) ^ SHR32(x, 3)) +#define S321(x) (ROTR32(x,17) ^ ROTR32(x,19) ^ SHR32(x,10)) +#define S322(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x,22)) +#define S323(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x,25)) +#define S640(x) (ROTR64(x, 1) ^ ROTR64(x, 8) ^ SHR64(x, 7)) +#define S641(x) (ROTR64(x,19) ^ ROTR64(x,61) ^ SHR64(x, 6)) +#define S642(x) (ROTR64(x,28) ^ ROTR64(x,34) ^ ROTR64(x,39)) +#define S643(x) (ROTR64(x,14) ^ ROTR64(x,18) ^ ROTR64(x,41)) +#define F320(x,y,z) ((x & y) | (z & (x | y))) +#define F321(x,y,z) (z ^ (x & (y ^ z))) +#define F640(x,y,z) ((x & y) | (z & (x | y))) +#define F641(x,y,z) (z ^ (x & (y ^ z))) +#define R32(t) (W[t] = S321(W[t - 2]) + W[t - 7] + S320(W[t - 15]) + W[t - 16]) +#define P32(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S323(e) + F321(e,f,g) + K + x; \ + temp2 = S322(a) + F320(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} +#define P64(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S643(e) + F641(e,f,g) + K + x; \ + temp2 = S642(a) + F640(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} +#ifdef POCO_ARCH_BIG_ENDIAN +#ifndef GET_UINT32 +#define GET_UINT32(n,b,i) \ +do { \ + (n) = ( (Poco::UInt32) (b)[(i) ] ) \ + | ( (Poco::UInt32) (b)[(i) + 1] << 8 ) \ + | ( (Poco::UInt32) (b)[(i) + 2] << 16 ) \ + | ( (Poco::UInt32) (b)[(i) + 3] << 24 ); \ +} while( 0 ) +#endif +#ifndef PUT_UINT32 +#define PUT_UINT32(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} while( 0 ) +#endif +#ifndef GET_UINT64 +#define GET_UINT64(n,b,i) \ +{ \ + (n) = ( (Poco::UInt64) (b)[(i) ] ) \ + | ( (Poco::UInt64) (b)[(i) + 1] << 8 ) \ + | ( (Poco::UInt64) (b)[(i) + 2] << 16 ) \ + | ( (Poco::UInt64) (b)[(i) + 3] << 24 ) \ + | ( (Poco::UInt64) (b)[(i) + 4] << 32 ) \ + | ( (Poco::UInt64) (b)[(i) + 5] << 40 ) \ + | ( (Poco::UInt64) (b)[(i) + 6] << 48 ) \ + | ( (Poco::UInt64) (b)[(i) + 7] << 56 ); \ +} +#endif +#ifndef PUT_UINT64 +#define PUT_UINT64(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 7] = (unsigned char) ( (n) >> 56 ); \ +} +#endif +#else +#ifndef GET_UINT32 +#define GET_UINT32(n,b,i) \ +do { \ + (n) = ( (Poco::UInt32) (b)[(i) ] << 24 ) \ + | ( (Poco::UInt32) (b)[(i) + 1] << 16 ) \ + | ( (Poco::UInt32) (b)[(i) + 2] << 8 ) \ + | ( (Poco::UInt32) (b)[(i) + 3] ); \ +} while( 0 ) +#endif +#ifndef PUT_UINT32 +#define PUT_UINT32(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} while( 0 ) +#endif +#ifndef GET_UINT64 +#define GET_UINT64(n,b,i) \ +{ \ + (n) = ( (Poco::UInt64) (b)[(i) ] << 56 ) \ + | ( (Poco::UInt64) (b)[(i) + 1] << 48 ) \ + | ( (Poco::UInt64) (b)[(i) + 2] << 40 ) \ + | ( (Poco::UInt64) (b)[(i) + 3] << 32 ) \ + | ( (Poco::UInt64) (b)[(i) + 4] << 24 ) \ + | ( (Poco::UInt64) (b)[(i) + 5] << 16 ) \ + | ( (Poco::UInt64) (b)[(i) + 6] << 8 ) \ + | ( (Poco::UInt64) (b)[(i) + 7] ); \ +} +#endif +#ifndef PUT_UINT64 +#define PUT_UINT64(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 7] = (unsigned char) ( (n) ); \ +} +#endif +#endif + + +SHA2Engine::SHA2Engine(ALGORITHM algorithm): + _context(NULL), + _algorithm(algorithm) +{ + _digest.reserve(digestLength()); + reset(); +} + + +SHA2Engine::~SHA2Engine() +{ + reset(); + free(_context); +} + + +void _sha256_process(HASHCONTEXT* pContext, const unsigned char data[64]) +{ + unsigned int i; + Poco::UInt32 temp1, temp2, temp3[8], W[64]; + for (i = 0; i < 8; i++) temp3[i] = pContext->state.state32[i]; + for (i = 0; i < 16; i++) { GET_UINT32(W[i], data, 4 * i); } + for (i = 0; i < 16; i += 8) + { + P32(temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], W[i + 0], K32[i + 0]); + P32(temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], W[i + 1], K32[i + 1]); + P32(temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], W[i + 2], K32[i + 2]); + P32(temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], W[i + 3], K32[i + 3]); + P32(temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], W[i + 4], K32[i + 4]); + P32(temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], W[i + 5], K32[i + 5]); + P32(temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], W[i + 6], K32[i + 6]); + P32(temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], W[i + 7], K32[i + 7]); + } + for (i = 16; i < 64; i += 8) + { + P32(temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], R32(i + 0), K32[i + 0]); + P32(temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], R32(i + 1), K32[i + 1]); + P32(temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], R32(i + 2), K32[i + 2]); + P32(temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], R32(i + 3), K32[i + 3]); + P32(temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], R32(i + 4), K32[i + 4]); + P32(temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], R32(i + 5), K32[i + 5]); + P32(temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], R32(i + 6), K32[i + 6]); + P32(temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], R32(i + 7), K32[i + 7]); + } + for (i = 0; i < 8; i++) pContext->state.state32[i] += temp3[i]; +} + + +void _sha512_process(HASHCONTEXT* pContext, const unsigned char data[128]) +{ + int i; + Poco::UInt64 temp1, temp2, temp3[8], W[80]; + for (i = 0; i < 16; i++) { GET_UINT64(W[i], data, i << 3); } + for (; i < 80; i++) { W[i] = S641(W[i - 2]) + W[i - 7] + S640(W[i - 15]) + W[i - 16]; } + for (i = 0; i < 8; i++) temp3[i] = pContext->state.state64[i]; + i = 0; + do + { + P64(temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], W[i], K64[i]); i++; + P64(temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], W[i], K64[i]); i++; + P64(temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], W[i], K64[i]); i++; + P64(temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], temp3[4], W[i], K64[i]); i++; + P64(temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], temp3[3], W[i], K64[i]); i++; + P64(temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], temp3[2], W[i], K64[i]); i++; + P64(temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], temp3[1], W[i], K64[i]); i++; + P64(temp3[1], temp3[2], temp3[3], temp3[4], temp3[5], temp3[6], temp3[7], temp3[0], W[i], K64[i]); i++; + } while (i < 80); + for (i = 0; i < 8; i++) pContext->state.state64[i] += temp3[i]; +} + + +void SHA2Engine::updateImpl(const void* buffer_, std::size_t count) +{ + if (_context == NULL || buffer_ == NULL || count == 0) return; + Poco::UInt32 left = 0; + HASHCONTEXT* pContext = (HASHCONTEXT*)_context; + unsigned char* data = (unsigned char*)buffer_; + if (pContext->size > SHA_256) + { + left = (Poco::UInt32)(pContext->total.total64[0] & 0x7F); + size_t fill = 128 - left; + pContext->total.total64[0] += (Poco::UInt64)count; + if (pContext->total.total64[0] < (Poco::UInt64)count) pContext->total.total64[1]++; + if (left && count >= fill) + { + memcpy((void *)(pContext->buffer + left), data, fill); + _sha512_process(pContext, pContext->buffer); + data += fill; + count -= fill; + left = 0; + } + while (count >= 128) + { + _sha512_process(pContext, data); + data += 128; + count -= 128; + } + } + else + { + left = (Poco::UInt32)(pContext->total.total32[0] & 0x3F); + size_t fill = 64 - left; + pContext->total.total32[0] += (Poco::UInt32)count; + pContext->total.total32[0] &= 0xFFFFFFFF; + if (pContext->total.total32[0] < (Poco::UInt32)count) pContext->total.total32[1]++; + if (left && count >= fill) + { + memcpy((void *)(pContext->buffer + left), data, fill); + _sha256_process(pContext, pContext->buffer); + data += fill; + count -= fill; + left = 0; + } + while (count >= 64) + { + _sha256_process(pContext, data); + data += 64; + count -= 64; + } + } + if (count > 0) memcpy((void *)(pContext->buffer + left), data, count); +} + + +std::size_t SHA2Engine::digestLength() const +{ + return (size_t)((int)_algorithm / 8); +} + + +void SHA2Engine::reset() +{ + if (_context != NULL) free(_context); + _context = calloc(1, sizeof(HASHCONTEXT)); + HASHCONTEXT* pContext = (HASHCONTEXT*)_context; + pContext->size = _algorithm; + if (_algorithm == SHA_224) + { + pContext->state.state32[0] = 0xC1059ED8; + pContext->state.state32[1] = 0x367CD507; + pContext->state.state32[2] = 0x3070DD17; + pContext->state.state32[3] = 0xF70E5939; + pContext->state.state32[4] = 0xFFC00B31; + pContext->state.state32[5] = 0x68581511; + pContext->state.state32[6] = 0x64F98FA7; + pContext->state.state32[7] = 0xBEFA4FA4; + } + else if (_algorithm == SHA_256) + { + pContext->state.state32[0] = 0x6A09E667; + pContext->state.state32[1] = 0xBB67AE85; + pContext->state.state32[2] = 0x3C6EF372; + pContext->state.state32[3] = 0xA54FF53A; + pContext->state.state32[4] = 0x510E527F; + pContext->state.state32[5] = 0x9B05688C; + pContext->state.state32[6] = 0x1F83D9AB; + pContext->state.state32[7] = 0x5BE0CD19; + } + else if (_algorithm == SHA_384) + { + pContext->state.state64[0] = UL64(0xCBBB9D5DC1059ED8); + pContext->state.state64[1] = UL64(0x629A292A367CD507); + pContext->state.state64[2] = UL64(0x9159015A3070DD17); + pContext->state.state64[3] = UL64(0x152FECD8F70E5939); + pContext->state.state64[4] = UL64(0x67332667FFC00B31); + pContext->state.state64[5] = UL64(0x8EB44A8768581511); + pContext->state.state64[6] = UL64(0xDB0C2E0D64F98FA7); + pContext->state.state64[7] = UL64(0x47B5481DBEFA4FA4); + } + else + { + pContext->state.state64[0] = UL64(0x6A09E667F3BCC908); + pContext->state.state64[1] = UL64(0xBB67AE8584CAA73B); + pContext->state.state64[2] = UL64(0x3C6EF372FE94F82B); + pContext->state.state64[3] = UL64(0xA54FF53A5F1D36F1); + pContext->state.state64[4] = UL64(0x510E527FADE682D1); + pContext->state.state64[5] = UL64(0x9B05688C2B3E6C1F); + pContext->state.state64[6] = UL64(0x1F83D9ABFB41BD6B); + pContext->state.state64[7] = UL64(0x5BE0CD19137E2179); + } +} + + +const DigestEngine::Digest& SHA2Engine::digest() +{ + _digest.clear(); + if (_context == NULL) return _digest; + HASHCONTEXT* pContext = (HASHCONTEXT*)_context; + size_t last, padn; + unsigned char hash[64]; + memset(hash, 0, 64); + if (pContext->size > SHA_256) + { + unsigned char msglen[16]; + Poco::UInt64 high = (pContext->total.total64[0] >> 61) | (pContext->total.total64[1] << 3); + Poco::UInt64 low = (pContext->total.total64[0] << 3); + PUT_UINT64(high, msglen, 0); + PUT_UINT64(low, msglen, 8); + last = (size_t)(pContext->total.total64[0] & 0x7F); + padn = (last < 112) ? (112 - last) : (240 - last); + updateImpl(padding, padn); + updateImpl(msglen, 16); + PUT_UINT64(pContext->state.state64[0], hash, 0); + PUT_UINT64(pContext->state.state64[1], hash, 8); + PUT_UINT64(pContext->state.state64[2], hash, 16); + PUT_UINT64(pContext->state.state64[3], hash, 24); + PUT_UINT64(pContext->state.state64[4], hash, 32); + PUT_UINT64(pContext->state.state64[5], hash, 40); + if (pContext->size > SHA_384) + { + PUT_UINT64(pContext->state.state64[6], hash, 48); + PUT_UINT64(pContext->state.state64[7], hash, 56); + } + } + else + { + unsigned char msglen[8]; + Poco::UInt32 high = (pContext->total.total32[0] >> 29) | (pContext->total.total32[1] << 3); + Poco::UInt32 low = (pContext->total.total32[0] << 3); + PUT_UINT32(high, msglen, 0); + PUT_UINT32(low, msglen, 4); + last = pContext->total.total32[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + updateImpl(padding, padn); + updateImpl(msglen, 8); + PUT_UINT32(pContext->state.state32[0], hash, 0); + PUT_UINT32(pContext->state.state32[1], hash, 4); + PUT_UINT32(pContext->state.state32[2], hash, 8); + PUT_UINT32(pContext->state.state32[3], hash, 12); + PUT_UINT32(pContext->state.state32[4], hash, 16); + PUT_UINT32(pContext->state.state32[5], hash, 20); + PUT_UINT32(pContext->state.state32[6], hash, 24); + if (pContext->size > SHA_224) PUT_UINT32(pContext->state.state32[7], hash, 28); + } + _digest.insert(_digest.begin(), hash, hash + digestLength()); + reset(); + return _digest; +} + + +} // namespace Poco diff --git a/Foundation/testsuite/Makefile-Driver b/Foundation/testsuite/Makefile-Driver index 3eacc7525..46d83251b 100644 --- a/Foundation/testsuite/Makefile-Driver +++ b/Foundation/testsuite/Makefile-Driver @@ -21,7 +21,7 @@ objects = ActiveMethodTest ActivityTest ActiveDispatcherTest \ PriorityNotificationQueueTest TimedNotificationQueueTest \ NotificationsTestSuite NullStreamTest NumberFormatterTest \ NumberParserTest PathTest PatternFormatterTest PBKDF2EngineTest RWLockTest \ - RandomStreamTest RandomTest RegularExpressionTest SHA1EngineTest \ + RandomStreamTest RandomTest RegularExpressionTest SHA1EngineTest SHA2EngineTest \ SemaphoreTest ConditionTest SharedLibraryTest SharedLibraryTestSuite \ SimpleFileChannelTest StopwatchTest \ StreamConverterTest StreamCopierTest StreamTokenizerTest \ diff --git a/Foundation/testsuite/src/CryptTestSuite.cpp b/Foundation/testsuite/src/CryptTestSuite.cpp index 5808302c8..780cf3ec6 100644 --- a/Foundation/testsuite/src/CryptTestSuite.cpp +++ b/Foundation/testsuite/src/CryptTestSuite.cpp @@ -12,6 +12,7 @@ #include "MD4EngineTest.h" #include "MD5EngineTest.h" #include "SHA1EngineTest.h" +#include "SHA2EngineTest.h" #include "HMACEngineTest.h" #include "PBKDF2EngineTest.h" #include "DigestStreamTest.h" @@ -26,6 +27,7 @@ CppUnit::Test* CryptTestSuite::suite() pSuite->addTest(MD4EngineTest::suite()); pSuite->addTest(MD5EngineTest::suite()); pSuite->addTest(SHA1EngineTest::suite()); + pSuite->addTest(SHA2EngineTest::suite()); pSuite->addTest(HMACEngineTest::suite()); pSuite->addTest(PBKDF2EngineTest::suite()); pSuite->addTest(DigestStreamTest::suite()); diff --git a/Foundation/testsuite/src/SHA2EngineTest.cpp b/Foundation/testsuite/src/SHA2EngineTest.cpp new file mode 100644 index 000000000..0f32dff9d --- /dev/null +++ b/Foundation/testsuite/src/SHA2EngineTest.cpp @@ -0,0 +1,131 @@ +// +// SHA2EngineTest.cpp +// +// Code of the SHA2EngineTest class. +// +// test vectors from FIPS 180-1 +// +// Copyright (c) 2017, Applied Informatics Software Engineering GmbH +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#include "SHA2EngineTest.h" +#include "Poco/CppUnit/TestCaller.h" +#include "Poco/CppUnit/TestSuite.h" +#include "Poco/SHA2Engine.h" + + +using Poco::SHA2Engine; +using Poco::DigestEngine; + + +SHA2EngineTest::SHA2EngineTest(const std::string& rName): CppUnit::TestCase(rName) +{ +} + + +SHA2EngineTest::~SHA2EngineTest() +{ +} + + +void SHA2EngineTest::testSHA224() +{ + SHA2Engine engine(SHA2Engine::SHA_224); + + engine.update("abc"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"); + + engine.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525"); + + engine.update("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3"); + + for (int i = 0; i < 1000000; ++i) + engine.update('a'); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67"); +} + + +void SHA2EngineTest::testSHA256() +{ + SHA2Engine engine(SHA2Engine::SHA_256); + + engine.update("abc"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + + engine.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); + + engine.update("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1"); + + for (int i = 0; i < 1000000; ++i) + engine.update('a'); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); +} + + +void SHA2EngineTest::testSHA384() +{ + SHA2Engine engine(SHA2Engine::SHA_384); + + engine.update("abc"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"); + + engine.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b"); + + engine.update("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039"); + + for (int i = 0; i < 1000000; ++i) + engine.update('a'); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985"); +} + + +void SHA2EngineTest::testSHA512() +{ + SHA2Engine engine(SHA2Engine::SHA_512); + + engine.update("abc"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"); + + engine.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445"); + + engine.update("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"); + + for (int i = 0; i < 1000000; ++i) + engine.update('a'); + assertTrue (DigestEngine::digestToHex(engine.digest()) == "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"); +} + + +void SHA2EngineTest::setUp() +{ +} + + +void SHA2EngineTest::tearDown() +{ +} + + +CppUnit::Test* SHA2EngineTest::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("SHA2EngineTest"); + + CppUnit_addTest(pSuite, SHA2EngineTest, testSHA224); + CppUnit_addTest(pSuite, SHA2EngineTest, testSHA256); + CppUnit_addTest(pSuite, SHA2EngineTest, testSHA384); + CppUnit_addTest(pSuite, SHA2EngineTest, testSHA512); + + return pSuite; +} diff --git a/Foundation/testsuite/src/SHA2EngineTest.h b/Foundation/testsuite/src/SHA2EngineTest.h new file mode 100644 index 000000000..be9108e4d --- /dev/null +++ b/Foundation/testsuite/src/SHA2EngineTest.h @@ -0,0 +1,41 @@ +// +// SHA2EngineTest.h +// +// Definition of the SHA2EngineTest class. +// +// Copyright (c) 2017, Applied Informatics Software Engineering GmbH +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef SHA2EngineTest_INCLUDED +#define SHA2EngineTest_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/CppUnit/TestCase.h" + + +class SHA2EngineTest: public CppUnit::TestCase +{ +public: + SHA2EngineTest(const std::string& name); + ~SHA2EngineTest(); + + void testSHA224(); + void testSHA256(); + void testSHA384(); + void testSHA512(); + + void setUp(); + void tearDown(); + + static CppUnit::Test* suite(); + +private: +}; + + +#endif // SHA2EngineTest_INCLUDED