Skip to content

Commit 082d948

Browse files
authored
Update Updater.cpp
1 parent 1cd84f6 commit 082d948

File tree

1 file changed

+224
-6
lines changed

1 file changed

+224
-6
lines changed

Diff for: libraries/Update/src/Updater.cpp

+224-6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include "spi_flash_mmap.h"
1010
#include "esp_ota_ops.h"
1111
#include "esp_image_format.h"
12+
#ifndef UPDATE_NOCRYPT
13+
#include "mbedtls/aes.h"
14+
#endif /* UPDATE_NOCRYPT */
1215

1316
static const char *_err2str(uint8_t _error) {
1417
if (_error == UPDATE_ERROR_OK) {
@@ -37,6 +40,10 @@ static const char *_err2str(uint8_t _error) {
3740
return ("Bad Argument");
3841
} else if (_error == UPDATE_ERROR_ABORT) {
3942
return ("Aborted");
43+
#ifndef UPDATE_NOCRYPT
44+
} else if (_error == UPDATE_ERROR_DECRYPT) {
45+
return ("Decryption error");
46+
#endif /* UPDATE_NOCRYPT */
4047
}
4148
return ("UNKNOWN");
4249
}
@@ -64,7 +71,15 @@ bool UpdateClass::_enablePartition(const esp_partition_t *partition) {
6471
}
6572

6673
UpdateClass::UpdateClass()
67-
: _error(0), _buffer(0), _bufferLen(0), _size(0), _progress_callback(NULL), _progress(0), _paroffset(0), _command(U_FLASH), _partition(NULL) {}
74+
: _error(0),
75+
#ifndef UPDATE_NOCRYPT
76+
_cryptKey(0), _cryptBuffer(0),
77+
#endif /* UPDATE_NOCRYPT */
78+
_buffer(0), _skipBuffer(0), _bufferLen(0), _size(0), _progress_callback(NULL), _progress(0), _paroffset(0), _command(U_FLASH), _partition(NULL)
79+
#ifndef UPDATE_NOCRYPT
80+
, _cryptMode(U_AES_DECRYPT_AUTO), _cryptAddress(0), _cryptCfg(0xf)
81+
#endif /* UPDATE_NOCRYPT */
82+
{}
6883

6984
UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress fn) {
7085
_progress_callback = fn;
@@ -79,6 +94,9 @@ void UpdateClass::_reset() {
7994
delete[] _skipBuffer;
8095
}
8196

97+
#ifndef UPDATE_NOCRYPT
98+
_cryptBuffer = nullptr;
99+
#endif /* UPDATE_NOCRYPT */
82100
_buffer = nullptr;
83101
_skipBuffer = nullptr;
84102
_bufferLen = 0;
@@ -170,6 +188,50 @@ bool UpdateClass::begin(size_t size, int command, int ledPin, uint8_t ledOn, con
170188
return true;
171189
}
172190

191+
#ifndef UPDATE_NOCRYPT
192+
bool UpdateClass::setupCrypt(const uint8_t *cryptKey, size_t cryptAddress, uint8_t cryptConfig, int cryptMode) {
193+
if (setCryptKey(cryptKey)) {
194+
if (setCryptMode(cryptMode)) {
195+
setCryptAddress(cryptAddress);
196+
setCryptConfig(cryptConfig);
197+
return true;
198+
}
199+
}
200+
return false;
201+
}
202+
203+
bool UpdateClass::setCryptKey(const uint8_t *cryptKey) {
204+
if (!cryptKey) {
205+
if (_cryptKey) {
206+
delete[] _cryptKey;
207+
_cryptKey = 0;
208+
log_d("AES key unset");
209+
}
210+
return false; //key cleared, no key to decrypt with
211+
}
212+
//initialize
213+
if (!_cryptKey) {
214+
_cryptKey = new (std::nothrow) uint8_t[ENCRYPTED_KEY_SIZE];
215+
}
216+
if (!_cryptKey) {
217+
log_e("new failed");
218+
return false;
219+
}
220+
memcpy(_cryptKey, cryptKey, ENCRYPTED_KEY_SIZE);
221+
return true;
222+
}
223+
224+
bool UpdateClass::setCryptMode(const int cryptMode) {
225+
if (cryptMode >= U_AES_DECRYPT_NONE && cryptMode <= U_AES_DECRYPT_ON) {
226+
_cryptMode = cryptMode;
227+
} else {
228+
log_e("bad crypt mode argument %i", cryptMode);
229+
return false;
230+
}
231+
return true;
232+
}
233+
#endif /* UPDATE_NOCRYPT */
234+
173235
void UpdateClass::_abort(uint8_t err) {
174236
_reset();
175237
_error = err;
@@ -179,7 +241,144 @@ void UpdateClass::abort() {
179241
_abort(UPDATE_ERROR_ABORT);
180242
}
181243

244+
#ifndef UPDATE_NOCRYPT
245+
void UpdateClass::_cryptKeyTweak(size_t cryptAddress, uint8_t *tweaked_key) {
246+
memcpy(tweaked_key, _cryptKey, ENCRYPTED_KEY_SIZE);
247+
if (_cryptCfg == 0) {
248+
return; //no tweaking needed, use crypt key as-is
249+
}
250+
251+
const uint8_t pattern[] = {23, 23, 23, 14, 23, 23, 23, 12, 23, 23, 23, 10, 23, 23, 23, 8};
252+
int pattern_idx = 0;
253+
int key_idx = 0;
254+
int bit_len = 0;
255+
uint32_t tweak = 0;
256+
cryptAddress &= 0x00ffffe0; //bit 23-5
257+
cryptAddress <<= 8; //bit23 shifted to bit31(MSB)
258+
while (pattern_idx < sizeof(pattern)) {
259+
tweak = cryptAddress << (23 - pattern[pattern_idx]); //bit shift for small patterns
260+
// alternative to: tweak = rotl32(tweak,8 - bit_len);
261+
tweak = (tweak << (8 - bit_len)) | (tweak >> (24 + bit_len)); //rotate to line up with end of previous tweak bits
262+
bit_len += pattern[pattern_idx++] - 4; //add number of bits in next pattern(23-4 = 19bits = 23bit to 5bit)
263+
while (bit_len > 7) {
264+
tweaked_key[key_idx++] ^= tweak; //XOR byte
265+
// alternative to: tweak = rotl32(tweak, 8);
266+
tweak = (tweak << 8) | (tweak >> 24); //compiler should optimize to use rotate(fast)
267+
bit_len -= 8;
268+
}
269+
tweaked_key[key_idx] ^= tweak; //XOR remaining bits, will XOR zeros if no remaining bits
270+
}
271+
if (_cryptCfg == 0xf) {
272+
return; //return with fully tweaked key
273+
}
274+
275+
//some of tweaked key bits need to be restore back to crypt key bits
276+
const uint8_t cfg_bits[] = {67, 65, 63, 61};
277+
key_idx = 0;
278+
pattern_idx = 0;
279+
while (key_idx < ENCRYPTED_KEY_SIZE) {
280+
bit_len += cfg_bits[pattern_idx];
281+
if ((_cryptCfg & (1 << pattern_idx)) == 0) { //restore crypt key bits
282+
while (bit_len > 0) {
283+
if (bit_len > 7 || ((_cryptCfg & (2 << pattern_idx)) == 0)) { //restore a crypt key byte
284+
tweaked_key[key_idx] = _cryptKey[key_idx];
285+
} else { //MSBits restore crypt key bits, LSBits keep as tweaked bits
286+
tweaked_key[key_idx] &= (0xff >> bit_len);
287+
tweaked_key[key_idx] |= (_cryptKey[key_idx] & (~(0xff >> bit_len)));
288+
}
289+
key_idx++;
290+
bit_len -= 8;
291+
}
292+
} else { //keep tweaked key bits
293+
while (bit_len > 0) {
294+
if (bit_len < 8 && ((_cryptCfg & (2 << pattern_idx)) == 0)) { //MSBits keep as tweaked bits, LSBits restore crypt key bits
295+
tweaked_key[key_idx] &= (~(0xff >> bit_len));
296+
tweaked_key[key_idx] |= (_cryptKey[key_idx] & (0xff >> bit_len));
297+
}
298+
key_idx++;
299+
bit_len -= 8;
300+
}
301+
}
302+
pattern_idx++;
303+
}
304+
}
305+
306+
bool UpdateClass::_decryptBuffer() {
307+
if (!_cryptKey) {
308+
log_w("AES key not set");
309+
return false;
310+
}
311+
if (_bufferLen % ENCRYPTED_BLOCK_SIZE != 0) {
312+
log_e("buffer size error");
313+
return false;
314+
}
315+
if (!_cryptBuffer) {
316+
_cryptBuffer = new (std::nothrow) uint8_t[ENCRYPTED_BLOCK_SIZE];
317+
}
318+
if (!_cryptBuffer) {
319+
log_e("new failed");
320+
return false;
321+
}
322+
uint8_t tweaked_key[ENCRYPTED_KEY_SIZE]; //tweaked crypt key
323+
int done = 0;
324+
325+
/*
326+
Mbedtls functions will be replaced with esp_aes functions when hardware acceleration is available
327+
328+
To Do:
329+
Replace mbedtls for the cases where there's no hardware acceleration
330+
*/
331+
332+
mbedtls_aes_context ctx; //initialize AES
333+
mbedtls_aes_init(&ctx);
334+
while ((_bufferLen - done) >= ENCRYPTED_BLOCK_SIZE) {
335+
for (int i = 0; i < ENCRYPTED_BLOCK_SIZE; i++) {
336+
_cryptBuffer[(ENCRYPTED_BLOCK_SIZE - 1) - i] = _buffer[i + done]; //reverse order 16 bytes to decrypt
337+
}
338+
if (((_cryptAddress + _progress + done) % ENCRYPTED_TWEAK_BLOCK_SIZE) == 0 || done == 0) {
339+
_cryptKeyTweak(_cryptAddress + _progress + done, tweaked_key); //update tweaked crypt key
340+
if (mbedtls_aes_setkey_enc(&ctx, tweaked_key, 256)) {
341+
return false;
342+
}
343+
if (mbedtls_aes_setkey_dec(&ctx, tweaked_key, 256)) {
344+
return false;
345+
}
346+
}
347+
if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, _cryptBuffer, _cryptBuffer)) { //use MBEDTLS_AES_ENCRYPT to decrypt flash code
348+
return false;
349+
}
350+
for (int i = 0; i < ENCRYPTED_BLOCK_SIZE; i++) {
351+
_buffer[i + done] = _cryptBuffer[(ENCRYPTED_BLOCK_SIZE - 1) - i]; //reverse order 16 bytes from decrypt
352+
}
353+
done += ENCRYPTED_BLOCK_SIZE;
354+
}
355+
return true;
356+
}
357+
#endif /* UPDATE_NOCRYPT */
358+
182359
bool UpdateClass::_writeBuffer() {
360+
#ifndef UPDATE_NOCRYPT
361+
//first bytes of loading image, check to see if loading image needs decrypting
362+
if (!_progress) {
363+
_cryptMode &= U_AES_DECRYPT_MODE_MASK;
364+
if ((_cryptMode == U_AES_DECRYPT_ON) || ((_command == U_FLASH) && (_cryptMode & U_AES_DECRYPT_AUTO) && (_buffer[0] != ESP_IMAGE_HEADER_MAGIC))) {
365+
_cryptMode |= U_AES_IMAGE_DECRYPTING_BIT; //set to decrypt the loading image
366+
log_d("Decrypting OTA Image");
367+
}
368+
}
369+
370+
if (!_target_md5_decrypted) {
371+
_md5.add(_buffer, _bufferLen);
372+
}
373+
374+
//check if data in buffer needs decrypting
375+
if (_cryptMode & U_AES_IMAGE_DECRYPTING_BIT) {
376+
if (!_decryptBuffer()) {
377+
_abort(UPDATE_ERROR_DECRYPT);
378+
return false;
379+
}
380+
}
381+
#endif /* UPDATE_NOCRYPT */
183382
//first bytes of new firmware
184383
uint8_t skip = 0;
185384
if (!_progress && _command == U_FLASH) {
@@ -229,7 +428,13 @@ bool UpdateClass::_writeBuffer() {
229428
if (!_progress && _command == U_FLASH) {
230429
_buffer[0] = ESP_IMAGE_HEADER_MAGIC;
231430
}
232-
_md5.add(_buffer, _bufferLen);
431+
#ifndef UPDATE_NOCRYPT
432+
if (_target_md5_decrypted) {
433+
#endif /* UPDATE_NOCRYPT */
434+
_md5.add(_buffer, _bufferLen);
435+
#ifndef UPDATE_NOCRYPT
436+
}
437+
#endif /* UPDATE_NOCRYPT */
233438
_progress += _bufferLen;
234439
_bufferLen = 0;
235440
if (_progress_callback) {
@@ -271,12 +476,19 @@ bool UpdateClass::_verifyEnd() {
271476
return false;
272477
}
273478

274-
bool UpdateClass::setMD5(const char *expected_md5) {
479+
bool UpdateClass::setMD5(const char *expected_md5
480+
#ifndef UPDATE_NOCRYPT
481+
,bool calc_post_decryption
482+
#endif /* UPDATE_NOCRYPT */
483+
) {
275484
if (strlen(expected_md5) != 32) {
276485
return false;
277486
}
278487
_target_md5 = expected_md5;
279488
_target_md5.toLowerCase();
489+
#ifndef UPDATE_NOCRYPT
490+
_target_md5_decrypted = calc_post_decryption;
491+
#endif /* UPDATE_NOCRYPT */
280492
return true;
281493
}
282494

@@ -349,10 +561,16 @@ size_t UpdateClass::writeStream(Stream &data) {
349561
return 0;
350562
}
351563

352-
if (!_verifyHeader(data.peek())) {
353-
_reset();
354-
return 0;
564+
#ifndef UPDATE_NOCRYPT
565+
if (_command == U_FLASH && !_cryptMode) {
566+
#endif /* UPDATE_NOCRYPT */
567+
if (!_verifyHeader(data.peek())) {
568+
_reset();
569+
return 0;
570+
}
571+
#ifndef UPDATE_NOCRYPT
355572
}
573+
#endif /* UPDATE_NOCRYPT */
356574

357575
if (_ledPin != -1) {
358576
pinMode(_ledPin, OUTPUT);

0 commit comments

Comments
 (0)