Skip to content

Commit

Permalink
Add MD5 to core, Fix OTA examples and Digest Authentication to OTA an…
Browse files Browse the repository at this point in the history
…d espota.py
  • Loading branch information
Me No Dev committed Nov 8, 2015
1 parent e613e42 commit a8976a0
Show file tree
Hide file tree
Showing 13 changed files with 501 additions and 230 deletions.
43 changes: 43 additions & 0 deletions cores/esp8266/MD5Builder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "Arduino.h"
#include "md5.h"
#include "MD5Builder.h"

#define hex_char_to_byte(c) (((c)>='a'&&(c)<='f')?((c)-87):((c)>='A'&&(c)<='F')?((c)-55):((c)>='0'&&(c)<='9')?((c)-48):0)

void MD5Builder::begin(void){
memset(_buf, 0x00, 16);
MD5Init(&_ctx);
}

void MD5Builder::add(uint8_t * data, uint16_t len){
MD5Update(&_ctx, data, len);
}

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) tmp[i/2] = (hex_char_to_byte(data[i]) & 0x0F) << 4 | (hex_char_to_byte(data[i+1]) & 0x0F);
add(tmp, len/2);
free(tmp);
}

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[32];
getChars(out);
return String(out);
}
47 changes: 47 additions & 0 deletions cores/esp8266/MD5Builder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
md5.h - exposed md5 ROM functions for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
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_MD5_BUILDER__
#define __ESP8266_MD5_BUILDER__

#include "Arduino.h"
#include "md5.h"

class MD5Builder {
private:
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()); }
void calculate(void);
void getBytes(uint8_t * output);
void getChars(char * output);
String toString(void);
};


#endif
29 changes: 27 additions & 2 deletions cores/esp8266/Updater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ void UpdaterClass::_reset() {
_currentAddress = 0;
_size = 0;
_command = U_FLASH;
_target_md5 = 0;
}

