|
|
(25 intermediate revisions by 4 users not shown) |
Line 1: |
Line 1: |
− | This tutorial is an add-on to [[Tutorial A5 Breaking AES-256 Bootloader]]. It continues working on the same firmware, showing how to obtain the hidden IV and signature in the bootloader. '''It is not possible to do this bonus tutorial without first completing the regular tutorial''', so please finish Tutorial A5 first. | + | {{Warningbox|This tutorial has been updated for ChipWhisperer 5 release. If you are using 4.x.x or 3.x.x see the "V4" or "V3" link in the sidebar.}} |
| | | |
− | ''This tutorial is under construction! Check back in a few days.''
| + | {{Infobox tutorial |
| + | |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 ==
| + | {{Tutorial boilerplate}} |
− | * Repeat of theory from tutorial
| + | |
| | | |
− | == Bootloader Source Code ==
| + | * Jupyter file: '''PA_Multi_1-Breaking_AES-256_Bootloader.ipynb''' |
− | 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.)
| + | |
| | | |
− | The important part of the bootloader code includes the decryption, the IV application, and the signature check. This snippet from <code>bootloader.c</code> shows all three:
| |
| | | |
− | <pre>
| + | == XMEGA Target == |
− | // Continue with decryption
| + | |
− | trigger_high();
| + | |
− | aes256_decrypt_ecb(&ctx, tmp32);
| + | |
− | trigger_low();
| + | |
− |
| + | |
− | // Apply IV (first 16 bytes)
| + | |
− | for (i = 0; i < 16; i++){
| + | |
− | tmp32[i] ^= iv[i];
| + | |
− | }
| + | |
| | | |
− | //Save IV for next time from original ciphertext
| + | See the following for using: |
− | for (i = 0; i < 16; i++){
| + | * ChipWhisperer-Lite Classic (XMEGA) |
− | iv[i] = tmp32[i+16];
| + | * ChipWhisperer-Lite Capture + XMEGA Target on UFO Board (including NAE-SCAPACK-L1/L2 users) |
− | }
| + | * ChipWhisperer-Pro + XMEGA Target on UFO Board |
| | | |
− | // Tell the user that the CRC check was okay | + | https://chipwhisperer.readthedocs.io/en/latest/tutorials/pa_multi_1-openadc-cwlitexmega.html#tutorial-pa-multi-1-openadc-cwlitexmega |
− | putch(COMM_OK);
| + | |
− | putch(COMM_OK);
| + | |
| | | |
− | //Check the signature
| + | == ChipWhisperer-Lite ARM / STM32F3 Target == |
− | if ((tmp32[0] == SIGNATURE1) &&
| + | |
− | (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
| + | See the following for using: |
− | <pre>
| + | * ChipWhisperer-Lite 32-bit (STM32F3 Target) |
− | avr-objdump -m avr -D bootloader.hex > disassembly.txt
| + | * ChipWhisperer-Lite Capture + STM32F3 Target on UFO Board (including NAE-SCAPACK-L1/L2 users) |
− | </pre>
| + | * ChipWhisperer-Pro + STM32F3 Target on UFO Board |
− | This will convert the hex file into assembly code, making it more human-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, Z+
| + | |
− | 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 ; 0x364
| + | |
| | | |
− | 36e: 84 ea ldi r24, 0xA4 ; 164
| + | https://chipwhisperer.readthedocs.io/en/latest/tutorials/pa_multi_1-openadc-cwlitearm.html#tutorial-pa-multi-1-openadc-cwlitearm |
− | 370: 0e 94 16 02 call 0x42c ; 0x42c
| + | |
− | 374: 84 ea ldi r24, 0xA4 ; 164
| + | |
− | 376: 0e 94 16 02 call 0x42c ; 0x42c
| + | |
| | | |
− | 37a: 89 89 ldd r24, Y+17 ; 0x11
| + | == ChipWhisperer Nano Target == |
− | 37c: 88 23 and r24, r24
| + | |
− | 37e: 09 f0 breq .+2 ; 0x382
| + | |
− | 380: 98 cf rjmp .-208 ; 0x2b2
| + | |
| | | |
− | 382: 8a 89 ldd r24, Y+18 ; 0x12
| + | This tutorial is not available for the ChipWhisperer Nano. |
− | 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>
| + | |
− | Let's examine this code in more detail.
| + | |
− | | + | |
− | == The IV ==
| + | |
− | * Suggest some ideas
| + | |
− | == The Signature ==
| + | |
− | * Timing attack
| + | |
− | * Show firmware
| + | |
− | | + | |
− | = Attacking the IV =
| + | |
− | Steps:
| + | |
− | * Investigation
| + | |
− | ** Look at bootloader code
| + | |
− | ** Move trigger
| + | |
− | ** Record 1
| + | |
− | ** Show different instructions in trace
| + | |
− | * 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 Attack
| + | |
− | from 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 Script
| + | |
− | from chipwhisperer.common.autoscript import AutoScriptBase
| + | |
− | #Imports from Preprocessing
| + | |
− | import chipwhisperer.analyzer.preprocessing as preprocessing
| + | |
− | #Imports from Capture
| + | |
− | from chipwhisperer.analyzer.attacks.CPA import CPA
| + | |
− | from chipwhisperer.analyzer.attacks.CPAProgressive import CPAProgressive
| + | |
− | import chipwhisperer.analyzer.attacks.models.AES128_8bit
| + | |
− | # Imports from utilList
| + | |
− | | + | |
− | # Imports for AES256 Attack
| + | |
− | from chipwhisperer.analyzer.attacks.models.AES128_8bit import getHW
| + | |
− | | + | |
− | #Imports for IV Attack
| + | |
− | from 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 =
| + | |
This tutorial will introduce you to measuring the power consumption of a device under attack. It will demonstrate how you can view the difference between assembly instructions. In ChipWhisperer 5 Release, the software documentation is now held outside the wiki. See links below.
Running the tutorial uses the referenced Jupyter notebook file.