Skip to content

Commit dea0e10

Browse files
committed
First draft on SHA256 calculation, needs a bit of cleanup
1 parent 85c87bb commit dea0e10

File tree

3 files changed

+96
-2
lines changed

3 files changed

+96
-2
lines changed

src/ArduinoIoTCloudTCP.cpp

+86
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@
2727
#ifdef BOARD_HAS_ECCX08
2828
#include "tls/BearSSLTrustAnchors.h"
2929
#include "tls/utility/CryptoUtil.h"
30+
#include "tls/utility/SHA256.h"
3031
#endif
3132

33+
#undef max
34+
#undef min
35+
#include <algorithm>
36+
3237
#include "utility/ota/OTAStorage_SNU.h"
3338
#include "utility/ota/OTAStorage_SFU.h"
3439
#include "utility/ota/OTAStorage_SSU.h"
@@ -119,6 +124,85 @@ int ArduinoIoTCloudTCP::begin(String brokerAddress, uint16_t brokerPort)
119124
_brokerAddress = brokerAddress;
120125
_brokerPort = brokerPort;
121126

127+
#ifdef OTA_ENABLED
128+
/* Calculate the SHA256 checksum over the firmware stored in the flash of the
129+
* MCU. Note: As we don't know the length per-se we read chunks of the flash
130+
* until we detect one containing only 0xFF (= flash erased). This only works
131+
* for firmware updated via OTA and second stage bootloaders (SxU family)
132+
* because only those erase the complete flash before performing an update.
133+
* Since the SHA256 firmware image is only required for the cloud servers to
134+
* perform a version check after the OTA update this is a acceptable trade off.
135+
*/
136+
SHA256 sha256;
137+
sha256.begin();
138+
139+
uint32_t const APP_START_ADDR = 0x2000; /* Start after the bootloader. */
140+
#undef FLASH_SIZE
141+
uint32_t const FLASH_READ_SIZE = 0x40000 - APP_START_ADDR;
142+
uint32_t const FLASH_READ_CHUNK_SIZE = 64;
143+
144+
uint32_t flash_addr = APP_START_ADDR;
145+
for(; flash_addr < FLASH_READ_SIZE; flash_addr += FLASH_READ_CHUNK_SIZE)
146+
{
147+
/* Read from the MCU's flash. */
148+
uint8_t buf[FLASH_READ_CHUNK_SIZE];
149+
memcpy(buf, reinterpret_cast<const void *>(flash_addr), FLASH_READ_CHUNK_SIZE);
150+
151+
/* Check if the next segment is erased, that is if all bytes within
152+
* a read segment are 0xFF -> then we've reached the end of the
153+
* firmware.
154+
*/
155+
uint8_t buf_2[FLASH_READ_CHUNK_SIZE];
156+
memcpy(buf_2, reinterpret_cast<const void *>(flash_addr + FLASH_READ_CHUNK_SIZE), FLASH_READ_CHUNK_SIZE);
157+
size_t valid_bytes_in_buf = 0;
158+
DBG_VERBOSE("[%X]", flash_addr);
159+
char msg[4];
160+
for(size_t i=0; i<FLASH_READ_CHUNK_SIZE; i++)
161+
{
162+
snprintf(msg, 4, "%02X", buf[i]);
163+
Serial.print(msg);
164+
}
165+
Serial.println();
166+
167+
168+
if (std::all_of(buf_2, buf_2+FLASH_READ_CHUNK_SIZE, [](uint8_t const elem) { return (elem == 0xFF); }))
169+
{
170+
/* Eliminate trailing 0xFF. */
171+
for(valid_bytes_in_buf = FLASH_READ_CHUNK_SIZE; valid_bytes_in_buf > 0; valid_bytes_in_buf--) {
172+
if (buf[valid_bytes_in_buf-1] != 0xFF)
173+
break;
174+
}
175+
/* Update with the remaining bytes. */
176+
DBG_VERBOSE("End of firmware, %d valid bytes in last read segment", valid_bytes_in_buf);
177+
sha256.update(buf, valid_bytes_in_buf);
178+
break;
179+
}
180+
else
181+
{
182+
/* Otherwise update the SHA256 hash. */
183+
sha256.update(buf, FLASH_READ_CHUNK_SIZE);
184+
}
185+
}
186+
Serial.println();
187+
/* Retrieve the final hash string. */
188+
uint8_t sha256_hash[SHA256::HASH_SIZE] = {0};
189+
sha256.finalize(sha256_hash);
190+
String sha256_str;
191+
std::for_each(sha256_hash,
192+
sha256_hash + SHA256::HASH_SIZE,
193+
[&sha256_str](uint8_t const elem)
194+
{
195+
char buf[4];
196+
snprintf(buf, 4, "%02X", elem);
197+
sha256_str += buf;
198+
});
199+
/* Update the property. */
200+
_ota_img_sha256 = sha256_str;
201+
/* Do some debug printout. */
202+
DBG_VERBOSE("SHA256: %d bytes read", flash_addr);
203+
DBG_VERBOSE("SHA256: HASH(%d) = %s", strlen(_ota_img_sha256.c_str()), _ota_img_sha256.c_str());
204+
#endif /* OTA_ENABLED */
205+
122206
#ifdef BOARD_HAS_ECCX08
123207
if (!ECCX08.begin()) { DBG_ERROR("Cryptography processor failure. Make sure you have a compatible board."); return 0; }
124208
if (!CryptoUtil::readDeviceId(ECCX08, getDeviceId(), ECCX08Slot::DeviceId)) { DBG_ERROR("Cryptography processor read failure."); return 0; }
@@ -187,6 +271,8 @@ void ArduinoIoTCloudTCP::update()
187271
_mqtt_data_request_retransmit = false;
188272
}
189273

274+
//DBG_VERBOSE("SHA256: HASH(%d) = %s", strlen(_ota_img_sha256.c_str()), _ota_img_sha256.c_str());
275+
190276
// MTTQClient connected!, poll() used to retrieve data from MQTT broker
191277
_mqttClient.poll();
192278

src/tls/utility/SHA256.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121

2222
#include "SHA256.h"
2323

24+
/******************************************************************************
25+
* STATIC MEMBER DECLARATION
26+
******************************************************************************/
27+
28+
constexpr size_t SHA256::HASH_SIZE;
29+
2430
/******************************************************************************
2531
* PUBLIC MEMBER FUNCTIONS
2632
******************************************************************************/
@@ -35,7 +41,7 @@ void SHA256::update(uint8_t const * data, size_t const len)
3541
br_sha256_update(&_ctx, data, len);
3642
}
3743

38-
void SHA256::finalize(char * hash)
44+
void SHA256::finalize(uint8_t * hash)
3945
{
4046
br_sha256_out(&_ctx, hash);
4147
}

src/tls/utility/SHA256.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ class SHA256
3333

3434
public:
3535

36+
static constexpr size_t HASH_SIZE = 32;
37+
3638
void begin ();
3739
void update (uint8_t const * data, size_t const len);
38-
void finalize(char * hash);
40+
void finalize(uint8_t * hash);
3941

4042
private:
4143

0 commit comments

Comments
 (0)