bool UpdaterClass::begin(size_t size, int command) {
Expand Down Expand Up @@ -96,10 +97,17 @@ bool UpdaterClass::begin(size_t size, int command) {
_size = size;
_buffer = new uint8_t[FLASH_SECTOR_SIZE];
_command = command;


_target_md5 = new char[64];
_md5.begin();
return true;
}

void UpdaterClass::setMD5(const char * expected_md5){

This comment has been minimized.

Copy link
@mangelajo

mangelajo Nov 10, 2015

Contributor

niiiice!! 👍

if(strlen(expected_md5) != 32) return;
strcpy(_target_md5, expected_md5);
}

bool UpdaterClass::end(bool evenIfRemaining){
if(_size == 0){
#ifdef DEBUG_UPDATER
Expand All @@ -123,7 +131,21 @@ bool UpdaterClass::end(bool evenIfRemaining){
}
_size = progress();
}


_md5.calculate();
if(_target_md5 && strlen(_target_md5) == 32){
if(strcmp(_target_md5, _md5.toString().c_str()) != 0){
_error = UPDATE_ERROR_MD5;
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf("MD5 Failed: expected:%s, calculated:%s\n", _target_md5, _md5.toString().c_str());
#endif
return false;
}
#ifdef DEBUG_UPDATER
else DEBUG_UPDATER.printf("MD5 Success: %s\n", _md5.toString().c_str());
#endif
}

if (_command == U_FLASH) {
eboot_command ebcmd;
ebcmd.action = ACTION_COPY_RAW;
Expand Down Expand Up @@ -157,6 +179,7 @@ bool UpdaterClass::_writeBuffer(){
#endif
return false;
}
_md5.add(_buffer, _bufferLen);
_currentAddress += _bufferLen;
_bufferLen = 0;
return true;
Expand Down Expand Up @@ -232,6 +255,8 @@ void UpdaterClass::printError(Stream &out){
out.println("Bad Size Given");
} else if(_error == UPDATE_ERROR_STREAM){
out.println("Stream Read Timeout");
} else if(_error == UPDATE_ERROR_MD5){
out.println("MD5 Check Failed");
} else {
out.println("UNKNOWN");
}
Expand Down
22 changes: 21 additions & 1 deletion cores/esp8266/Updater.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@

#include "Arduino.h"
#include "flash_utils.h"
#include "MD5Builder.h"

#define UPDATE_ERROR_OK 0
#define UPDATE_ERROR_WRITE 1
#define UPDATE_ERROR_ERASE 2
#define UPDATE_ERROR_SPACE 3
#define UPDATE_ERROR_SIZE 4
#define UPDATE_ERROR_STREAM 5
#define UPDATE_ERROR_MD5 6

#define U_FLASH 0
#define U_SPIFFS 100

//#define DEBUG_UPDATER Serial1
//#define DEBUG_UPDATER Serial

class UpdaterClass {
public:
Expand Down Expand Up @@ -56,7 +58,22 @@ class UpdaterClass {
Prints the last error to an output stream
*/
void printError(Stream &out);

/*
sets the expected MD5 for the firmware (hexString)
*/
void setMD5(const char * expected_md5);

/*
returns the MD5 String of the sucessfully ended firmware
*/
String md5String(void){ return _md5.toString(); }

/*
populated the result with the md5 bytes of the sucessfully ended firmware
*/
void md5(uint8_t * result){ return _md5.getBytes(result); }

//Helpers
uint8_t getError(){ return _error; }
void clearError(){ _error = UPDATE_ERROR_OK; }
Expand Down Expand Up @@ -120,6 +137,9 @@ class UpdaterClass {
uint32_t _startAddress;
uint32_t _currentAddress;
uint32_t _command;

char *_target_md5;
MD5Builder _md5;
};

extern UpdaterClass Update;
Expand Down
44 changes: 44 additions & 0 deletions cores/esp8266/md5.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
md5.h - exposed md5 ROM functions for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
original C source from https://github.com/morrissinger/ESP8266-Websocket/raw/master/MD5.h
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_MD5__
#define __ESP8266_MD5__

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
uint32_t state[4];
uint32_t count[2];
uint8_t buffer[64];
} md5_context_t;

extern void MD5Init (md5_context_t *);
extern void MD5Update (md5_context_t *, uint8_t *, uint16_t);
extern void MD5Final (uint8_t [16], md5_context_t *);

#ifdef __cplusplus
} // extern "C"
#endif

#endif
Loading

5 comments on commit a8976a0

@mangelajo
Copy link
Contributor

Choose a reason for hiding this comment

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

Awesome work, some comments, but WOW! :)

This is real collaborative work! :)

@me-no-dev
Copy link
Collaborator

Choose a reason for hiding this comment

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

yeah, look at the final code. Will have the sanity checks + new command for auth. Maybe you are commenting on a particular commit and not on the whole pull request?

@hallard
Copy link
Contributor

Choose a reason for hiding this comment

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

great jobs guys,
Any chance to put the bargraph on espota.py before PR, this will avoid me to wait merge and do another PR ?
changes are really trivials
add this func anywhere you want

# update_progress() : Displays or updates a console progress bar
## Accepts a float between 0 and 1. Any int will be converted to a float.
## A value under 0 represents a 'halt'.
## A value at 1 or bigger represents 100%
def update_progress(progress):
    barLength = 60 # Modify this to change the length of the progress bar
    status = ""
    if isinstance(progress, int):
        progress = float(progress)
    if not isinstance(progress, float):
        progress = 0
        status = "error: progress var must be float\r\n"
    if progress < 0:
        progress = 0
        status = "Halt...\r\n"
    if progress >= 1:
        progress = 1
        status = "Done...\r\n"
    block = int(round(barLength*progress))
    text = "\rUploading: [{0}] {1}% {2}".format( "="*block + " "*(barLength-block), int(progress*100), status)
    sys.stdout.write(text)
    sys.stdout.flush()

then the main transfer loop becomes with calls to update_progress and offset var + that's all

try:
    f = open(filename, "rb")
    update_progress(0)
    #sys.stderr.write('Uploading')
    #sys.stderr.flush()
    offset = 0
    while True:
      chunk = f.read(1460)
      if not chunk: break
      offset += len(chunk)
      update_progress(offset/float(content_size))
      #sys.stderr.write('.')
      #sys.stderr.flush()
      connection.settimeout(10)
      try:

@me-no-dev
Copy link
Collaborator

Choose a reason for hiding this comment

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

@hallard
Copy link
Contributor

Choose a reason for hiding this comment

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

Excellent, thanks :-)

Please sign in to comment.