diff --git a/cores/esp8266/HashBuilder.cpp b/cores/esp8266/HashBuilder.cpp new file mode 100644 index 0000000000..f586e937a0 --- /dev/null +++ b/cores/esp8266/HashBuilder.cpp @@ -0,0 +1,94 @@ +#include +#include + +uint8_t HashBuilder::_hexCharToByte(uint8_t c){ + return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) : + (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : + (c >= '0' && c<= '9') ? (c - (uint8_t)'0') : 0; +} + +void HashBuilder::begin(void){ + _init(); +} + +void HashBuilder::add(uint8_t * data, uint16_t len){ + _update(data, len); +} + +void HashBuilder::calculate(void){ + _final(); +} + + +void HashBuilder::addHexString(const char * data){ + uint16_t i, len = strlen(data); + std::unique_ptr tmp(new uint8_t[len/2]); + if(tmp == NULL) { + return; + } + for(i=0; i buf(new uint8_t[BUFFER_SIZE]); + if(!buf){ + return false; + } + + int maxLeft = totalLen; + int bytesAvailable = stream.available(); + while((bytesAvailable > 0) && (maxLeft > 0)) { + + int bytesToRead = bytesAvailable; + if(bytesToRead > maxLeft) bytesToRead = maxLeft ; + if(bytesToRead > BUFFER_SIZE) bytesToRead = BUFFER_SIZE; + + int numBytesRead = stream.readBytes(buf.get(), bytesToRead); + if(numBytesRead<1) { + return false; + } + _update(buf.get(), numBytesRead); + yield(); + + maxLeft -= numBytesRead; + bytesAvailable = stream.available(); + } + return true; +} + +// RESULTS +String HashBuilder::_byteVecToString( std::vector& res){ + String resString; + resString.reserve(res.size()*2); + static constexpr char hex[] = "0123456789abcdef"; + for (uint8_t & c : res){ + resString += String(hex[c / 16]); + resString += String(hex[c % 16]); + } + return resString; +} + +String HashBuilder::toString(){ + return _byteVecToString(_result()); +} + +void HashBuilder::getBytes(uint8_t * output){ + auto res = _result(); + for(uint8_t i = 0; i < res.size(); i++){ + output[i] = res[i]; + } +} + +void HashBuilder::getChars(char * output){ + auto res = _result(); + for(uint8_t i = 0; i < res.size(); i++){ + sprintf(output + (i * 2), "%02x", res[i]); + } +} diff --git a/cores/esp8266/HashBuilder.h b/cores/esp8266/HashBuilder.h new file mode 100644 index 0000000000..7e75abc242 --- /dev/null +++ b/cores/esp8266/HashBuilder.h @@ -0,0 +1,44 @@ +#ifndef __ESP8266_HASH_BUILDER__ +#define __ESP8266_HASH_BUILDER__ + +#include +#include +#include +#include + +class HashBuilder{ + public: + void begin(void); + void add(uint8_t * data, uint16_t len); + void calculate(void); + + void addHexString(const char * data); + bool addStream(Stream & stream, const size_t maxLen); + String toString(void); + + // deprecated + void getBytes(uint8_t * output ); + void getChars(char * output); + + // INLINE + void add(char * data){ add((const char*)data); } + void add(String data){ add(data.c_str()); } + void addHexString(char * data){ addHexString((const char*)data); } + void addHexString(String data){ addHexString(data.c_str()); } + void add(const char * data){ add((uint8_t*)data, strlen(data)); } + + protected: + virtual void _init(void) = 0; + virtual void _update(uint8_t * data, uint16_t len) = 0; + virtual void _final() = 0; + virtual std::vector &_result() = 0; + + uint8_t _hexCharToByte(uint8_t c); + String _byteVecToString( std::vector& v); +}; + +// might be renamed to cryptoBuilder, cause same baseclass +// might be reused in CrpytoSubmodule +typedef HashBuilder CryptoBuilder; + +#endif diff --git a/cores/esp8266/HashBuilder.h.gch b/cores/esp8266/HashBuilder.h.gch new file mode 100644 index 0000000000..e4bf2984d9 Binary files /dev/null and b/cores/esp8266/HashBuilder.h.gch differ diff --git a/cores/esp8266/MD5Builder.cpp b/cores/esp8266/MD5Builder.cpp index ac4fa29ee2..55d19ccc32 100644 --- a/cores/esp8266/MD5Builder.cpp +++ b/cores/esp8266/MD5Builder.cpp @@ -1,101 +1,19 @@ #include #include -uint8_t hex_char_to_byte(uint8_t c) -{ - return (c >= 'a' && c <= 'f') ? (c - ((uint8_t)'a' - 0xa)) : - (c >= 'A' && c <= 'F') ? (c - ((uint8_t)'A' - 0xA)) : - (c >= '0' && c<= '9') ? (c - (uint8_t)'0') : 0; +void MD5Builder::_init(void){ + _resultVector = {}; + MD5Init(&_ctx); + return; } -void MD5Builder::begin(void) -{ - memset(_buf, 0x00, 16); - MD5Init(&_ctx); -} - -void MD5Builder::add(uint8_t * data, uint16_t len) -{ +void MD5Builder::_update(uint8_t * data, uint16_t len){ MD5Update(&_ctx, data, len); + return; } -void MD5Builder::addHexString(const char * data) -{ - uint16_t i, len = strlen(data); - uint8_t * tmp = (uint8_t*)malloc(len/2); - if(tmp == NULL) { - return; - } - for(i=0; i 0) && (maxLengthLeft > 0)) { - - // determine number of bytes to read - int readBytes = bytesAvailable; - if(readBytes > maxLengthLeft) { - readBytes = maxLengthLeft ; // read only until max_len - } - if(readBytes > buf_size) { - readBytes = buf_size; // not read more the buffer can handle - } - - // read data and check if we got something - int numBytesRead = stream.readBytes(buf, readBytes); - if(numBytesRead< 1) { - return false; - } - - // Update MD5 with buffer payload - MD5Update(&_ctx, buf, numBytesRead); - - yield(); // time for network streams - - // update available number of bytes - maxLengthLeft -= numBytesRead; - bytesAvailable = stream.available(); - } - free(buf); - return true; -} - -void MD5Builder::calculate(void) -{ - MD5Final(_buf, &_ctx); -} - -void MD5Builder::getBytes(uint8_t * output) -{ - memcpy(output, _buf, 16); -} - -void MD5Builder::getChars(char * output) -{ - for(uint8_t i = 0; i < 16; i++) { - sprintf(output + (i * 2), "%02x", _buf[i]); - } -} - -String MD5Builder::toString(void) -{ - char out[33]; - getChars(out); - return String(out); +void MD5Builder::_final(void){ + _resultVector.resize(HEX_STR_LEN); + MD5Final(_resultVector.data(), &_ctx); + return; } diff --git a/cores/esp8266/MD5Builder.h b/cores/esp8266/MD5Builder.h index d4e336fca9..261508e839 100644 --- a/cores/esp8266/MD5Builder.h +++ b/cores/esp8266/MD5Builder.h @@ -1,9 +1,10 @@ -/* - md5.h - exposed md5 ROM functions for esp8266 +/* + MD5Builder.h - exposed md5 ROM functions for esp8266 - Copyright (c) 2015 Hristo Gochkov. All rights reserved. + Copyright (c) 2015 Hristo Gochkov, All rights reserved. + Refactored by Sven Eliasson. This file is part of the esp8266 core for Arduino environment. - + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either @@ -18,32 +19,26 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + #ifndef __ESP8266_MD5_BUILDER__ #define __ESP8266_MD5_BUILDER__ #include #include #include "md5.h" +#include "HashBuilder.h" -class MD5Builder { +class MD5Builder : public HashBuilder { private: + const int HEX_STR_LEN = 16; md5_context_t _ctx; - uint8_t _buf[16]; - public: - void begin(void); - void add(uint8_t * data, uint16_t len); - void add(const char * data){ add((uint8_t*)data, strlen(data)); } - void add(char * data){ add((const char*)data); } - void add(String data){ add(data.c_str()); } - void addHexString(const char * data); - void addHexString(char * data){ addHexString((const char*)data); } - void addHexString(String data){ addHexString(data.c_str()); } - bool addStream(Stream & stream, const size_t maxLen); - void calculate(void); - void getBytes(uint8_t * output); - void getChars(char * output); - String toString(void); + void _init(void) override; + void _update(uint8_t * data, uint16_t len) override; + void _final() override; + std::vector &_result(){ return _resultVector;} + std::vector _resultVector = {}; }; + #endif diff --git a/cores/esp8266/MD5Builder.h.gch b/cores/esp8266/MD5Builder.h.gch new file mode 100644 index 0000000000..e4bf2984d9 Binary files /dev/null and b/cores/esp8266/MD5Builder.h.gch differ diff --git a/cores/esp8266/SHA256Builder.cpp b/cores/esp8266/SHA256Builder.cpp new file mode 100644 index 0000000000..6fce1152c0 --- /dev/null +++ b/cores/esp8266/SHA256Builder.cpp @@ -0,0 +1,18 @@ +#include + +void SHA256Builder::_init(void){ + _resultVector = {}; + SHA256_Init(&_ctx); + return; +} + +void SHA256Builder::_update(uint8_t * data, uint16_t len){ + SHA256_Update(&_ctx, data, len); + return; +} + +void SHA256Builder::_final(void){ + _resultVector.resize(HEX_STR_LEN); + SHA256_Final(_resultVector.data(), &_ctx); + return; +} diff --git a/cores/esp8266/SHA256Builder.h b/cores/esp8266/SHA256Builder.h new file mode 100644 index 0000000000..e4eedc70dd --- /dev/null +++ b/cores/esp8266/SHA256Builder.h @@ -0,0 +1,43 @@ +/* + MD5Builder.h - exposed md5 ROM functions for esp8266 + + Copyright (c) 2015 Hristo Gochkov, All rights reserved. + Refactored by Sven Eliasson. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __ESP8266_SHA256_BUILDER__ +#define __ESP8266_SHA256_BUILDER__ + +#include +#include +#include "sha256.h" +#include "HashBuilder.h" + +class SHA256Builder : public HashBuilder { + private: + const int HEX_STR_LEN = 32; + sha256_context_t _ctx; + void _init(void) override; + void _update(uint8_t * data, uint16_t len) override; + void _final() override; + std::vector &_result(){ return _resultVector;} + std::vector _resultVector = {}; +}; + + +#endif diff --git a/cores/esp8266/SHA256Builder.h.gch b/cores/esp8266/SHA256Builder.h.gch new file mode 100644 index 0000000000..e4bf2984d9 Binary files /dev/null and b/cores/esp8266/SHA256Builder.h.gch differ diff --git a/cores/esp8266/hashBuilder.h.gch b/cores/esp8266/hashBuilder.h.gch new file mode 100644 index 0000000000..e4bf2984d9 Binary files /dev/null and b/cores/esp8266/hashBuilder.h.gch differ diff --git a/cores/esp8266/sha256.h b/cores/esp8266/sha256.h new file mode 100644 index 0000000000..f5d1f5c95b --- /dev/null +++ b/cores/esp8266/sha256.h @@ -0,0 +1,25 @@ +#ifndef __ESP8266_SHA256__ +#define __ESP8266_SHA256__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SHA256_SIZE 32 + +typedef struct +{ + uint32_t total[2]; + uint32_t state[8]; + uint8_t buffer[64]; +} sha256_context_t; + +extern void SHA256_Init(sha256_context_t *ctx); +extern void SHA256_Update(sha256_context_t *ctx, const uint8_t * msg, const int len); +extern void SHA256_Final(uint8_t *digest, sha256_context_t *ctx); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/cores/esp8266/sha256.h.gch b/cores/esp8266/sha256.h.gch new file mode 100644 index 0000000000..2e7929b52b Binary files /dev/null and b/cores/esp8266/sha256.h.gch differ diff --git a/tests/host/Makefile b/tests/host/Makefile index a59cff4068..872e2a8777 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -17,7 +17,9 @@ CORE_CPP_FILES := $(addprefix $(CORE_PATH)/,\ FS.cpp \ spiffs_api.cpp \ pgmspace.cpp \ + HashBuilder.cpp \ MD5Builder.cpp \ + SHA256Builder.cpp \ ) CORE_C_FILES := $(addprefix $(CORE_PATH)/,\ @@ -37,6 +39,7 @@ MOCK_CPP_FILES := $(addprefix common/,\ MOCK_C_FILES := $(addprefix common/,\ md5.c \ + sha256.c \ noniso.c \ ) @@ -48,7 +51,9 @@ INC_PATHS += $(addprefix -I, \ TEST_CPP_FILES := \ fs/test_fs.cpp \ core/test_pgmspace.cpp \ + core/test_hashbuilder.cpp \ core/test_md5builder.cpp \ + core/test_sha256builder.cpp \ CXXFLAGS += -std=c++11 -Wall -coverage -O0 -fno-common diff --git a/tests/host/common/sha256.c b/tests/host/common/sha256.c new file mode 100644 index 0000000000..5c9bdaf864 --- /dev/null +++ b/tests/host/common/sha256.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2015, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + #include + #include + #include + + typedef struct + { + uint32_t total[2]; + uint32_t state[8]; + uint8_t buffer[64]; + } SHA256_CTX; + + + +#define GET_UINT32(n,b,i) \ +{ \ + (n) = ((uint32_t) (b)[(i) ] << 24) \ + | ((uint32_t) (b)[(i) + 1] << 16) \ + | ((uint32_t) (b)[(i) + 2] << 8) \ + | ((uint32_t) (b)[(i) + 3] ); \ +} + +#define PUT_UINT32(n,b,i) \ +{ \ + (b)[(i) ] = (uint8_t) ((n) >> 24); \ + (b)[(i) + 1] = (uint8_t) ((n) >> 16); \ + (b)[(i) + 2] = (uint8_t) ((n) >> 8); \ + (b)[(i) + 3] = (uint8_t) ((n) ); \ +} + +static const uint8_t sha256_padding[64] = +{ + 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 +}; + +/** + * Initialize the SHA256 context + */ +void SHA256_Init(SHA256_CTX *ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +static void SHA256_Process(const uint8_t digest[64], SHA256_CTX *ctx) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A, B, C, D, E, F, G, H; + + GET_UINT32(W[0], digest, 0); + GET_UINT32(W[1], digest, 4); + GET_UINT32(W[2], digest, 8); + GET_UINT32(W[3], digest, 12); + GET_UINT32(W[4], digest, 16); + GET_UINT32(W[5], digest, 20); + GET_UINT32(W[6], digest, 24); + GET_UINT32(W[7], digest, 28); + GET_UINT32(W[8], digest, 32); + GET_UINT32(W[9], digest, 36); + GET_UINT32(W[10], digest, 40); + GET_UINT32(W[11], digest, 44); + GET_UINT32(W[12], digest, 48); + GET_UINT32(W[13], digest, 52); + GET_UINT32(W[14], digest, 56); + GET_UINT32(W[15], digest, 60); + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ +( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ +) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + + P(A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98); + P(H, A, B, C, D, E, F, G, W[ 1], 0x71374491); + P(G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF); + P(F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5); + P(E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B); + P(D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1); + P(C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4); + P(B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5); + P(A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98); + P(H, A, B, C, D, E, F, G, W[ 9], 0x12835B01); + P(G, H, A, B, C, D, E, F, W[10], 0x243185BE); + P(F, G, H, A, B, C, D, E, W[11], 0x550C7DC3); + P(E, F, G, H, A, B, C, D, W[12], 0x72BE5D74); + P(D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE); + P(C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7); + P(B, C, D, E, F, G, H, A, W[15], 0xC19BF174); + P(A, B, C, D, E, F, G, H, R(16), 0xE49B69C1); + P(H, A, B, C, D, E, F, G, R(17), 0xEFBE4786); + P(G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6); + P(F, G, H, A, B, C, D, E, R(19), 0x240CA1CC); + P(E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F); + P(D, E, F, G, H, A, B, C, R(21), 0x4A7484AA); + P(C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC); + P(B, C, D, E, F, G, H, A, R(23), 0x76F988DA); + P(A, B, C, D, E, F, G, H, R(24), 0x983E5152); + P(H, A, B, C, D, E, F, G, R(25), 0xA831C66D); + P(G, H, A, B, C, D, E, F, R(26), 0xB00327C8); + P(F, G, H, A, B, C, D, E, R(27), 0xBF597FC7); + P(E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3); + P(D, E, F, G, H, A, B, C, R(29), 0xD5A79147); + P(C, D, E, F, G, H, A, B, R(30), 0x06CA6351); + P(B, C, D, E, F, G, H, A, R(31), 0x14292967); + P(A, B, C, D, E, F, G, H, R(32), 0x27B70A85); + P(H, A, B, C, D, E, F, G, R(33), 0x2E1B2138); + P(G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC); + P(F, G, H, A, B, C, D, E, R(35), 0x53380D13); + P(E, F, G, H, A, B, C, D, R(36), 0x650A7354); + P(D, E, F, G, H, A, B, C, R(37), 0x766A0ABB); + P(C, D, E, F, G, H, A, B, R(38), 0x81C2C92E); + P(B, C, D, E, F, G, H, A, R(39), 0x92722C85); + P(A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1); + P(H, A, B, C, D, E, F, G, R(41), 0xA81A664B); + P(G, H, A, B, C, D, E, F, R(42), 0xC24B8B70); + P(F, G, H, A, B, C, D, E, R(43), 0xC76C51A3); + P(E, F, G, H, A, B, C, D, R(44), 0xD192E819); + P(D, E, F, G, H, A, B, C, R(45), 0xD6990624); + P(C, D, E, F, G, H, A, B, R(46), 0xF40E3585); + P(B, C, D, E, F, G, H, A, R(47), 0x106AA070); + P(A, B, C, D, E, F, G, H, R(48), 0x19A4C116); + P(H, A, B, C, D, E, F, G, R(49), 0x1E376C08); + P(G, H, A, B, C, D, E, F, R(50), 0x2748774C); + P(F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5); + P(E, F, G, H, A, B, C, D, R(52), 0x391C0CB3); + P(D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A); + P(C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F); + P(B, C, D, E, F, G, H, A, R(55), 0x682E6FF3); + P(A, B, C, D, E, F, G, H, R(56), 0x748F82EE); + P(H, A, B, C, D, E, F, G, R(57), 0x78A5636F); + P(G, H, A, B, C, D, E, F, R(58), 0x84C87814); + P(F, G, H, A, B, C, D, E, R(59), 0x8CC70208); + P(E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA); + P(D, E, F, G, H, A, B, C, R(61), 0xA4506CEB); + P(C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7); + P(B, C, D, E, F, G, H, A, R(63), 0xC67178F2); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} + +/** + * Accepts an array of octets as the next portion of the message. + */ +void SHA256_Update(SHA256_CTX *ctx, const uint8_t * msg, int len) +{ + uint32_t left = ctx->total[0] & 0x3F; + uint32_t fill = 64 - left; + + ctx->total[0] += len; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < len) + ctx->total[1]++; + + if (left && len >= fill) + { + memcpy((void *) (ctx->buffer + left), (void *)msg, fill); + SHA256_Process(ctx->buffer, ctx); + len -= fill; + msg += fill; + left = 0; + } + + while (len >= 64) + { + SHA256_Process(msg, ctx); + len -= 64; + msg += 64; + } + + if (len) + { + memcpy((void *) (ctx->buffer + left), (void *) msg, len); + } +} + +/** + * Return the 256-bit message digest into the user's array + */ +void SHA256_Final(uint8_t *digest, SHA256_CTX *ctx) +{ + uint32_t last, padn; + uint32_t high, low; + uint8_t msglen[8]; + + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + PUT_UINT32(high, msglen, 0); + PUT_UINT32(low, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + SHA256_Update(ctx, sha256_padding, padn); + SHA256_Update(ctx, msglen, 8); + + PUT_UINT32(ctx->state[0], digest, 0); + PUT_UINT32(ctx->state[1], digest, 4); + PUT_UINT32(ctx->state[2], digest, 8); + PUT_UINT32(ctx->state[3], digest, 12); + PUT_UINT32(ctx->state[4], digest, 16); + PUT_UINT32(ctx->state[5], digest, 20); + PUT_UINT32(ctx->state[6], digest, 24); + PUT_UINT32(ctx->state[7], digest, 28); +} diff --git a/tests/host/core/test_hashbuilder.cpp b/tests/host/core/test_hashbuilder.cpp new file mode 100644 index 0000000000..8086c0ae9f --- /dev/null +++ b/tests/host/core/test_hashbuilder.cpp @@ -0,0 +1,192 @@ +/* + test_hashBuilder.cpp - HashBuilder tests + Copyright © 2017 Sven Eliasson + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + */ + +#include +#include +#include +#include +#include + + +TEST_CASE("HashLib: can be instantiated"){ + class MockBuilder: public HashBuilder{ + void _init(void){ return;} + void _update(uint8_t * data, uint16_t len){ return;} + void _final(){ return; } + std::vector &_result(){ return resultVec; } + std::vector resultVec = {} ; + public: + bool ok(void){ return true;} + }; + MockBuilder t; + REQUIRE(t.ok()); +} + + +TEST_CASE("HashLib: _byteVecToString Method"){ + class MockBuilder: public HashBuilder{ + void _init(void){ return;} + void _update(uint8_t * data, uint16_t len){ return;} + void _final(){ return; } + std::vector &_result(){ return resultVec; } + std::vector resultVec = {209, 86, 166, 229}; + public: + String test_byteVecToString( std::vector &res){ + return _byteVecToString(res); + } + }; + + MockBuilder t; + std::vector v = {80, 120, 0, 93, 47}; + const String expectedHashString = "5078005d2f"; + REQUIRE( t.test_byteVecToString(v) == expectedHashString); +} + +TEST_CASE("HashLib: toString Method"){ + class MockBuilder: public HashBuilder{ + void _init(void){ return;} + void _update(uint8_t * data, uint16_t len){ return;} + void _final(){ return; } + std::vector &_result(){ return resultVec; } + std::vector resultVec = {209, 86, 166, 229}; + }; + + MockBuilder t; + const String falseHexString = "5078005d2f"; + const String expectedResult = "d156a6e5"; + REQUIRE( t.toString() == expectedResult); + REQUIRE_FALSE( t.toString() == falseHexString ); +} + +TEST_CASE("HashLib: getChars"){ + class MockBuilder: public HashBuilder{ + void _init(void){ return;} + void _update(uint8_t * data, uint16_t len){ return;} + void _final(){ return; } + std::vector &_result(){ return resultVec; } + std::vector resultVec = {209, 86, 166, 229}; + }; + MockBuilder t; + char buff[100]; + t.getChars(buff); + const String expectedResult = "d156a6e5"; + String res = String(buff); + REQUIRE(res == expectedResult); +} + + +TEST_CASE("HashLib: getBytes"){ + class MockBuilder: public HashBuilder{ + void _init(void){ return;} + void _update(uint8_t * data, uint16_t len){ return;} + void _final(){ return; } + std::vector &_result(){ return resultVec; } + public: + std::vector resultVec = {209, 86, 166, 229}; + }; + const String expectedResult = "d156a6e5"; + + MockBuilder t; + uint8_t buff[100]; + t.getBytes(buff); + for( int it = 0; it < 4 ; it++){ + REQUIRE( buff[it] == t.resultVec[it] ); + } +} + +TEST_CASE("HashLib: _hexCharToByte"){ + class MockBuilder: public HashBuilder{ + void _init(void){ return;} + void _update(uint8_t * data, uint16_t len){ return;} + void _final(){ return; } + std::vector &_result(){ return resultVec; } + public: + std::vector resultVec = {209, 86, 166, 229}; + uint8_t test_hexCharToByte(uint8_t c){ + return _hexCharToByte(c); + }; + }; + const char hex[] = "0123456789abcdef"; + MockBuilder t; + for(int i = 0; i < 16; i++){ + REQUIRE( t.test_hexCharToByte( hex[i] ) == i ); + } +} + +TEST_CASE("HashLib: addHexString"){ + class MockBuilder: public HashBuilder{ + void _init(void){ return;} + void _update(uint8_t * data, uint16_t len){ + for( int i =0; i < len; i++){ + payloadDump.push_back(data[i]); + } + } + void _final(){ return; } + std::vector &_result(){ return resultVec; } + + public: + std::vector payloadDump; + String returnPayloadDumpAsHex( ){ + return _byteVecToString(payloadDump); + } + std::vector resultVec = {209, 86, 166, 229}; + }; + + MockBuilder t; + SECTION("Using a c-string"){ + char payload[] = "1234567890abcdeffedcba98765432106469676974616c7369676e61747572656170706c69636174696f6e73"; + t.addHexString(payload); + auto str = t.returnPayloadDumpAsHex(); + REQUIRE( str == payload ); + } + + SECTION("Using a String"){ + const String payload = "1234567890abcdeffedcba98765432106469676974616c7369676e61747572656170706c69636174696f6e73"; + t.addHexString(payload); + auto str = t.returnPayloadDumpAsHex(); + REQUIRE( str == payload ); + } +} + + + TEST_CASE("HashLib: addStream"){ + class MockBuilder: public HashBuilder{ + void _init(void){ return;} + void _update(uint8_t * data, uint16_t len){ + for( int i =0; i < len; i++){ + payloadDump.push_back(data[i]); + } + } + void _final(){ return; } + std::vector &_result(){ return resultVec; } + + public: + std::vector resultVec = {209, 86, 166, 229}; + std::vector payloadDump; + }; + + MockBuilder t; + const char* payload = "HASHLIB::addStream_works_longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"; + StreamString stream; + stream.print(payload); + t.addStream(stream, stream.available()); + + String reRead = ""; + for( auto c : t.payloadDump ){ + reRead += char(c); + } + REQUIRE( reRead == String(payload) ); + +} diff --git a/tests/host/core/test_md5builder.cpp b/tests/host/core/test_md5builder.cpp index f8ce5ed126..023afc2a9c 100644 --- a/tests/host/core/test_md5builder.cpp +++ b/tests/host/core/test_md5builder.cpp @@ -17,6 +17,7 @@ #include #include #include +#include TEST_CASE("MD5Builder::add works as expected", "[core][MD5Builder]") { @@ -24,8 +25,10 @@ TEST_CASE("MD5Builder::add works as expected", "[core][MD5Builder]") builder.begin(); builder.add("short"); builder.calculate(); + std::cout << "String" << builder.toString().c_str() << std::endl; REQUIRE(builder.toString() == "4f09daa9d95bcb166a302407a0e0babe"); + builder.begin(); builder.add("longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"); builder.calculate(); diff --git a/tests/host/core/test_sha256builder.cpp b/tests/host/core/test_sha256builder.cpp new file mode 100644 index 0000000000..b422c8c363 --- /dev/null +++ b/tests/host/core/test_sha256builder.cpp @@ -0,0 +1,72 @@ +/* + test_md5builder.cpp - MD5Builder tests + Copyright © 2016 Ivan Grokhotkov + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + */ + +#include +#include +#include +#include + +TEST_CASE("SHA256Builder::add works as expected", "[core][SHA256Builder]") +{ + SHA256Builder builder; + builder.begin(); + builder.add("short"); + builder.calculate(); + REQUIRE(builder.toString() == "f9b0078b5df596d2ea19010c001bbd009e651de2c57e8fb7e355f31eb9d3f739"); + + builder.begin(); + builder.add("longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"); + builder.calculate(); + REQUIRE(builder.toString() == "0435a3add4cc74a0b15d05f9b7c53b6773f8b062735343a7f8128c28d8e1e4a4"); +} + + +TEST_CASE("SHA256Builder::addHexString works as expected", "[core][SHA256Builder]") +{ + SHA256Builder builder; + builder.begin(); + builder.addHexString("1234567890abcdeffedcba98765432106469676974616c7369676e61747572656170706c69636174696f6e73"); + builder.calculate(); + REQUIRE(builder.toString() == "a2526a45572e9d0b3e97b1bbd1f23fe79d93297f787f78e2df84021cd0ff03bf"); +} + +TEST_CASE("SHA256Builder::addStream works", "[core][SHA256Builder]"){ + SHA256Builder builder; + const char* str = "MD5Builder::addStream_works_longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"; + { + StreamString stream; + stream.print(str); + builder.begin(); + REQUIRE( builder.addStream(stream, stream.available()) ); + builder.calculate(); + REQUIRE(builder.toString() == "12d9e218343a2cfda7e966591c3a858db66db2a47f253711c1c6d34a57128ad9"); + } + { + StreamString stream; + stream.print(str); + builder.begin(); + REQUIRE( builder.addStream(stream, 20)) ; + builder.calculate(); + REQUIRE(builder.toString() == "d1417bbca9aa9454a7a70fd05aa72e1fab385d1aee1785d37d36f7df4513430a"); + } + { + StreamString stream; + stream.print(str); + builder.begin(); + REQUIRE( builder.addStream(stream, 120)); + builder.calculate(); + REQUIRE(builder.toString() == "12d9e218343a2cfda7e966591c3a858db66db2a47f253711c1c6d34a57128ad9"); + } +}