Сбой функции XOR в особых случаях

#python #encryption #des

#python #шифрование #des

Вопрос:

Я хочу предварить это, сказав, что проблема связана с python, а не с DES. Я создал программу шифрования DES для своего класса криптологии. игнорируя ключевые функции, общий формат этого шифрования: открытый текст -> (перестановка) -> L0 R0. L(i) = R (i-1). R (i) = L(i-1) XOR F(E(R(i-1) XOR K (i))) в настоящее время моя программа предназначена для вывода каждого шага этого процесса. на каждом шаге моя программа работает по назначению, пока я не доберусь до окончательного XOR до конца этого раунда шифрования. Метод XOR, который я использую, использовался до этой проблемы и работает по назначению. Вот класс, который я создал:

 class DES:
    def printListInX(self, l, x):
        strList=""
        for i in range(len(l)):
            if i % x ==0:
                strList =" "
            strList =str(l[i])
        return strList
    def byteArrToInt(self,bits):
        #generally only used for turning 3 bits to 1 num
        temp=8*bits[0]   4*bits[1]  2*bits[2] bits[3]
        return temp 
    def intTo4bits(self, n)->list:
        bStr = '' 
        while n > 0: 
            bStr =  str(n % 2)  bStr 
            n = n >> 1 
        while len(bStr)<4:
            bStr="0" bStr
        return [int(x) for x in bStr]
    def shiftLeft(self, h, num):
        for i in range(num):
            h=h[1:] [h[0]]
        return h
    def xorBytes(self, n=[], m=[])->list:
        #assume n m of equal size
        temp=[]
        for i in range(len(n)):
            if n[i] == m[i]:
                temp.append(0)
            else:
                temp.append(1)
        return temp
    def get2from1(self, L):
        temp1=[]
        temp2=[]
        half=len(L)/2 #len is assumed even so no need to floor
        for i in range(len(L)):
            if i <half:
                temp1.append(L[i])
            else:
                temp2.append(L[i])
        return temp1, temp2
    def hexToBinList(self,h):
        binDict={
            "0":"0000","1":"0001","2":"0010","3":"0011","4":"0100",
            "5":"0101","6":"0110","7":"0111","8":"1000","9":"1001",
            "A":"1010","a":"1010","b":"1011","B":"1011",
            "C":"1100","c":"1100","D":"1101","d":"1101",
            "E":"1110","e":"1110","F":"1111","f":"1111"
        }
        if isinstance(h, str):
            strList=list(h)
        elif isinstance(h,list):
            #assume its a list of hex values
            strList=h
        ans=[]
        for c in strList:
            ans =list(binDict[c])
        return ans
    def process(self, h):
        if isinstance(h, str):
            if len(h)==64:
                #make into array of those ints
                #assuming 64 len string is only 1 or 0
                temp=list(h)
                return [int(x) for x in temp]
            elif len(h)==16:
                return self.hexToBinList(h)
        elif isinstance(h, list):
            if len(h)==64:
                #assume binary
                return h
            elif len(h)==16:
                return self.hexToBinList(h)
        #else?    if int do i convert to hex?

    def initialPermutation(self, ptList):
        #reorder bits, newList[0]=ptList[57] (58 but indexing starts at 1 not 0)
        newList=[]
        for i in range(len(ptList)):
            newList.append(ptList[self.ipTable[i] - 1])
        return newList

    def PC1(self,keyList):
        pc1Table=[57,49,41,33,25,17,9,
            1,58,50,42,34,26,18,
            10,2,59,51,43,35,27,
            19,11,3,60,52,44,36,
            
            63,55,47,39,31,23,15,
            7,62,54,46,38,30,22,
            14,6,61,53,45,37,29,
            21,13,5,28,20,12,4]
        #len(keyList)==64
        #len(ans)==56
        ans=[]
        for i in range(56):
            ans.append(keyList[pc1Table[i] - 1])
        return ans

    def PC2(self, keyList):
        pc2Table=[14,17,11,24,1,5,3,28,
            15,6,21,10,23,19,12,4,
            26,8,16,7,27,20,13,2,
            41,52,31,37,47,55,30,40,
            51,45,33,48,44,49,39,56,
            34,53,46,42,50,36,29,32]
        #len(keyList)=56
        #len(ans)=48
        ans=[]
        for i in range(48):
            ans.append(keyList[pc2Table[i] - 1])
        return ans

    def expansion(self, R:list)->list:
        eTable=[32,1,2,3,4,5,
            4,5,6,7,8,9,
            8,9,10,11,12,13,
            12,13,14,15,16,17,
            16,17,18,19,20,21,
            20,21,22,23,24,25,
            24,25,26,27,28,29,
            28,29,30,31,32,1]
        #len(R)=32
        #len(ans)=48
        ans=[]
        for i in range(48):
            ans.append(R[eTable[i] - 1])
        return ans

    def s1box(self, bits)->list:
        #bits is R XOR K. will be broken and sent to each box class internally
        box=[
            [14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7],
            [0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8],
            [4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0],
            [15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13]
        ]
        usable=bits[:6]
        bits=bits[6:]
        row=int( (str(usable[0])   str(usable[-1])), 2)
        col=self.byteArrToInt(usable[1:-1])
        print('bits from s1box: ', self.intTo4bits(box[row][col]))
        return self.intTo4bits(box[row][col])   self.s2box(bits)
      
    def s2box(self, bits)->list:
        box=[
            [15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10],
            [3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5],
            [0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15],
            [13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9]
        ]
        usable=bits[:6]
        bits=bits[6:]
        row=int( (str(usable[0])   str(usable[-1])), 2)
        col=self.byteArrToInt(usable[1:-1])
        print('bits from s2box: ', self.intTo4bits(box[row][col]))
        return self.intTo4bits(box[row][col])   self.s3box(bits) 

    def s3box(self, bits)->list:
        box=[
            [10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8],
            [13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1],
            [13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7],
            [1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12]
        ]
        usable=bits[:6]
        bits=bits[6:]
        row=int( (str(usable[0])   str(usable[-1])), 2)
        col=self.byteArrToInt(usable[1:-1])
        print('bits from s3box: ', self.intTo4bits(box[row][col]))
        return self.intTo4bits(box[row][col])   self.s4box(bits)

    def s4box(self, bits)->list:
        box=[
            [7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15],
            [13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9],
            [10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4],
            [3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14]
        ]
        usable=bits[:6]
        bits=bits[6:]
        row=int( (str(usable[0])   str(usable[-1])), 2)
        col=self.byteArrToInt(usable[1:-1])
        print('bits from s4box: ', self.intTo4bits(box[row][col]))
        return self.intTo4bits(box[row][col])   self.s5box(bits)
    
    def s5box(self, bits)->list:
        box=[
            [2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9],
            [14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6],
            [4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14],
            [11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3]
        ]
        usable=bits[:6]
        bits=bits[6:]
        row=int( (str(usable[0])   str(usable[-1])), 2)
        col=self.byteArrToInt(usable[1:-1])
        print('bits from s5box: ', self.intTo4bits(box[row][col]))
        return self.intTo4bits(box[row][col])   self.s6box(bits)

    def s6box(self, bits)->list:
        box=[
            [12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11],
            [10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8],
            [9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6],
            [4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13]
        ]
        usable=bits[:6]
        bits=bits[6:]
        row=int( (str(usable[0])   str(usable[-1])), 2)
        col=self.byteArrToInt(usable[1:-1])
        print('bits from s6box: ', self.intTo4bits(box[row][col]))
        return self.intTo4bits(box[row][col])   self.s7box(bits)

    def s7box(self, bits)->list:
        box=[
            [4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1],
            [13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6],
            [1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2],
            [6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12]
        ]
        usable=bits[:6]
        bits=bits[6:]
        row=int( (str(usable[0])   str(usable[-1])), 2)
        col=self.byteArrToInt(usable[1:-1])
        print('bits from s7box: ', self.intTo4bits(box[row][col]))
        return self.intTo4bits(box[row][col])   self.s8box(bits)

    def s8box(self, bits)->list:
        box=[
            [13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7],
            [1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2],
            [7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8],
            [2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11]
        ]
        #bits should not be len 6
        row=int( (str(bits[0])   str(bits[-1])), 2)
        col=self.byteArrToInt(bits[1:-1])
        print('bits from s8box: ', self.intTo4bits(box[row][col]))
        return self.intTo4bits(box[row][col])

    def pBox(self, bits)->list:
        box=[16,7,20,21,29,12,28,17,
            1,15,23,26,5,18,31,10,
            2,8,24,14,32,27,3,9,
            19,13,30,6,22,11,4,25]
        ans=[]
        for i in range(32):
            ans.append(bits[box[i] - 1])
        print('bits from pBox: ',self.printListInX(ans, 4))
        return ans

    def F(self, R:list, K:list)->list:
        #expand R from 32 to 48 bits
        expR=self.expansion(R)
        print('R after expansion: ', self.printListInX(expR, 6))
        #XOR newR with K
        rXorK=self.xorBytes(expR,K)
        print('R XOR K: ', self.printListInX(rXorK, 6))
        #break into 8 sub lists (size 6 each) for S boxes
        afterSbox=self.s1box(rXorK)    #should now be 32 bits   
        #P box permutation
        ans=self.pBox(afterSbox)
        return ans

    def finalPermutation(self, bits:list)->list:
        newList=[]
        for i in range(len(bits)):
            newList.append(bits[self.ipTableINV[i] - 1])
        return newList

    def encrypt(self, pt, key, numRounds):
        ################# SOMETHIGN WRONG ALGORITHMETICALLY #####################
        ############ i think its because i get L0 and R0 but never actually use them in F
        self.pt=self.process(pt) #will be type list
        self.key = self.process(key)#will be type list
        self.numRounds=numRounds #should always be 16

        #do IP on pt to get L,R
        newPtList=self.initialPermutation(self.pt)
        print('PT after first permutation: ', self.printListInX(newPtList,4))
        L,R=self.get2from1(newPtList)
        print("L0: ", self.printListInX(L, 4), "tR0: ", self.printListInX(R, 4))
        #do PC1 on key to get C,D
        key56bits=self.PC1(self.key) 
        print('key after PC1: ', self.printListInX(key56bits, 4))
        C,D=self.get2from1(key56bits)
        print('initail C: ', self.printListInX(C, 4), 'ninitial D: ', self.printListInX(D, 4))
        shift1=[0,1,8,15]
        for i in range(numRounds):
            print('nnstart of round ', (i 1),'nn')
            newL=R
            #newC=C (shifted left x times)
            #newD=D (shifted left x times)
            #x depends on roundnum
            if i in shift1:
                C=self.shiftLeft(C,1)
                D=self.shiftLeft(D,1)
            else:
                C=self.shiftLeft(C,2)
                D=self.shiftLeft(D,2)
            #K=COMPRESS(newC,newD)
            print('after shift C: ', self.printListInX(C, 4), 'nafter shift D: ', self.printListInX(D, 4))
            K=self.PC2(C D) 
            print('K', (i 1), ': ', self.printListInX(K, 6))
            #newR=L XOR F(R,K)
            fOfRK=self.F(R,K)            
            print('F of R0,K1: ', self.printListInX(fOfRK, 4))
            print('before final XOR')
            print('L',i,': ', self.printListInX(L, 4))
            print('F',(i 1),': ',self.printListInX(fOfRK,4))
            ################### start issue ################
            newR=self.xorBytes(fOfRK,L)
            ################### end issue ##################
            print('newR: ', self.printListInX(newR, 4))
            #L=newL, R=newR, C=newC, D=newD
            R=newR
            L=newL
            print('L', (i 1), ': ', self.printListInX(L, 4))
            print('R', (i 1), ': ', self.printListInX(R, 4))
        #now that rounds are done, do final permutation (ipTableINV)
        self.encryptedBits=self.finalPermutation(L R)
        return self.encryptedBits
    
    def __init__(self):
        self.ipTable=[58,50,42,34,26,18,10,2,
            60,52,44,36,28,20,12,4,
            62,54,46,38,30,22,14,6,
            64,56,48,40,32,24,16,8,
            57,49,41,33,25,17,9,1,
            59,51,43,35,27,19,11,3,
            61,53,45,37,29,21,13,5,
            63,55,47,39,31,23,15,7]
        self.ipTableINV=[40,8,48,16,56,24,64,32,
            39,7,47,15,55,23,63,31,
            38,6,46,14,54,22,26,30,
            37,5,45,13,53,21,61,29,
            36,4,44,12,52,20,60,28,
            35,3,43,11,51,19,59,27,
            34,2,42,10,50,18,58,26,
            33,1,41,9,49,17,57,25]
  

