|
| 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 */ |
0 commit comments