Pular para o conteúdo
Todos os conceitos

Modo ECB

O ECB cifra cada bloco de 16 bytes sozinho; blocos iguais saem iguais, e a forma da mensagem aparece no cifrado.

O AES é uma cifra de bloco: recebe exatamente 16 bytes e uma chave, e devolve 16 bytes que parecem aleatórios. Para uma mesma chave, ele funciona como uma tabela fixa: o mesmo bloco de entrada dá sempre o mesmo bloco de saída. Uma mensagem maior é cortada em blocos de 16 bytes (o último é completado com preenchimento, como o PKCS#7), e o modo de operação diz como esses blocos se encadeiam.

O modo mais simples, o ECB (Electronic Codebook, "livro de códigos"), não encadeia nada: cada bloco é cifrado sozinho, com a mesma chave. A consequência: dois blocos iguais na mensagem viram dois blocos iguais no cifrado. O conteúdo fica escondido; a repetição, não.

Um exemplo trabalhado, com uma planilha em que cada linha tem 16 bytes, em Python com a biblioteca pycryptodome:

>>> from Crypto.Cipher import AES
>>> chave = b'chave-de-exemplo'     # 16 bytes: AES-128 (só para o exemplo)
>>> msg = b'vaca;preta;300kg' + b'boi;branco;410kg' + b'vaca;preta;300kg'
>>> c = AES.new(chave, AES.MODE_ECB).encrypt(msg)
>>> [c[i:i + 16].hex()[:8] for i in range(0, len(c), 16)]
['ad00bab7', '6dd9e52c', 'ad00bab7']

O primeiro e o terceiro blocos cifrados são idênticos (a lista mostra só os 8 primeiros algarismos hexadecimais de cada um, mas os 32 batem). Quem intercepta não sabe o que está escrito, mas sabe que a linha 1 e a linha 3 são iguais. Numa imagem é pior: áreas de cor lisa viram blocos repetidos, e o contorno do desenho passa inteiro para o cifrado. Num banco de dados, dois clientes com o mesmo valor ficam com o mesmo cifrado.

No modo CBC (Cipher Block Chaining, "encadeamento de blocos"), cada bloco da mensagem é misturado (XOR) com o bloco cifrado anterior antes de passar pelo AES, e o primeiro, com um IV (vetor de inicialização): 16 bytes sorteados a cada mensagem. A mesma planilha:

>>> import os
>>> iv = os.urandom(16)
>>> c = AES.new(chave, AES.MODE_CBC, iv).encrypt(msg)
>>> [c[i:i + 16].hex()[:8] for i in range(0, len(c), 16)]
['2adfa50a', 'f4205c77', 'ac81f1c4']

Os três saem diferentes, e o resultado muda a cada execução, porque o IV muda. O IV não é segredo: vai junto com o cifrado, em geral nos 16 primeiros bytes.

ECB cada bloco cifrado sozinho, com a mesma chave mensagem cifrado vaca;preta;300kg boi;branco;410kg vaca;preta;300kg AES AES AES ad00bab7… 6dd9e52c… ad00bab7… blocos iguais na entrada, blocos iguais na saída CBC cada bloco misturado com o cifrado anterior mensagem cifrado vaca;preta;300kg boi;branco;410kg vaca;preta;300kg IV sorteado AES AES AES 2adfa50a… f4205c77… ac81f1c4… três blocos diferentes, e outros a cada IV
No ECB, cada bloco passa pelo AES sozinho, e as duas linhas vaca;preta;300kg viram o mesmo bloco ad00bab7; no CBC, cada bloco é misturado com o cifrado anterior, o primeiro com o IV sorteado, e os três saem diferentes.

Para reconhecer ECB num arquivo cifrado, conte os blocos repetidos: blocos = [c[i:i + 16] for i in range(0, len(c), 16)] e compare len(blocos) com len(set(blocos)). Num cifrado bem feito, dois blocos de 16 bytes iguais não aparecem por acaso.

O uso correto. Não use ECB para mais de um bloco. Prefira um modo autenticado, como o GCM, que além de esconder a repetição detecta se alguém mexeu no cifrado. Ele usa um nonce (número usado uma vez) que precisa ser novo a cada mensagem e nunca se repetir com a mesma chave; a biblioteca sorteia um se você não passar:

import os
from Crypto.Cipher import AES
chave = os.urandom(16)                         # chave sorteada de verdade
cifra = AES.new(chave, AES.MODE_GCM)           # nonce novo, sorteado
cifrado, etiqueta = cifra.encrypt_and_digest(msg)
# guarde cifra.nonce, o cifrado e a etiqueta; para abrir:
texto = AES.new(chave, AES.MODE_GCM, nonce=cifra.nonce).decrypt_and_verify(cifrado, etiqueta)

Se um único byte do cifrado ou da etiqueta for alterado, o decrypt_and_verify dá erro em vez de devolver lixo.

Aparece nestes desafios