это программа-драйвер, используемая для запуска и создания выходных данных:

 from DES64Bit import DES 

cipher=DES()

pt="0123456789ABCDEF"

key="0123456789ABCDEF"

cipher.encrypt(pt=pt, key=key, numRounds=2)
  

результат, полученный из этого, выглядит следующим образом
DES_OUTPUT

проблема здесь находится в третьем от последнего раунда перед началом второго раунда «newR: » эта строка должна состоять из двух предыдущих строк, исключающих or’d.

здесь у меня есть программа, использующая тот же метод, который используется внутри, а также ту же битовую строку

 def xorBytes(n, m):
    #assume n m of equal size
    temp=[]
    for i in range(len(n)):
        if n[i] == m[i]:
            temp.append(0)
        else:
            temp.append(1)
    return temp

n=[1,1,1,1, 0,0,0,0, 1,0,1,0, 1,0,1,0, 1,1,1,1, 0,0,0,0, 1,0,1,0, 1,0,1,0]

m=[0,0,1,1, 1,0,0,0, 1,1,0,1, 1,0,1,1, 1,1,1,1, 1,0,0,1, 1,1,0,0, 1,0,1,1]

print(xorBytes(n,m))
  

(извиняюсь, я не смог включить последние 3 строки в пример кода)

вывод из этой программы выглядит следующим образом:

 [1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1]
  

