Pular para o conteúdo
Todos os conceitos

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.

texto bytes inteiro boi 62 6f 69 6451049 0x626f69 .encode() from_bytes to_bytes .decode() peso da posição b = 0x62 = 98 × 65536 6422528 o = 0x6f = 111 × 256 28416 i = 0x69 = 105 × 1 105 6422528 + 28416 + 105 = 6451049 o primeiro byte é o que mais pesa (big-endian)
Com encode, o texto boi vira os bytes 62 6f 69; com from_bytes, os bytes viram o inteiro 6451049, com o primeiro byte pesando 65536, o segundo 256 e o último 1; to_bytes e decode fazem o caminho de volta.

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 01 viram 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ódulo n) 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 n da 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.

Aparece nestes desafios