Changes

Tutorial A5-Bonus Breaking AES-256 Bootloader

8,815 bytes removed, 13:36, 29 July 2019
no edit summary
{{Warningbox|This tutorial is an add-on to [[Tutorial A5 Breaking AES-256 Bootloader]]has been updated for ChipWhisperer 5 release. It continues working on If you are using 4.x.x or 3.x.x see the same firmware, showing how to obtain the hidden IV and signature "V4" or "V3" link in the bootloader. '''It is not possible to do this bonus tutorial without first completing the regular tutorial''', so please finish Tutorial A5 firstsidebar.}}
''This {{Infobox tutorial is under construction! Check back in a few days.''|name = A5: Breaking AES-256 Bootloader|image = |caption = |software versions =|capture hardware = CW-Lite, CW-Lite 2-Part, CW-Pro|Target Device = |Target Architecture = XMEGA/Arm|Hardware Crypto = No|Purchase Hardware = }}
= Background =<!-- To edit this, edit Template:Tutorial_boilerplate -->== AES in CBC Mode ==* Repeat of theory from tutorial{{Tutorial boilerplate}}
== The IV ==* Suggest some ideas== The Signature ==* Timing attack* Show firmwareJupyter file: '''PA_Multi_1-Breaking_AES-256_Bootloader.ipynb'''
= Exploring the Bootloader =
In this tutorial, we have the luxury of seeing the source code of the bootloader. This is generally not something we would have access to in the real world, so we'll try not to use it to cheat. (Peeking at <code>supersecret.h</code> counts as cheating.) Instead, we'll use the source to help us identify important parts of the power traces.
== Bootloader Source Code XMEGA Target ==Inside the bootloader's main loop, it does three tasks that we're interested in:* it decrypts the incoming ciphertext;* it applies the IV to the decryption's result; and* it checks for the signature in the resulting plaintext.This snippet from <code>bootloader.c</code> shows all three of these tasks:
<pre>See the following for using:// Continue with decryptiontrigger_high* ChipWhisperer-Lite Classic (XMEGA); aes256_decrypt_ecb* ChipWhisperer-Lite Capture + XMEGA Target on UFO Board (&ctx, tmp32);trigger_low(); including NAE-SCAPACK-L1// Apply IV (first 16 bytesL2 users)for (i = 0; i < 16; i* ChipWhisperer-Pro ++){ tmp32[i] ^= iv[i];}XMEGA Target on UFO Board
https://Save IV for next time from original ciphertext for (i = 0; i < 16; i++){ iv[i] = tmp32[i+16];}chipwhisperer.readthedocs.io/en/latest/tutorials/pa_multi_1-openadc-cwlitexmega.html#tutorial-pa-multi-1-openadc-cwlitexmega
== ChipWhisperer-Lite ARM // Tell the user that the CRC check was okayputch(COMM_OK);putch(COMM_OK);STM32F3 Target ==
//Check See the signaturefollowing for using:if * ChipWhisperer-Lite 32-bit ((tmp32[0] == SIGNATURE1STM32F3 Target) && * ChipWhisperer-Lite Capture + STM32F3 Target on UFO Board (tmp32[1] == SIGNATURE2) && (tmp32[2] == SIGNATURE3) && (tmp32[3] == SIGNATURE4)){ // Delay to emulate a write to flash memory _delay_ms(1);} </pre>This gives us a pretty good idea of how the microcontroller is going to do its job. However, we can go one step further and find the exact assembly code that the target will execute. If you have Atmel Studio and its toolchain on your computer, you can get the assembly file from the command line with<pre>avrincluding NAE-objdump SCAPACK-m avr -D bootloader.hex > disassembly.txt<L1/pre>L2 users)This will convert the hex file into assembly code, making it more human* ChipWhisperer-readable. The important part of this assembly code is:<pre> 344: d3 01 movw r26, r6 346: 93 01 movw r18, r6 348: f6 01 movw r30, r12 34a: 80 81 ld r24, Z 34c: f9 01 movw r30, r18 34e: 91 91 ld r25, ZPro + 350: 9f 01 movw r18, r30 352: 89 27 eor r24, r25 354: f6 01 movw r30, r12 356: 81 93 st Z+, r24 358: 6f 01 movw r12, r30 35a: ee 15 cp r30, r14 35c: ff 05 cpc r31, r15 35e: a1 f7 brne .-24 ; 0x348 360: fe 01 movw r30, r28 362: b1 96 adiw r30, 0x21 ; 33 364: 81 91 ld r24, Z+ 366: 8d 93 st X+, r24 368: e4 15 cp r30, r4 36a: f5 05 cpc r31, r5 36c: d9 f7 brne .-10 ; 0x364STM32F3 Target on UFO Board
36ehttps: 84 ea ldi r24, 0xA4 ; 164 370: 0e 94 16 02 call 0x42c ; 0x42c 374: 84 ea ldi r24, 0xA4 ; 164 376: 0e 94 16 02 call 0x42c ; 0x42c//chipwhisperer.readthedocs.io/en/latest/tutorials/pa_multi_1-openadc-cwlitearm.html#tutorial-pa-multi-1-openadc-cwlitearm
37a: 89 89 ldd r24, Y+17 ; 0x11 37c: 88 23 and r24, r24 37e: 09 f0 breq .+2 ; 0x382 380: 98 cf rjmp .-208 ; 0x2b2== ChipWhisperer Nano Target ==
382: 8a 89 ldd r24, Y+18 ; 0x12 384: 8b 3e cpi r24, 0xEB ; 235 386: 09 f0 breq .+2 ; 0x38a 388: 94 cf rjmp .-216 ; 0x2b2  38a: 8b 89 ldd r24, Y+19 ; 0x13 38c: 82 30 cpi r24, 0x02 ; 2 38e: 09 f0 breq .+2 ; 0x392 390: 90 cf rjmp .-224 ; 0x2b2  392: 8c 89 ldd r24, Y+20 ; 0x14 394: 8d 31 cpi r24, 0x1D ; 29 396: 09 f0 breq .+2 ; 0x39a 398: 8c cf rjmp .-232 ; 0x2b2  39a: 83 e3 ldi r24, 0x33 ; 51 39c: 97 e0 ldi r25, 0x07 ; 7 39e: 01 97 sbiw r24, 0x01 ; 1 3a0: f1 f7 brne .-4 ; 0x39e 3a2: 87 cf rjmp .-242 ; 0x2b2</pre> We'll use both of the source files throughout the This tutorial. == Power Traces ==After the bootloader is finished not available for the decryption process, it executes a couple of distinct pieces of code:* To apply the IV, it uses an XOR operation;* To store the new IV, it copies the previous ciphertext into the IV array;* It sends two bytes on the serial port;* It checks the bytes of the signature one by oneChipWhisperer Nano.We should be able to recognize these four parts of the code in the power traces. Let's modify our capture routine to find them. Re-run the capture script and change a few settings:<ol><li> We'd like to skip over all of the decryption process. The source code around this point is:<pre>trigger_high(); aes256_decrypt_ecb(&ctx, tmp32); /* encrypting the data block */trigger_low();</pre>so we can skip straight over the AES-256 function by triggering on a falling edge instead of a rising edge. Change this in the scope settings.<li> We don't need as many samples now. Change the number of samples to 3000.<li> If we decrypt multiple ciphertexts in a row, only the first one will use the secret IV - all of the others will use the previous ciphertext instead. To avoid this, we'll have to automatically reset the board.<ol><li> In the ''General Settings'' tab, change the Auxiliary Module to ''Reset AVR/XMEGA via CW-Lite''.<li> In the ''Aux Settings'' tab, change both delays to around 100 ms.</ol><li> Capture one trace and make sure that everything works.</ol>If everything worked out, you should be able to see all of the code's features: [[File:Tutorial-A5-Bonus-Trace-Notes.PNG]] = Attacking the IV =Steps:* Making the attack feasible** Capture a bunch (500?)** Apply decryption** Look at one bit** Find means + plot** Find differences + plot* Automating the attack** Finding the attack points** Getting a single bit** Building the IV bytes* Full script in appendix Example: <pre>#Imports for IV Attackfrom Crypto.Cipher import AES def initPreprocessing(self): self.preProcessingResyncSAD0 = preprocessing.ResyncSAD.ResyncSAD(self.parent) self.preProcessingResyncSAD0.setEnabled(True) self.preProcessingResyncSAD0.setReference(rtraceno=0, refpoints=(6300,6800), inputwindow=(6000,7200)) self.preProcessingResyncSAD1 = preprocessing.ResyncSAD.ResyncSAD(self.parent) self.preProcessingResyncSAD1.setEnabled(True) self.preProcessingResyncSAD1.setReference(rtraceno=0, refpoints=(4800,5100), inputwindow=(4700,5200)) self.preProcessingList = [self.preProcessingResyncSAD0,self.preProcessingResyncSAD1,] return self.preProcessingList class AESIVAttack(object): numSubKeys = 16  @staticmethod def leakage(textin, textout, guess, bnum, setting, state): knownkey = [0x94, 0x28, 0x5D, 0x4D, 0x6D, 0xCF, 0xEC, 0x08, 0xD8, 0xAC, 0xDD, 0xF6, 0xBE, 0x25, 0xA4, 0x99, 0xC4, 0xD9, 0xD0, 0x1E, 0xC3, 0x40, 0x7E, 0xD7, 0xD5, 0x28, 0xD4, 0x09, 0xE9, 0xF0, 0x88, 0xA1] knownkey = str(bytearray(knownkey)) ct = str(bytearray(textin))  aes = AES.new(knownkey, AES.MODE_ECB) pt = aes.decrypt(ct) return getHW(bytearray(pt)[bnum] ^ guess)</pre> = Appendix D AES-256 IV Attack Script = '''NB: This script works for 0.10 release or later, see local copy in doc/html directory of chipwhisperer release if you need earlier versions''' Full attack script, copy/paste into a file then add as active attack script: <pre>#IV Attack Scriptfrom chipwhisperer.common.autoscript import AutoScriptBase#Imports from Preprocessingimport chipwhisperer.analyzer.preprocessing as preprocessing#Imports from Capturefrom chipwhisperer.analyzer.attacks.CPA import CPAfrom chipwhisperer.analyzer.attacks.CPAProgressive import CPAProgressiveimport chipwhisperer.analyzer.attacks.models.AES128_8bit# Imports from utilList # Imports for AES256 Attackfrom chipwhisperer.analyzer.attacks.models.AES128_8bit import getHW #Imports for IV Attackfrom Crypto.Cipher import AES class AESIVAttack(object): numSubKeys = 16  @staticmethod def leakage(textin, textout, guess, bnum, setting, state): knownkey = [0x94, 0x28, 0x5D, 0x4D, 0x6D, 0xCF, 0xEC, 0x08, 0xD8, 0xAC, 0xDD, 0xF6, 0xBE, 0x25, 0xA4, 0x99, 0xC4, 0xD9, 0xD0, 0x1E, 0xC3, 0x40, 0x7E, 0xD7, 0xD5, 0x28, 0xD4, 0x09, 0xE9, 0xF0, 0x88, 0xA1] knownkey = str(bytearray(knownkey)) ct = str(bytearray(textin))  aes = AES.new(knownkey, AES.MODE_ECB) pt = aes.decrypt(ct) return getHW(bytearray(pt)[bnum] ^ guess) class userScript(AutoScriptBase): preProcessingList = [] def initProject(self): pass  def initPreprocessing(self): self.preProcessingResyncSAD0 = preprocessing.ResyncSAD.ResyncSAD(self.parent) self.preProcessingResyncSAD0.setEnabled(True) self.preProcessingResyncSAD0.setReference(rtraceno=0, refpoints=(6300,6800), inputwindow=(6000,7200)) self.preProcessingResyncSAD1 = preprocessing.ResyncSAD.ResyncSAD(self.parent) self.preProcessingResyncSAD1.setEnabled(True) self.preProcessingResyncSAD1.setReference(rtraceno=0, refpoints=(4800,5100), inputwindow=(4700,5200)) self.preProcessingList = [self.preProcessingResyncSAD0,self.preProcessingResyncSAD1,] return self.preProcessingList  def initAnalysis(self): self.attack = CPA(self.parent, console=self.console, showScriptParameter=self.showScriptParameter) self.attack.setAnalysisAlgorithm(CPAProgressive, AESIVAttack, None) self.attack.setTraceStart(0) self.attack.setTracesPerAttack(100) self.attack.setIterations(1) self.attack.setReportingInterval(25) self.attack.setTargetBytes([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) self.attack.setTraceManager(self.traceManager()) self.attack.setProject(self.project()) self.attack.setPointRange((4800,6500)) return self.attack  def initReporting(self, results): results.setAttack(self.attack) results.setTraceManager(self.traceManager()) self.results = results  def doAnalysis(self): self.attack.doAttack()</pre> = Attacking the Signature =
Approved_users, administrator
366
edits