@@ -31,6 +31,8 @@ static const char * _err2str(uint8_t _error){
31
31
return (" Bad Argument" );
32
32
} else if (_error == UPDATE_ERROR_ABORT){
33
33
return (" Aborted" );
34
+ } else if (_error == UPDATE_ERROR_DECRYPT){
35
+ return (" Decryption error" );
34
36
}
35
37
return (" UNKNOWN" );
36
38
}
@@ -59,14 +61,20 @@ bool UpdateClass::_enablePartition(const esp_partition_t* partition){
59
61
60
62
UpdateClass::UpdateClass ()
61
63
: _error(0 )
64
+ , _cryptKey(0 )
65
+ , _cryptBuffer(0 )
62
66
, _buffer(0 )
67
+ , _skipBuffer(0 )
63
68
, _bufferLen(0 )
64
69
, _size(0 )
65
70
, _progress_callback(NULL )
66
71
, _progress(0 )
67
72
, _paroffset(0 )
68
73
, _command(U_FLASH)
69
74
, _partition(NULL )
75
+ , _cryptMode(U_AES_DECRYPT_AUTO)
76
+ , _cryptAddress(0 )
77
+ , _cryptCfg(0xf )
70
78
{
71
79
}
72
80
@@ -83,6 +91,7 @@ void UpdateClass::_reset() {
83
91
delete[] _skipBuffer;
84
92
}
85
93
94
+ _cryptBuffer = nullptr ;
86
95
_buffer = nullptr ;
87
96
_skipBuffer = nullptr ;
88
97
_bufferLen = 0 ;
@@ -176,6 +185,48 @@ bool UpdateClass::begin(size_t size, int command, int ledPin, uint8_t ledOn, con
176
185
return true ;
177
186
}
178
187
188
+ bool UpdateClass::setupCrypt (const uint8_t *cryptKey, size_t cryptAddress, uint8_t cryptConfig, int cryptMode){
189
+ if (setCryptKey (cryptKey)){
190
+ if (setCryptMode (cryptMode)){
191
+ setCryptAddress (cryptAddress);
192
+ setCryptConfig (cryptConfig);
193
+ return true ;
194
+ }
195
+ }
196
+ return false ;
197
+ }
198
+
199
+ bool UpdateClass::setCryptKey (const uint8_t *cryptKey){
200
+ if (!cryptKey){
201
+ if (_cryptKey){
202
+ delete[] _cryptKey;
203
+ _cryptKey = 0 ;
204
+ log_d (" AES key unset" );
205
+ }
206
+ return false ; // key cleared, no key to decrypt with
207
+ }
208
+ // initialize
209
+ if (!_cryptKey){
210
+ _cryptKey = new (std::nothrow) uint8_t [ENCRYPTED_KEY_SIZE];
211
+ }
212
+ if (!_cryptKey){
213
+ log_e (" new failed" );
214
+ return false ;
215
+ }
216
+ memcpy (_cryptKey, cryptKey, ENCRYPTED_KEY_SIZE);
217
+ return true ;
218
+ }
219
+
220
+ bool UpdateClass::setCryptMode (const int cryptMode){
221
+ if (cryptMode >= U_AES_DECRYPT_NONE && cryptMode <= U_AES_DECRYPT_ON){
222
+ _cryptMode = cryptMode;
223
+ }else {
224
+ log_e (" bad crypt mode arguement %i" , cryptMode);
225
+ return false ;
226
+ }
227
+ return true ;
228
+ }
229
+
179
230
void UpdateClass::_abort (uint8_t err){
180
231
_reset ();
181
232
_error = err;
@@ -185,7 +236,119 @@ void UpdateClass::abort(){
185
236
_abort (UPDATE_ERROR_ABORT);
186
237
}
187
238
239
+ void UpdateClass::_cryptKeyTweak (size_t cryptAddress, uint8_t *tweaked_key){
240
+ memcpy (tweaked_key, _cryptKey, ENCRYPTED_KEY_SIZE );
241
+ if (_cryptCfg == 0 ) return ; // no tweaking needed, use crypt key as-is
242
+
243
+ const uint8_t pattern[] = { 23 , 23 , 23 , 14 , 23 , 23 , 23 , 12 , 23 , 23 , 23 , 10 , 23 , 23 , 23 , 8 };
244
+ int pattern_idx = 0 ;
245
+ int key_idx = 0 ;
246
+ int bit_len = 0 ;
247
+ uint32_t tweak = 0 ;
248
+ cryptAddress &= 0x00ffffe0 ; // bit 23-5
249
+ cryptAddress <<= 8 ; // bit23 shifted to bit31(MSB)
250
+ while (pattern_idx < sizeof (pattern)){
251
+ tweak = cryptAddress<<(23 - pattern[pattern_idx]); // bit shift for small patterns
252
+ // alternative to: tweak = rotl32(tweak,8 - bit_len);
253
+ tweak = (tweak<<(8 - bit_len)) | (tweak>>(24 + bit_len)); // rotate to line up with end of previous tweak bits
254
+ bit_len += pattern[pattern_idx++] - 4 ; // add number of bits in next pattern(23-4 = 19bits = 23bit to 5bit)
255
+ while (bit_len > 7 ){
256
+ tweaked_key[key_idx++] ^= tweak; // XOR byte
257
+ // alternative to: tweak = rotl32(tweak, 8);
258
+ tweak = (tweak<<8 ) | (tweak>>24 ); // compiler should optimize to use rotate(fast)
259
+ bit_len -=8 ;
260
+ }
261
+ tweaked_key[key_idx] ^= tweak; // XOR remaining bits, will XOR zeros if no remaining bits
262
+ }
263
+ if (_cryptCfg == 0xf ) return ; // return with fully tweaked key
264
+
265
+ // some of tweaked key bits need to be restore back to crypt key bits
266
+ const uint8_t cfg_bits[] = { 67 , 65 , 63 , 61 };
267
+ key_idx = 0 ;
268
+ pattern_idx = 0 ;
269
+ while (key_idx < ENCRYPTED_KEY_SIZE){
270
+ bit_len += cfg_bits[pattern_idx];
271
+ if ( (_cryptCfg & (1 <<pattern_idx)) == 0 ){ // restore crypt key bits
272
+ while (bit_len > 0 ){
273
+ if ( bit_len > 7 || ((_cryptCfg & (2 <<pattern_idx)) == 0 ) ){ // restore a crypt key byte
274
+ tweaked_key[key_idx] = _cryptKey[key_idx];
275
+ }else { // MSBits restore crypt key bits, LSBits keep as tweaked bits
276
+ tweaked_key[key_idx] &= (0xff >>bit_len);
277
+ tweaked_key[key_idx] |= (_cryptKey[key_idx] & (~(0xff >>bit_len)) );
278
+ }
279
+ key_idx++;
280
+ bit_len -= 8 ;
281
+ }
282
+ }else { // keep tweaked key bits
283
+ while (bit_len > 0 ){
284
+ if ( bit_len <8 && ((_cryptCfg & (2 <<pattern_idx)) == 0 ) ){ // MSBits keep as tweaked bits, LSBits restore crypt key bits
285
+ tweaked_key[key_idx] &= (~(0xff >>bit_len));
286
+ tweaked_key[key_idx] |= (_cryptKey[key_idx] & (0xff >>bit_len));
287
+ }
288
+ key_idx++;
289
+ bit_len -= 8 ;
290
+ }
291
+ }
292
+ pattern_idx++;
293
+ }
294
+ }
295
+
296
+ bool UpdateClass::_decryptBuffer (){
297
+ if (!_cryptKey){
298
+ log_w (" AES key not set" );
299
+ return false ;
300
+ }
301
+ if (_bufferLen%ENCRYPTED_BLOCK_SIZE !=0 ){
302
+ log_e (" buffer size error" );
303
+ return false ;
304
+ }
305
+ if (!_cryptBuffer){
306
+ _cryptBuffer = new (std::nothrow) uint8_t [ENCRYPTED_BLOCK_SIZE];
307
+ }
308
+ if (!_cryptBuffer){
309
+ log_e (" new failed" );
310
+ return false ;
311
+ }
312
+ uint8_t tweaked_key[ENCRYPTED_KEY_SIZE]; // tweaked crypt key
313
+ int done = 0 ;
314
+
315
+ esp_aes_context ctx; // initialize AES
316
+ esp_aes_init ( &ctx );
317
+ while ((_bufferLen - done) >= ENCRYPTED_BLOCK_SIZE){
318
+ for (int i=0 ; i < ENCRYPTED_BLOCK_SIZE; i++) _cryptBuffer[(ENCRYPTED_BLOCK_SIZE - 1 ) - i] = _buffer[i + done]; // reverse order 16 bytes to decrypt
319
+ if ( ((_cryptAddress + _progress + done) % ENCRYPTED_TWEAK_BLOCK_SIZE) == 0 || done == 0 ){
320
+ _cryptKeyTweak (_cryptAddress + _progress + done, tweaked_key); // update tweaked crypt key
321
+ if ( esp_aes_setkey ( &ctx, tweaked_key, 256 ) ){
322
+ return false ;
323
+ }
324
+ }
325
+ if ( esp_aes_crypt_ecb ( &ctx, ESP_AES_ENCRYPT, _cryptBuffer, _cryptBuffer ) ){ // use ESP_AES_ENCRYPT to decrypt flash code
326
+ return false ;
327
+ }
328
+ for (int i=0 ; i < ENCRYPTED_BLOCK_SIZE; i++) _buffer[i + done] = _cryptBuffer[(ENCRYPTED_BLOCK_SIZE - 1 ) - i]; // reverse order 16 bytes from decrypt
329
+ done += ENCRYPTED_BLOCK_SIZE;
330
+ }
331
+ return true ;
332
+ }
333
+
188
334
bool UpdateClass::_writeBuffer (){
335
+ // first bytes of loading image, check to see if loading image needs decrypting
336
+ if (!_progress){
337
+ _cryptMode &= U_AES_DECRYPT_MODE_MASK;
338
+ if ( ( _cryptMode == U_AES_DECRYPT_ON )
339
+ || ((_command == U_FLASH) && (_cryptMode & U_AES_DECRYPT_AUTO) && (_buffer[0 ] != ESP_IMAGE_HEADER_MAGIC))
340
+ ){
341
+ _cryptMode |= U_AES_IMAGE_DECRYPTING_BIT; // set to decrypt the loading image
342
+ log_d (" Decrypting OTA Image" );
343
+ }
344
+ }
345
+ // check if data in buffer needs decrypting
346
+ if ( _cryptMode & U_AES_IMAGE_DECRYPTING_BIT ){
347
+ if ( !_decryptBuffer () ){
348
+ _abort (UPDATE_ERROR_DECRYPT);
349
+ return false ;
350
+ }
351
+ }
189
352
// first bytes of new firmware
190
353
uint8_t skip = 0 ;
191
354
if (!_progress && _command == U_FLASH){
0 commit comments