#!/usr/bin/env python3
import binascii
var=binascii.a2b_qp("hello")
key=binascii.a2b_qp("supersecretkey")[:len(var)]
print(binascii.b2a_qp(var))
print(binascii.b2a_qp(key))
#here i want to do an XOR operation on the bytes in var and key and place them in 'encryption': encryption=var XOR key
print(binascii.b2a_qp(encrypted))
Si quelqu'un pouvait m'éclairer sur la façon dont je pouvais accomplir cela, je serais très heureux. Très nouveau pour toutes les conversions de type de données, alors oui ... la lecture du wiki python n'est pas aussi claire que je le voudrais :(.
Il semble que ce que vous devez faire est XOR chacun des caractères du message avec le caractère correspondant dans la clé. Cependant, pour ce faire, vous avez besoin d'un peu d'interconversion en utilisant ord
et chr
, car vous ne pouvez que des nombres xor, pas des chaînes:
>>> encrypted = [ chr(ord(a) ^ ord(b)) for (a,b) in Zip(var, key) ]
>>> encrypted
['\x1b', '\x10', '\x1c', '\t', '\x1d']
>>> decrypted = [ chr(ord(a) ^ ord(b)) for (a,b) in Zip(encrypted, key) ]
>>> decrypted
['h', 'e', 'l', 'l', 'o']
>>> "".join(decrypted)
'hello'
Notez que binascii.a2b_qp("hello")
convertit simplement une chaîne en une autre chaîne (mais éventuellement avec un codage différent).
Votre approche et mon code ci-dessus ne fonctionneront que si la clé est au moins aussi longue que le message. Cependant, vous pouvez facilement répéter la clé si nécessaire en utilisant itertools.cycle
:
>>> from itertools import cycle
>>> var="hello"
>>> key="xy"
>>> encrypted = [ chr(ord(a) ^ ord(b)) for (a,b) in Zip(var, cycle(key)) ]
>>> encrypted
['\x10', '\x1c', '\x14', '\x15', '\x17']
>>> decrypted = [ chr(ord(a) ^ ord(b)) for (a,b) in Zip(encrypted, cycle(key)) ]
>>> "".join(decrypted)
'hello'
Pour résoudre le problème des caractères unicode/multi-octets (soulevé dans les commentaires ci-dessous), on peut convertir la chaîne (et la clé) en octets, les compresser ensemble, puis effectuer le XOR, quelque chose comme:
>>> var=u"hello\u2764"
>>> var
'hello❤'
>>> encrypted = [ a ^ b for (a,b) in Zip(bytes(var, 'utf-8'),cycle(bytes(key, 'utf-8'))) ]
>>> encrypted
[27, 16, 28, 9, 29, 145, 248, 199]
>>> decrypted = [ a ^ b for (a,b) in Zip(bytes(encrypted), cycle(bytes(key, 'utf-8'))) ]
>>> decrypted
[104, 101, 108, 108, 111, 226, 157, 164]
>>> bytes(decrypted)
b'hello\xe2\x9d\xa4'
>>> bytes(decrypted).decode()
'hello❤'
Le premier est basé sur Zip :
def encrypt1(var, key):
return bytes(a ^ b for a, b in Zip(var, key))
Le second utilise int.from_bytes et int.to_bytes :
def encrypt2(var, key):
key = key[:len(var)]
int_var = int.from_bytes(var, sys.byteorder)
int_key = int.from_bytes(key, sys.byteorder)
int_enc = int_var ^ int_key
return int_enc.to_bytes(len(var), sys.byteorder)
Tests simples:
assert encrypt1(b'hello', b'supersecretkey') == b'\x1b\x10\x1c\t\x1d'
assert encrypt2(b'hello', b'supersecretkey') == b'\x1b\x10\x1c\t\x1d'
Tests de performances avec var
et key
faisant 1000 octets de long:
$ python3 -m timeit \
-s "import test_xor;a=b'abcdefghij'*100;b=b'0123456789'*100" \
"test_xor.encrypt1(a, b)"
10000 loops, best of 3: 100 usec per loop
$ python3 -m timeit \
-s "import test_xor;a=b'abcdefghij'*100;b=b'0123456789'*100" \
"test_xor.encrypt2(a, b)"
100000 loops, best of 3: 5.1 usec per loop
L'approche entière semble être beaucoup plus rapide.