это то, что должно быть выведено вместе с «newR: «

эта ошибка возникает в каждом раунде на данный момент, когда я XOR L(i-1) с помощью F(E(R(i-1) XOR K(i)))

Я точно не знаю, что вызывает эту ошибку, но переменная, которую я использую для хранения этого результата, вообще не использовалась до ее создания там. Метод XOR, который я использую, используется ранее и после, только в этом месте в каждом раунде он неверен. Каждый раз на этом этапе результатом становится список всех единиц правильного размера. два списка, введенные в мой метод XOR, выводятся ранее, поэтому они существуют и содержат правильные элементы.

Я был бы признателен за любую помощь в этом. Как упоминалось в начале, это, скорее всего, скорее проблема python, чем проблема DES.

Комментарии:

1. Не могли бы вы привести более минимальный пример? Это некоторый код для чтения..

2. на предоставленном изображении последние 3 строки — «L0: …», «F1: …» и «newR: …». newR может быть L0 XOR ИЛИ F1. последний приведенный пример кода — это моя функция XOR, а также пример того, как эти два проходят через нее. при изоляции проблемы нет. Проблема возникает только в каждом раунде при последнем вызове XOR

3. в большом примере кода предпоследним методом является мой метод шифрования. вот где все происходит. строка, в которой существует эта проблема, окружена комментариями с надписью «начало проблемы» «конец проблемы»

Ответ №1:

Проблема в том, что вы смешиваете типы … иногда вы используете список символов '0' , '1' а иногда список чисел 0 и 1 .

В Python 0 == '0' будет возвращен False и, следовательно, X-Or будет всеми единицами.

Просто преобразуйте все, чтобы использовать символы или все, чтобы использовать числа, не смешивайте их.

Для других типов сравнения (например < ) Python 3 выдал бы ошибку, но для проверки равенства разные типы просто сравнивают разные, независимо от того, какое значение.