Texto como número
Um texto vira bytes, e os bytes em fila formam um único inteiro em base 256; é assim que o RSA enxerga a mensagem.
As cifras de chave pública, como o RSA, não enxergam letras: fazem contas com números inteiros. Antes de cifrar, o programa transforma a mensagem num número, em dois passos; depois de decifrar, faz o caminho de volta.
Passo 1: texto em bytes. Cada caractere vira um ou mais bytes, segundo uma codificação. Em ASCII (e em UTF-8, que é igual ao ASCII nas letras sem acento), b é o byte 0x62 (98 em decimal), o é 0x6f (111) e i é 0x69 (105). Em Python, 'boi'.encode() devolve b'boi', os bytes 62 6f 69. Letra acentuada ocupa mais de um byte em UTF-8: 'pão'.encode() dá b'p\xc3\xa3o', quatro bytes para três letras.
Passo 2: bytes em número. Os bytes ficam em fila, como os algarismos de um número escrito em base 256: cada byte é um "algarismo" de 0 a 255, e cada posição vale 256 vezes mais que a da direita. É a mesma ideia de 427 = 4 × 100 + 2 × 10 + 7, com 256 no lugar de 10:
b'boi' = 98 × 65536 + 111 × 256 + 105 × 1
= 6422528 + 28416 + 105
= 6451049
Em hexadecimal a conta some: cada byte ocupa exatamente dois algarismos, e basta juntar os bytes, 0x626f69. Por isso, para ler um número desses, o primeiro passo é passá-lo para hexadecimal.
Em Python, as duas direções:
>>> int.from_bytes('boi'.encode(), 'big')
6451049
>>> hex(6451049)
'0x626f69'
>>> (6451049).to_bytes(3, 'big').decode()
'boi'
O 'big' (de big-endian) diz que o primeiro byte é o mais significativo, o da esquerda, como nos números que escrevemos. Com 'little' a ordem se inverte, e b'boi' vira 6909794: os dois lados precisam combinar a ordem, e nas bibliotecas de criptografia ela é 'big'. Para saber quantos bytes um número n ocupa, use (n.bit_length() + 7) // 8: o número de bits, arredondado para cima em bytes de 8 bits.
Dois cuidados que aparecem na prática:
- Zeros à esquerda somem. Os bytes
00 01viram o número 1, que volta como um byte só,01. Por isso os padrões fixam o tamanho da conversão (no RSA, o tamanho do módulon) em vez de calculá-lo a partir do número. - O número tem limite. No RSA, a mensagem precisa ser menor que o módulo
nda chave: com uma chave de 2048 bits, menos de 256 bytes, e no máximo 190 com o preenchimento recomendado (OAEP com SHA-256). Por isso o RSA quase nunca cifra um texto longo: ele cifra uma chave curta de AES, e o AES cifra o resto.