Skip to content

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions cores/esp8266/HashBuilder.cpp
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]);
Copy link
Member

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.

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]);
Copy link
Member

Choose a reason for hiding this comment

The 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 hex array. Would it make sense to use same method here?

}
}
44 changes: 44 additions & 0 deletions cores/esp8266/HashBuilder.h
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest expressing deprecation with __attribute__((deprecated)) Why are these deprecated, by the way?


// 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;
Copy link
Member

Choose a reason for hiding this comment

The 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 extui instructions to truncate 32-bit int to a 16-bit one.

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;
Copy link
Member

Choose a reason for hiding this comment

The 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
Binary file added cores/esp8266/HashBuilder.h.gch
Binary file not shown.
102 changes: 10 additions & 92 deletions cores/esp8266/MD5Builder.cpp
Original file line number Diff line number Diff line change
@@ -1,101 +1,19 @@
#include <Arduino.h>
Copy link
Member

Choose a reason for hiding this comment

The 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;
Copy link
Member

Choose a reason for hiding this comment

The 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;
Copy link
Member

Choose a reason for hiding this comment

The 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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

likewise

}
35 changes: 15 additions & 20 deletions cores/esp8266/MD5Builder.h
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 <WString.h>
#include <Stream.h>
#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<uint8_t> &_result(){ return _resultVector;}
std::vector<uint8_t> _resultVector = {};
};



#endif
Binary file added cores/esp8266/MD5Builder.h.gch
Binary file not shown.
18 changes: 18 additions & 0 deletions cores/esp8266/SHA256Builder.cpp
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returns, indentation

}
43 changes: 43 additions & 0 deletions cores/esp8266/SHA256Builder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
MD5Builder.h - exposed md5 ROM functions for esp8266
Copy link
Member

Choose a reason for hiding this comment

The 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
Binary file added cores/esp8266/SHA256Builder.h.gch
Binary file not shown.
Binary file added cores/esp8266/hashBuilder.h.gch
Binary file not shown.
25 changes: 25 additions & 0 deletions cores/esp8266/sha256.h
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
Binary file added cores/esp8266/sha256.h.gch
Binary file not shown.
Loading