예제 #1
0
    def defineName(self):
        self.name = 'Partition Comparison'

        self.partObject = Partition(self)
        partModeList = {}
        for a in self.partObject.supportedMethods:
            partModeList[a.partitionType] = a

        self.diffObject = DifferenceMode()
        diffModeList = {}
        for a in self.diffObject.supportedMethods:
            diffModeList[a.differenceType] = a

        self.addGroup("generatePartitions")
        self.addGroup("generatePartitionStats")
        self.addGroup("generatePartitionDiffs")
        self.addGroup("displayPartitionDiffs")

        self.poi = POI(self)
        self.poidock = self.parent.addDock(self.poi, "Points of Interest", area=Qt.RightDockWidgetArea)
        self.poidock.hide()

        self.params = [
              {'name':'Comparison Mode', 'key':'diffmode', 'type':'list', 'values':diffModeList, 'value':self.diffObject.diffMethodClass, 'set':self.updateScript},
              {'name':'Partition Mode', 'key':'partmode', 'type':'list', 'values':partModeList, 'value':self.partObject.partMethodClass, 'set':self.updateScript},
              {'name':'Display', 'type':'action', 'action':self.runAction},

              {'name':'Auto-Save Data to Project', 'key':'part-saveints', 'type':'bool', 'value':False, 'set':self.updateScript},
              {'name':'Auto-Load Data from Project', 'key':'part-loadints', 'type':'bool', 'value':False, 'set':self.updateScript},

              {'name':'Points of Interest', 'key':'poi', 'type':'group', 'children':[
                 {'name':'Selection Mode', 'type':'list', 'values':{'Max N Points/Subkey':'maxn'}, 'value':'maxn'},
                 {'name':'Point Range', 'key':'poi-pointrng', 'type':'range', 'limits':(0, 0), 'set':self.updatePOI},
                 {'name':'Num POI/Subkey', 'key':'poi-nummax', 'type':'int', 'limits':(1, 200), 'value':1, 'set':self.updatePOI},
                 {'name':'Min Spacing between POI', 'key':'poi-minspace', 'type':'int', 'limits':(1, 100E6), 'value':1, 'step':100, 'set':self.updatePOI},
                 # {'name':'Threshold', 'key':'threshold', 'type':'int', 'visible':False},
                 {'name':'Open POI Table', 'type':'action', 'action':self.poidock.show},
              ]},
             ]

        self.updateScript()
    def addTraces(self, tracedata, tracerange, progressBar=None, pointRange=None, attack=None):

        # NOTE: this is for calling substuff, not for legacy code here!
        if pointRange is None: pointRange = (0,-1)

        #---

        roundwidth = 0

        if attack is not None:
            round528 = attack.keeloq_round528
            roundwidth = attack.keeloq_roundwidth
            # print "Using KEELOQ timing values from attack: %d %d" % (round528, roundwidth)

        if self.config['roundtiming'] != True:
            roundwidth = 0

        #--- prepare environment

        partClass  = keeloqPartition_CiphertextMSB

        partObject = Partition()
        partObject.setPartMethod(partClass)
        partObject.setTraceSource(tracedata)

        partDisplay = PartitionDisplay(None)
        partDisplay._traces = tracedata

        if progressBar:
            progressBar.setMaximum(64 + 1)

        #--- loop for all unknown keybits

        keystream = ""

        for bit in range(0, 64):

            #--- Analize all possible values (0 and 1)

            guessNum   = 2
            guessDiffs = [] * guessNum

            #--- Partition and find differences using T-Test

            if bit==48:
                print "\nTODO: Sorry for becoming slower, the cipher implementation has not been optimized yet.\n"

            for guessBit in range (0, guessNum):

                # Probe known keystream + guessbit + dummybit
                #
                # The dummybit is necessary because of a property of Keeloq.  The last bit of the stream is
                # mixed into the attacked data bit with XOR.  This results in exactly complementary partitioning
                # for values 0 vs 1, making it impossible to pick a "winner".  Therefore we append the dummybit
                # at this position, so that guessbit is the last input that actually makes a measureable difference.

                partData  = partObject.generatePartitions(partitionClass=None,
                                         saveFile=False, loadFile=False, tRange=tracerange,
                                         partitionConfig={"keystream":"%s %d 0" % (keystream, guessBit)})

                partStats = partDisplay.generatePartitionStats(partitionData={"partclass":partClass, "partdata":partData},
                                         saveFile=False, loadFile=False,  tRange=tracerange, pointRange=pointRange)

                partDiffs = partDisplay.generatePartitionDiffs(DifferenceModeTTest,
                                         statsInfo={"partclass":partClass, "stats":partStats},
                                         saveFile=False, loadFile=False, tRange=tracerange)

                guessDiffs.append(partDiffs[0])
