Mapa da aula
Aula 04 publicada. Mapa, exemplo, EX010.
flowchart TD
N0["4.1 Bytes não são texto"]
N1["4.2 Usar o hashlib"]
N2["4.3 Formatos canônicos"]
N3["Síntese"]
N0 --> N1 --> N2 --> N3
N3 --> EX["Exemplo resolvido"]
EX --> Q["Exercício EX010"]
Desenho lógico
flowchart LR
N0["4.1 Bytes não são texto"]
N1["4.2 Usar o hashlib"]
N2["4.3 Formatos canônicos"]
N3["Síntese"]
N0 --> N1 --> N2 --> N3 --> Q["EX010"]
[4.1 Bytes não são texto]
|
v
[4.2 Usar o hashlib]
|
v
[4.3 Formatos canônicos]
|
v
[Síntese]
|
v
[Exemplo resolvido] --> [Exercício EX010]
Objetivos de aprendizagem
Você vai (1) representar corretamente bytes, texto e hexadecimal; (2) usar as funções de hash da biblioteca padrão; (3) evitar erros comuns de codificação que quebram verificações criptográficas.
4.1 Bytes não são texto
As funções criptográficas operam sobre bytes, e não sobre caracteres. Em Python, "litres" é texto e b"litres" são bytes; converter entre os dois exige uma codificação explícita, como UTF-8. O primeiro bug de Aiyana vem de calcular o hash de uma leitura num sistema com uma codificação diferente da de outro, de modo que leituras iguais produziram digests diferentes. Ela aprende a fixar uma codificação canônica na especificação, a converter uma única vez na fronteira e a manter bytes em todo o interior. O hexadecimal é um formato de exibição de bytes: dois caracteres hexadecimais representam um byte, e é por isso que um digest SHA-256 de 32 bytes é impresso com 64 caracteres.
4.2 Usar o hashlib
O módulo hashlib oferece o SHA-256 e outras funções do FIPS 180-4. Um hash leva uma entrada de qualquer tamanho a um digest de tamanho fixo; mudar um bit muda cerca de metade dos bits da saída. Aiyana escreve pequenas funções que calculam o hash de uma string de leitura e imprimem o digest hexadecimal e depois confere vetores de teste publicados na norma para confirmar que está chamando a função corretamente. Ela aprende a diferença entre chamar update repetidamente num objeto de hash, o que calcula o hash da concatenação, e calcular o hash de cada pedaço separadamente, o que dá resultados diferentes que confundiram seu primeiro teste.
4.3 Formatos canônicos
Dois programas precisam concordar byte a byte antes que hashes ou assinaturas possam coincidir. Aiyana define um formato canônico de leitura para a Ridgeway: ordem fixa dos campos, separadores de ponto e vírgula, litros inteiros e timestamps em UTC com um Z no final. Ela evita litros em ponto flutuante, porque 18342.0 e 18342 teriam hashes diferentes. Ela também evita que a ordem de impressão de um dicionário defina os bytes. Essa disciplina antecipa os capítulos seguintes, em que as leituras são autenticadas com HMAC e o firmware com assinaturas; ambos falham, sem causar dano, mas de modo confuso, se o emissor e o receptor discordarem sobre os bytes exatos.
Exemplo resolvido
Aiyana corrige um teste que falhava codificando as leituras em UTF-8 uma única vez, usando litros inteiros e timestamps em UTC, e depois confirma suas chamadas ao SHA-256 contra um vetor de teste do FIPS 180-4.
Caso sintético. O formato de leitura foi inventado para a Ridgeway; o FIPS 180-4 é real.
Erros e limites
Hash não é cifração: qualquer pessoa pode calcular um digest. Misturar texto e bytes muda os resultados silenciosamente, então especifique as codificações explicitamente.
Exercícios
-
EX010 — Tamanho em hexadecimal. Por que um digest SHA-256 é impresso com 64 caracteres hexadecimais?
Mostrar critérios de avaliação
Rubrica: 3 = 32 bytes, dois caracteres hexadecimais por byte;; 2 = 64 bytes;; 1 = aleatório;; 0 = nenhuma. -
EX011 — Bug de codificação. O que causou os primeiros digests divergentes de Aiyana?
Mostrar critérios de avaliação
Rubrica: 3 = codificações de texto diferentes em dois sistemas para leituras iguais;; 2 = codificação mencionada;; 1 = algoritmo errado;; 0 = nenhuma. -
EX012 — Litros inteiros. Por que o formato canônico usa litros inteiros?
Mostrar critérios de avaliação
Rubrica: 3 = 18342.0 e 18342 produzem bytes e digests diferentes;; 2 = floats são imprecisos;; 1 = estilo;; 0 = nenhuma.
Síntese
A programação criptográfica correta começa com bytes, codificações explícitas, vetores de teste verificados e um formato canônico com que os dois lados concordam.