XOR'ing цепочки - PullRequest
0 голосов
/ 21 апреля 2020

Я пытаюсь реализовать шифрование / дешифрование открытого текста RC4, и некоторое время я застрял на шаге XOR.

Мой код выглядит так:

def byteXOR(a, b):
    #TODO take two lists of byte string and return a list with the xor product of them
    u = a.split()
    v = b.split()
    print('Fst: \t {}'.format(u))
    print('Snd: \t {} \n'.format(v))

    '''Fill inn 0' if a bit is shorter than the other'''
    for x,y in zip(u, v):
        if len(x) != len(y):
            if len(x) < len(y):
                x.zfill(len(y) - len(x))
            elif len(x) > len(y):
                y.zfill(len(x) - len(y))

    xor = [ord(x) ^ ord(y) for (x, y) in zip(a, b)]
    print('Fst: \t {}'.format(u))
    print('Snd: \t {}'.format(v))
    print('XOR: \t {}'.format(xor))
    return xor

p = "1111 1010001 10111111 11111010 10101011"
q = "1101000 1100101 1101100 1101100 1101111"
byteXOR(p, q)

Я получаю этот вывод:

Fst:     ['1111', '1010001', '10111111', '11111010', '10101011']
Snd:     ['1101000', '1100101', '1101100', '1101100', '1101111'] 

Fst:     ['1111', '1010001', '10111111', '11111010', '10101011']
Snd:     ['1101000', '1100101', '1101100', '1101100', '1101111']
XOR:     [0, 0, 1, 0, 16, 1, 0, 17, 1, 1, 0, 1, 17, 1, 1, 17, 0, 0, 1, 0, 0, 16, 1, 17, 0, 0, 1, 1, 0, 0, 16, 17, 1, 0, 0, 0, 1, 0, 0]

Первая проблема, которую я не могу решить, это как убедиться, что битовые строки имеют одинаковую длину, я использовал встроенный метод zfill (), но когда я распечатайте списки они без изменений.

Вторая проблема, с которой я столкнулся, заключается в том, как получить желаемый результат произведения XOR n-ых элементов из каждого списка, например:

Fst:      ['0001111', '1010001', '10111111', '11111010', '10101011']
Snd:      ['1101000', '1100101', '01101100', '01101100', '01101111']
XOR:      ['0110011', '0110100', '11010011', '10010110', '11000100']

Ответы [ 3 ]

1 голос
/ 21 апреля 2020

У вас это работает?

def byteXOR(a, b):
    u = [int(bits, 2) for bits in a.split()]
    v = [int(bits, 2) for bits in b.split()]
    xor =  [f ^ s for (f, s) in zip(u, v)]
    print(" ".join([bin(bits).replace("0b", "") for bits in xor]))
    return xor

p = "1111 1010001 10111111 11111010 10101011"
q = "1101000 1100101 1101100 1101100 1101111"
byteXOR(p, q)
1 голос
/ 21 апреля 2020

Что касается XOR, вам нужно преобразовать str s в int s, использовать ^, затем преобразовать в bin представление, чтобы сделать его между соответствующим элементом вашего списка, который вы можете использовать map, то есть:

Fst = ['0001111', '1010001', '10111111', '11111010', '10101011']
Snd = ['1101000', '1100101', '01101100', '01101100', '01101111']
result = list(map(lambda x,y: bin(int(x,2)^int(y,2)), Fst, Snd))
print(result)

Вывод

['0b1100111', '0b110100', '0b11010011', '0b10010110', '0b11000100']

Обратите внимание, что bin возвращает представление, начинающееся с 0b и как можно меньше di git, поэтому, если вы хотите иметь фиксированную ширину без 0b вам нужно отбросить два первых символа, а затем использовать zfill т.е.

final_result = [i[2:].zfill(8) for i in result]
print(final_result)

Вывод:

['01100111', '00110100', '11010011', '10010110', '11000100']

Обратите внимание на второй необязательный аргумент для функции int, позволяющей указать базу число, это может быть любое значение от 2 до 36. Например:

print(int('FFF',16))

выходы:

4095

и т. Д.

0 голосов
/ 21 апреля 2020

Для вашей первой проблемы str.zfill() возвращает новую строку, она не изменяет исходную строку. Таким образом, вы должны переназначить его своим переменным:

for x,y in zip(u, v):
    if len(x) != len(y):
        if len(x) < len(y):
            x = x.zfill(len(y) - len(x))
        elif len(x) > len(y):
            y = y.zfill(len(x) - len(y))

Для вашей второй проблемы вы можете привести строки к int() и передать параметр base=2, чтобы сказать его в двоичном виде. Затем вы можете выполнить XOR '^' для целых чисел, а затем привести его обратно к двоичной строке, используя bin()

x = '0001111'
y = '1101000'

x = int(x, base=2)
y = int(y, base=2)

z = str(bin(x ^ y))[2:]  # remove the trailing 0b from the string
print(z)

Вывод:

1100111

Это, как говорится, так как int(string, base=2) преобразует строку в целые числа, вам действительно не нужно сначала zfill() байтов, и вы можете использовать zip(), чтобы сделать это в одной строке следующим образом:

p = "1111 1010001 10111111 11111010 10101011"
q = "1101000 1100101 1101100 1101100 1101111"

r = [bin(int(x, base=2) ^ int(y, base=2))[2:].zfill(8) for x, y in zip(p.split(' '), q.split(' '))]

print(' '.join(r))

Вывод:

01100111 00110100 11010011 10010110 11000100
...