# TODO: since we calculate 0 and 1 anyway we should call the partition mode just once and use a mode that produces 2 keys (0,1)

            #--- Determine range in which high correlation is expected

            # TODO: for strict round timing, it is faster to do partStats only for the desired pointRange

            if roundwidth <= 0: # look in whole pointRange
                lookStart = 0
                lookStop  = len(guessDiffs[0])

            else: # look only at expected position (enforce round timing)
                round      = 528 - 32 - (bit+1)
                roundStart = round528 - ((528-round) * roundwidth)
                roundStop  = roundStart + roundwidth

                lookStart  = roundStart - pointRange[0]
                lookStop   = roundStop  - pointRange[0]

                # print "Round=%d Pos=%d-%d look=%d-%d" % (round, roundStart, roundStop, lookStart, lookStop)

                if (lookStart < 0) or (lookStop > len(guessDiffs[0])):
                    print "Enforced round timing range (%d,%d) is outside of analyzed pointRange(%d,%d). "\
                          "Can't detect key bit %d. Result so far: %s" %\
                                   (roundStart, roundStop, pointRange[0], pointRange[1], bit, keystream)
                    return

            #--- Detect highest correlation
 
            # print "Looking at range %d-%d of %d" % (lookStart, lookStop, len(guessDiffs[0]))
            # if bit == 0:
            #     print guessDiffs[0][lookStart:lookStop]
            #     print guessDiffs[1][lookStart:lookStop]

            winBit = 0 if (np.nanmax(guessDiffs[0][lookStart:lookStop]) > np.nanmax(guessDiffs[1][lookStart:lookStop])) else 1
            badBit = winBit ^ 1

            winOffset     = np.argmax(guessDiffs[winBit][lookStart:lookStop]) + lookStart
            badOffset     = np.argmax(guessDiffs[badBit][lookStart:lookStop]) + lookStart

            winDiff       =           guessDiffs[winBit][winOffset]
            badDiff       =           guessDiffs[badBit][badOffset]
            winRatioSpot  = winDiff / guessDiffs[badBit][winOffset]
            winRatioTrace = winDiff / badDiff

            keystream = "%s%d" % (keystream, winBit)

            #--- report

            print "Analysis of keybit #%02d (of 64): %d (diff=%f spot=%f trace=%f pos=%d) vs %d (diff=%f pos=%d)" %\
                                              (bit,
                                               winBit, winDiff, winRatioSpot, winRatioTrace, winOffset + pointRange[0],
                                               badBit, badDiff,                              badOffset + pointRange[0])

            if progressBar:
                progressBar.setText("Attacking key bits (%d of 64)" % bit)
                progressBar.setStatusMask("key=%s\nkeystream=%s" % (keeloqFormatKeystream(keystream), keystream))
                progressBar.updateStatus(bit)
                if progressBar.wasAborted():
                    print "Aborting. Result so far: %s" % keystream
                    return

        #---

        keyStr = "%s%s" % (keystream[16:64], keystream[0:16])
        keyInt = int(keyStr, 2)

        print "Keystream = %s" % keystream
        print "Key: %016x" % keyInt

        if progressBar:
            progressBar.setText("Attack finished")
            progressBar.setStatusMask("Key: %016x" % keyInt)
            progressBar.updateStatus(64)

        #--- Decrypt the data associated with all traces

        progress = 64

        if True:
            start = tracerange[0]
            end   = tracerange[1]
            if end == -1:
                end = tracedata.numTraces()
            tnum = start
            while tnum < end:
                t = tracedata.getSegment(tnum)
                # Discover where this trace starts & ends
                tmapstart = t.mappedRange[0]
                tmapend = t.mappedRange[1]

                if progressBar:
                    increment = tmapend + 1 - tmapstart
                    progressBar.setMaximum(progress + increment + 1)
                    progressBar.setText("Decrypting traces")

                for tnum in range(tmapstart, tmapend + 1):
                    if progressBar:
                        progressBar.updateStatus(progress)
                        progress += 1
                        if progressBar.wasAborted():
                            return
                    textout = t.getTextout(tnum - tmapstart)
                    if (textout is not None) and (len(textout) >= 4):
                        data = (textout[0] << 24) | (textout[1] << 16) | (textout[2] << 8) | (textout[3] << 0)
                        decrypt = keeloqDecrypt(data, keyInt)
                        print "Trace %0d: %08x -> %08x" % (tnum - tmapstart, data, decrypt)

                tnum = tmapend + 1

        print "Key: %016x" % keyInt

        #--- cleanup

        if progressBar:
            progressBar.setMaximum(100)
            progressBar.updateStatus(100)
