Почему я должен хекслифифицировать перед декодированием в ascii?

Итак, я пытался лучше познакомиться с криптографией, используя python (в частности, pycryptodome), и столкнулся с интересной проблемой, пытаясь декодировать строку байтов в ascii. Пожалуйста, смотрите код ниже:

from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
message = b'Something secret'

random_gen = Crypto.Random.new().read
print("Type of random_gen: {}".format(type(random_gen)))
private_key = RSA.generate(1024, random_gen) # private key
public_key = private_key.publickey() # public key

signer = PKCS1_v1_5.new(private_key) # signer which uses private key
verifier = PKCS1_v1_5.new(public_key) # verifier which uses public key

h = SHA.new(message) # hash of message
print("Hash: {}".format(h.hexdigest()))

signature = signer.sign(h) # sign hashed version of message
print("Signature type = {}".format(type(signature)))
print("Signature: {}".format(binascii.hexlify(signature).decode('ascii')))

Почему в самой последней строке кода я должен сначала hexlify() сигнатуру типа <class 'bytes'> перед декодированием ее в ascii, чтобы я мог прочитать подпись? Почему, если я делаю:

print("Signature: {}".format(signature.decode('ascii')))

Я получаю следующую ошибку:

UnicodeDecodeError: 'ascii' codec can't decode byte 0x88 in position 2: ordinal not in range(128)

Спасибо за помощь.


person DGav    schedule 18.07.2018    source источник
comment
Потому что ASCII относится к 7-битной кодовой странице US-ASCII. Он не может представлять ни один байт, значение которого превышает 0x7F.   -  person Panagiotis Kanavos    schedule 18.07.2018
comment
@PanagiotisKanavos - правильно, но я думал, что шестнадцатеричное преобразование чего-либо просто возвращает шестнадцатеричное представление строки байтов и не меняет саму строку байтов; поэтому, если байт выходит за пределы допустимого диапазона для декодирования с помощью ascii, то почему преобразование его в шестнадцатеричный формат будет работать?   -  person DGav    schedule 18.07.2018


Ответы (1)


signature - это последовательность байтов: каждый элемент представляет собой целое число от 0 до 255 включительно, если вы попытаетесь декодировать его непосредственно в ascii, значения выше 127 вызовут исключение.

binascii.hexlify возвращает новую последовательность байтов со своего входа: для каждого байта со входа на выходе возвращаются два байта, которые представляют собой коды символов ascii, соответствующие шестнадцатеричному представлению входного байта. Таким образом, каждый байт вывода представляет собой символ ascii либо между '0' и '9', либо между 'a' и 'f'. Например, входной байт 128 создает два символа "80", поэтому два байта 56 и 48 (которые являются кодами ascii символов '8' и '0').

Итак, binascii.hexlify производит шестнадцатеричное представление в форме ascii двоичного ввода. decode('ascii'), примененный после binascii.hexlify, не изменяет содержимое, а создает объект типа str.

В python 3.5 и выше вы можете просто использовать метод hex объекта bytes для получения объекта str, содержащего его шестнадцатеричное представление:

signature.hex()
person Jérôme Migné    schedule 21.07.2018
comment
Оооочень интересно. Я не знал, что binascii.hexlify возвращает новую последовательность байтов, и мне придется более внимательно изучить описанный вами метод, с помощью которого это происходит. Спасибо - person DGav; 24.07.2018