Package: darkphoenixAES
Dark PhoenixThe Phoenix became Dark Phoenix due to allowing human emotions to cloud its judgment. In this state, Phoenix was the strongest, but also an evil entity that thirsted for power and destruction. Totally uncontrollable, Dark Phoenix was a force to be reckoned with as it was not bound by a human conscience.DarkPhoenix is a tool to perform differential fault analysis attacks (DFA) against AES whiteboxeswith external encodings, as described inA DFA Attack on White-Box Implementations of AES with External Encodings, Alessandro Amadori, Wil Michiels, Peter Roelse [1]DependenciesIn order to solve some equations, you should haveSageMathinstalled on your computer and available in your PATH (under the namesage).Install$pipinstalldarkphoenixAESTest$python3-mdarkphoenixAES--selftestUsageTo use this attack, you shouldImplement your own class inheriting fromWhiteBoxedAESto provide the script an access to the whitebox to attack.Instantiate theAttackclass with your own class as parameter, and run it.1. Implement a class inheriting from WhiteBoxedAESThe class inheriting fromWhiteBoxedAESwill be the interface between the whitebox and the attack script.
This class must be able to introduce a fault at a given position in the whitebox.Here is an example of implementation.
More information is available in the fileWhiteBoxedAES.py.
A complete example is implemented inWhiteBoxedAESTest.py.fromdarkphoenixAESimportWhiteBoxedAESclassMyWhiteBoxedAES(WhiteBoxedAES):def__init__(self,...):self.aeswb=...defgetRoundNumber(self):# return the number of rounds of the whitebox (10 for AES128,#   12 for AES192 and 14 for AES256)return10defisEncrypt(self):# Does the whitebox encrypt of decrypt data# (needed and validate with the MixColumns result)returnTruedefhasReverse(self):# Is there an applyReverse method that can be called?returnFalsedefapply(self,data):# Apply the whitebox on a buffer# [param] data  a buffer of 16 bytes (type bytes)# return  16 bytes of the encrypted/decrypted datareturn# TODO : return the encrypted value of datadefapplyFault(self,data,faults):# Apply the whitebox on a buffer and inject fault at the given position# [param] data      a buffer of 16 bytes (type bytes)# [param] faults    a list of faults to apply:#       fround, fbytes, fxorval = faults[0]#       fround      the round to apply the fault. 0 is the first round#       fbytes      the position of the internal state byte to fault (between 0 and 15)#       fxorval     the fault to apply by xor (between 1 and 255)# return  16 bytes of the faulted encrypted datareturn# TODO : return the encrypted faulted value of data with the given faults2. Instantiate and run the Attack classfromdarkphoenixAESimportAttackimportMyWhiteBoxedAES# initialize your whiteboxmyWB=MyWhiteBoxedAES(...)# run the attack# The file "backup.json" will be used the save the result of# each step and must be removed before running on a new instance.attack=Attack(myWB)attack.run("backup.json")# print extracted roundKeyattack.printKey()# get the extracted Keykey=attack.getKey()print("key:",key.hex())# get the external encodinginputE,outputE=attack.externalEncoding()When instantiating the Attack class, you can specify the following optional arguments:nprocess: The number of processes used by multiprocess (default: autodetect (None))
The special value0disables the use of multiprocess.noprogress: Enable or disable the progress bar (default: autodetect TTY (None))sageSubProc: Use Sage in a subprocess (default:True). The attack needs SageMath to solve some equations. IfTrue, a separate process is used to solve these equations, otherwise, the Sage library is loaded within the current Python processstep1DoubleValue: apply Step 1 with the property used in the paper (two fixed values by column) (default:False). If this option isFalse, only one fixed value is needed in Step 1 (reducing the complexity by 256). However, this optimization delays the detection of a wrong injection position during Step 2.Advanced UsageSelecting fault position during the attack (manually)To perform the attack, the fault must first be injected one MixColumn before the output, then two MixColumn before, etc.
While the position of the first faults can be found by looking at the output, this not the case for the next ones.If you want to manually select the fault position during the attack, you can use the base classWhiteBoxedAESDynamicinstead ofWhiteBoxedAES:fromdarkphoenixAESimportWhiteBoxedAESDynamicclassMyWhiteBoxedAES(WhiteBoxedAESDynamic):# ... same as WhiteBoxedAESdefprepareFaultPosition(self,fround,reverseRoundMethod,reverseRoundMethod2=None):# TODO search fault for the round `fround`passWhen the attack needs to inject faults in a new round, the methodprepareFaultPositionwill first be called. In order to verify if the fault is valid for this round, two methods are given:reverseRoundMethod: reverse the result up tofround+1. A valid fault position must fault 4 bytes of the reversed output with this method.reverseRoundMethod2: reverse the result up tofround+2. A valid fault position must fault all the bytes of the reversed output with this method. This method is provided to detect is the fault is applied at fround+2 instead of fround. This method is not provided whenfround == wb.getRoundNumber()-1WhenprepareFaultPositionreturns, 16 different fault positions must have been found according toreverseRoundMethodandreverseRoundMethod2.Selecting fault position during the attack (automatically)DarkPhoenix integrates a second mechanism to identify the fault position. To use it, the base classWhiteBoxedAESAutomust be used, and the methodAttack.runshould be replaced byAttack.runAuto:fromdarkphoenixAESimportWhiteBoxedAESAutoclassMyWhiteBoxedAES(WhiteBoxedAESAuto):# ... same as WhiteBoxedAESdefchangeFaultPosition(self,fround,fbytes):# TODO select a random fault position for (fround, fbytes)passdefapplyFault(self,data,faults):forfround,fbytes,fxorvalinfaults:# TODO Apply the fault fxorval at the last selected position for (fround, fbytes)The methodchangeFaultPositionselects a random fault position and associates (fround, fbytes) to this position. When a fault is asked withapplyFaultwith the same (fround, fbytes), this position should be used. If DarkPhoenix detects that the position is not valid,changeFaultPositionwill be called again until a valid position is found.While DarkPhoenix is able to identify if the fault is mathematically valid,changeFaultPositionmust verify that the fault position is viable (i.e. it does not crash the process) for any fault value.WhiteBoxedAES compatible with multiprocessingWhenAttackis not called withnprocess=0, the computation of the two first steps will be performed in manymultiprocessing.Processor in amultiprocessing.Pool. On Linux, this is equivalent to a fork (seemultiprocessing documentation).When a new process is created during these steps, the new process has it own copy ofWhiteBoxedAES. However, depending of the implementation ofWhiteBoxedAES, some resources need to be recreated (file descriptor, subprocess, debugged process, ...). For this purpose, the methodnewThreadwill be called on the new copy ofWhiteBoxedAESwhen the new thread start.However, the firstWhiteBoxedAESand any copy of it must return the same result for the same input with the same fault. If this not possible, you should disable multiprocessing withnprocess=0.If using dynamic fault position,prepareFaultPositionandchangeFaultPositionare always called on the first instance ofWhiteBoxedAES. The fault position must be shared with any future copy ofWhiteBoxedAES.AboutAuthors and ContributorsInitial Authors and Contributors:Nicolas SurbayrolePhilippe TeuwenFor next contributions, see the git project history.CopyrightQuarkslabLicenseDarkPhoenix is provided under theApache 2.0 license.CreditsMany thanks to Alessandro Amadori, author of [1], for having shared his simulation scripts, which greatly helped us verify our own implementation during its development.References[1]
Amadori A., Michiels W., Roelse P. (2020)
A DFA Attack on White-Box Implementations of AES with External Encodings.
In: Paterson K., Stebila D. (eds) Selected Areas in Cryptography – SAC 2019. SAC 2019. Lecture Notes in Computer Science, vol 11959. Springer, Cham.https://doi.org/10.1007/978-3-030-38471-5_24