Skip to content

Commit 63e85b2

Browse files
committed
Extracting calculation of firmware SHA256 value into class FlashSHA256
1 parent dea0e10 commit 63e85b2

File tree

3 files changed

+164
-75
lines changed

3 files changed

+164
-75
lines changed

src/ArduinoIoTCloudTCP.cpp

+4-75
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,9 @@
2727
#ifdef BOARD_HAS_ECCX08
2828
#include "tls/BearSSLTrustAnchors.h"
2929
#include "tls/utility/CryptoUtil.h"
30-
#include "tls/utility/SHA256.h"
3130
#endif
3231

33-
#undef max
34-
#undef min
35-
#include <algorithm>
36-
32+
#include "utility/ota/FlashSHA256.h"
3733
#include "utility/ota/OTAStorage_SNU.h"
3834
#include "utility/ota/OTAStorage_SFU.h"
3935
#include "utility/ota/OTAStorage_SSU.h"
@@ -132,75 +128,10 @@ int ArduinoIoTCloudTCP::begin(String brokerAddress, uint16_t brokerPort)
132128
* because only those erase the complete flash before performing an update.
133129
* Since the SHA256 firmware image is only required for the cloud servers to
134130
* perform a version check after the OTA update this is a acceptable trade off.
131+
* The bootloader is excluded from the calculation and occupies flash address
132+
* range 0 to 0x2000, total flash size of 0x40000 bytes (256 kByte).
135133
*/
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());
134+
_ota_img_sha256 = FlashSHA256::calc(0x2000, 0x40000 - 0x2000);
204135
#endif /* OTA_ENABLED */
205136

206137
#ifdef BOARD_HAS_ECCX08
@@ -271,8 +202,6 @@ void ArduinoIoTCloudTCP::update()
271202
_mqtt_data_request_retransmit = false;
272203
}
273204

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

