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
1316static 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
6673UpdateClass::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
6984UpdateClass &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+
173235void 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+
182359bool 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