-
Notifications
You must be signed in to change notification settings - Fork 13.3k
WIP: Add a SHA256Builder #3223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Add a SHA256Builder #3223
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#include <HashBuilder.h> | ||
#include <Arduino.h> | ||
|
||
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<uint8_t[]> tmp(new uint8_t[len/2]); | ||
if(tmp == NULL) { | ||
return; | ||
} | ||
for(i=0; i<len; i+=2) { | ||
uint8_t high = _hexCharToByte(data[i]); | ||
uint8_t low = _hexCharToByte(data[i+1]); | ||
tmp[i/2] = (high & 0x0F) << 4 | (low & 0x0F); | ||
} | ||
add(tmp.get(), len/2); | ||
return; | ||
} | ||
|
||
bool HashBuilder::addStream(Stream & stream, const size_t totalLen){ | ||
const int BUFFER_SIZE = 512; | ||
std::unique_ptr<uint8_t[]> 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<uint8_t>& 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]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does nearly the same thing as _byteVecToString but uses sprintf instead of the |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#ifndef __ESP8266_HASH_BUILDER__ | ||
#define __ESP8266_HASH_BUILDER__ | ||
|
||
#include <WString.h> | ||
#include <Stream.h> | ||
#include <memory> | ||
#include <vector> | ||
|
||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggest expressing deprecation with |
||
|
||
// 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this is carried over from the original code, but since you are improving things, would you mind replacing this uint16_t with size_t? It doesn't serve any purpose and only adds extra |
||
virtual void _final() = 0; | ||
virtual std::vector<uint8_t> &_result() = 0; | ||
|
||
uint8_t _hexCharToByte(uint8_t c); | ||
String _byteVecToString( std::vector<uint8_t>& v); | ||
}; | ||
|
||
// might be renamed to cryptoBuilder, cause same baseclass | ||
// might be reused in CrpytoSubmodule | ||
typedef HashBuilder CryptoBuilder; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that the current HashBuilder interface is a good fit for AES/RSA. There may be common operations such as conversions from/to byte/hex arrays, but this doesn't mean that these features should share a common interface, given how different the use cases are. If we happen to need the byte/hex transforms for crypto classes, my suggestion is to move these transforms into helper functions/classes shared between HashBuilder and the future crypto classes. |
||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,101 +1,19 @@ | ||
#include <Arduino.h> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't comment on them directly, but there is a bunch of binary files with .gch extensions added in this PR. |
||
#include <MD5Builder.h> | ||
|
||
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. likewise |
||
} | ||
|
||
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need for explicit return here |
||
} | ||
|
||
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<len; i+=2) { | ||
uint8_t high = hex_char_to_byte(data[i]); | ||
uint8_t low = hex_char_to_byte(data[i+1]); | ||
tmp[i/2] = (high & 0x0F) << 4 | (low & 0x0F); | ||
} | ||
add(tmp, len/2); | ||
free(tmp); | ||
} | ||
|
||
bool MD5Builder::addStream(Stream & stream, const size_t maxLen) | ||
{ | ||
const int buf_size = 512; | ||
int maxLengthLeft = maxLen; | ||
uint8_t * buf = (uint8_t*) malloc(buf_size); | ||
|
||
if(!buf) { | ||
return false; | ||
} | ||
|
||
int bytesAvailable = stream.available(); | ||
while((bytesAvailable > 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. likewise |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#include <SHA256Builder.h> | ||
|
||
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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. returns, indentation |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
MD5Builder.h - exposed md5 ROM functions for esp8266 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the ever present comment line :) |
||
|
||
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 <WString.h> | ||
#include <Stream.h> | ||
#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<uint8_t> &_result(){ return _resultVector;} | ||
std::vector<uint8_t> _resultVector = {}; | ||
}; | ||
|
||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I can't be upset with the indentation given that we don't have specific rules in this project (which is a shame)... but would be great if indentation was at least consistent at file scope.