예제 #3
0
    def defineName(self):
        self.partObject = Partition()
        partModeList = {}
        for a in self.partObject.supportedMethods:
            partModeList[a.partitionType] = a

        self.diffObject = DifferenceMode()
        diffModeList = {}
        for a in self.diffObject.supportedMethods:
            diffModeList[a.differenceType] = a

        self.addGroup("generatePartitions")
        self.addGroup("generatePartitionStats")
        self.addGroup("generatePartitionDiffs")
        self.addGroup("displayPartitionDiffs")

        self.getParams().addChildren([
            {
                'name': 'Comparison Mode',
                'key': 'diffmode',
                'type': 'list',
                'values': diffModeList,
                'value': self.diffObject.diffMethodClass,
                'action': lambda _: self.updateScript()
            },
            {
                'name': 'Partition Mode',
                'key': 'partmode',
                'type': 'list',
                'values': partModeList,
                'value': self.partObject.partMethodClass,
                'action': lambda _: self.updateScript()
            },
            {
                'name': 'Display',
                'type': 'action',
                'action': lambda _: self.runAction()
            },
            {
                'name': 'Auto-Save Data to Project',
                'key': 'part-saveints',
                'type': 'bool',
                'value': False,
                'action': lambda _: self.updateScript()
            },
            {
                'name': 'Auto-Load Data from Project',
                'key': 'part-loadints',
                'type': 'bool',
                'value': False,
                'action': lambda _: self.updateScript()
            },
            {
                'name':
                'Points of Interest',
                'key':
                'poi',
                'type':
                'group',
                'children': [
                    {
                        'name': 'Selection Mode',
                        'type': 'list',
                        'values': {
                            'Max N Points/Subkey': 'maxn'
                        },
                        'value': 'maxn'
                    },
                    {
                        'name': 'Point Range',
                        'key': 'poi-pointrng',
                        'type': 'range',
                        'limits': (0, 0),
                        'default': (0, 0),
                        'value': (0, 0),
                        'action': lambda _: self.updatePOI()
                    },
                    {
                        'name': 'Num POI/Subkey',
                        'key': 'poi-nummax',
                        'type': 'int',
                        'limits': (1, 200),
                        'value': 1,
                        'action': lambda _: self.updatePOI()
                    },
                    {
                        'name': 'Min Spacing between POI',
                        'key': 'poi-minspace',
                        'type': 'int',
                        'limits': (1, 100E6),
                        'value': 1,
                        'step': 100,
                        'action': lambda _: self.updatePOI()
                    },
                    {
                        'name': 'Hill detection',
                        'key': 'poi-hilldet',
                        'type': 'bool',
                        'value': True,
                        'tip': "Extend the bounds downhill for each peak",
                        'action': lambda _: self.updatePOI()
                    },
                    # {'name':'Threshold', 'key':'threshold', 'type':'int', 'visible':False},
                    {
                        'name': 'Open POI Table',
                        'type': 'action',
                        'action': lambda _: self.poiDock.show()
                    },
                ]
            },
        ])
예제 #4
0
 def __init__(self, tmanager=None):
     self._traceSource = None
     self.partObject = Partition()
 def __init__(self, tmanager=None):
     self._tmanager = None
     self.partObject = Partition(self)