src/utility/ota/FlashSHA256.cpp

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
This file is part of ArduinoIoTCloud.
3+
4+
Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
5+
6+
This software is released under the GNU General Public License version 3,
7+
which covers the main part of arduino-cli.
8+
The terms of this license can be found at:
9+
https://www.gnu.org/licenses/gpl-3.0.en.html
10+
11+
You can be released from the requirements of the above licenses by purchasing
12+
a commercial license. Buying such a license is mandatory if you want to modify or
13+
otherwise use the software for commercial activities involving the Arduino
14+
software without disclosing the source code of your own applications. To purchase
15+
a commercial license, send an email to [email protected].
16+
*/
17+
18+
/******************************************************************************
19+
* INCLUDE
20+
******************************************************************************/
21+
22+
#include <AIoTC_Config.h>
23+
#if OTA_ENABLED
24+
25+
#include "FlashSHA256.h"
26+
27+
#include "../../tls/utility/SHA256.h"
28+
29+
#include <Arduino_DebugUtils.h>
30+
31+
#undef max
32+
#undef min
33+
#include <algorithm>
34+
35+
/******************************************************************************
36+
* PUBLIC MEMBER FUNCTIONS
37+
******************************************************************************/
38+
39+
String FlashSHA256::calc(uint32_t const start_addr, uint32_t const max_flash_size)
40+
{
41+
SHA256 sha256;
42+
uint8_t chunk [FLASH_READ_CHUNK_SIZE],
43+
next_chunk[FLASH_READ_CHUNK_SIZE];
44+
45+
sha256.begin();
46+
47+
/* Read the first two chunks of flash. */
48+
uint32_t flash_addr = start_addr;
49+
memcpy(chunk, reinterpret_cast<const void *>(flash_addr), FLASH_READ_CHUNK_SIZE);
50+
flash_addr += FLASH_READ_CHUNK_SIZE;
51+
52+
for(; flash_addr < max_flash_size; flash_addr += FLASH_READ_CHUNK_SIZE)
53+
{
54+
/* Read the next chunk of memory. */
55+
memcpy(next_chunk, reinterpret_cast<const void *>(flash_addr), FLASH_READ_CHUNK_SIZE);
56+
57+
/* Check if the next segment is erased, that is if all bytes within
58+
* a read segment are 0xFF -> then we've reached the end of the firmware.
59+
*/
60+
bool const next_chunk_is_erased_flash = std::all_of(next_chunk,
61+
next_chunk+FLASH_READ_CHUNK_SIZE,
62+
[](uint8_t const elem) { return (elem == 0xFF); });
63+
/* Determine how many bytes at the end of the current chunk are
64+
* already set to 0xFF and therefore erased/non-written flash
65+
* memory.
66+
*/
67+
if (next_chunk_is_erased_flash)
68+
{
69+
/* Eliminate trailing 0xFF. */
70+
size_t valid_bytes_in_chunk = 0;
71+
for(valid_bytes_in_chunk = FLASH_READ_CHUNK_SIZE; valid_bytes_in_chunk > 0; valid_bytes_in_chunk--)
72+
{
73+
if (chunk[valid_bytes_in_chunk-1] != 0xFF)
74+
break;
75+
}
76+
DBG_VERBOSE("FlashSHA256::calc: end of firmware, %d valid bytes in last read chunk", valid_bytes_in_chunk);
77+
/* Update with the remaining bytes. */
78+
sha256.update(chunk, valid_bytes_in_chunk);
79+
break;
80+
}
81+
82+
/* We've read a normal segment with the next segment not containing
83+
* any erased elements, just update the SHA256 hash calcultion.
84+
*/
85+
sha256.update(chunk, FLASH_READ_CHUNK_SIZE);
86+
87+
/* Copy next_chunk to chunk. */
88+
memcpy(chunk, next_chunk, FLASH_READ_CHUNK_SIZE);
89+
}
90+
91+
/* Retrieve the final hash string. */
92+
uint8_t sha256_hash[SHA256::HASH_SIZE] = {0};
93+
sha256.finalize(sha256_hash);
94+
String sha256_str;
95+
std::for_each(sha256_hash,
96+
sha256_hash + SHA256::HASH_SIZE,
97+
[&sha256_str](uint8_t const elem)
98+
{
99+
char buf[4];
100+
snprintf(buf, 4, "%02X", elem);
101+
sha256_str += buf;
102+
});
103+
/* Do some debug printout. */
104+
DBG_VERBOSE("SHA256: %d bytes read", flash_addr);
105+
DBG_VERBOSE("SHA256: HASH(%d) = %s", strlen(sha256_str.c_str()), sha256_str.c_str());
106+
return sha256_str;
107+
}
108+
109+
#endif /* OTA_ENABLED */

src/utility/ota/FlashSHA256.h

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
This file is part of ArduinoIoTCloud.
3+
4+
Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
5+
6+
This software is released under the GNU General Public License version 3,
7+
which covers the main part of arduino-cli.
8+
The terms of this license can be found at:
9+
https://www.gnu.org/licenses/gpl-3.0.en.html
10+
11+
You can be released from the requirements of the above licenses by purchasing
12+
a commercial license. Buying such a license is mandatory if you want to modify or
13+
otherwise use the software for commercial activities involving the Arduino
14+
software without disclosing the source code of your own applications. To purchase
15+
a commercial license, send an email to [email protected].
16+
*/
17+
18+
#ifndef ARDUINO_OTA_FLASH_SHA256_H_
19+
#define ARDUINO_OTA_FLASH_SHA256_H_
20+
21+
/******************************************************************************
22+
* INCLUDE
23+
******************************************************************************/
24+
25+
#include <AIoTC_Config.h>
26+
#if OTA_ENABLED
27+
28+
#include <Arduino.h>
29+
30+
/******************************************************************************
31+
* CLASS DECLARATION
32+
******************************************************************************/
33+
34+
class FlashSHA256
35+
{
36+
public:
37+
38+
static String calc(uint32_t const start_addr, uint32_t const max_flash_size);
39+
40+
private:
41+
42+
FlashSHA256() { }
43+
FlashSHA256(FlashSHA256 const &) { }
44+
45+
static constexpr uint32_t FLASH_READ_CHUNK_SIZE = 64;
46+
47+
};
48+
49+
#endif /* OTA_ENABLED */
50+
51+
#endif /* ARDUINO_OTA_FLASH_SHA256_H_ */

0 commit comments

Comments
 (0)