Projeto 04: Criptografia Simétrica de Bloco: AES-CBC vs AES-GCM 🔒
Escopo do Projeto
Objetivo: Implementar cifragem de arquivos com o padrão AES de 256 bits, analisando os riscos de vazamento e ataques de padding oracle no modo CBC e dominando a integridade autenticada no modo moderno GCM (AEAD).
🎯 1. Contexto & Desafio Prático
A cifragem de dados em repouso exige a escolha correta do modo de operação de cifras de bloco. Você construirá uma ferramenta de terminal de cifragem e decifragem de arquivos sensíveis com AES-256, demonstrando por que o modo GCM impede adulterações de bits que passavam despercebidas no modo CBC.
📋 2. Requisitos Técnicos Obrigatórios
- R1 (Implementação com AES-256-GCM): Utilizar chave de 256 bits gerada com CSPRNG e Nonce criptograficamente único de 96 bits (12 bytes).
- R2 (Demonstração do Falha do CBC): Demonstrar o ataque de manipulação de bits (Bit-Flipping Attack) no modo CBC sem detecção de corrupção.
- R3 (Validação da Tag de Autenticação em GCM): Comprovar que qualquer alteração de 1 bit no arquivo cifrado em GCM gera rejeição imediata com exceção
InvalidTag. - R4 (CLI de Cifragem de Arquivos): Construir utilitário CLI:
secure-vault encrypt <file> -k <key>esecure-vault decrypt <file> -k <key>.
📐 3. Diagrama Conceitual & Arquitetura
graph TD
File["Arquivo Confidencial"] --> Nonce["Nonce Único (12 Bytes)"]
File & Nonce --> AESGCM["Cifra AES-256-GCM (AEAD)"]
Key["Chave de 256 bits"] --> AESGCM
AESGCM --> Encrypted["Envelope Cifrado [Nonce + Ciphertext + AuthTag]"]
Encrypted --> Attack{"Atacante adultera 1 bit no disco"}
Attack --> DecryptFail["Decifragem rejeitada: Tag Inválida! Integridade Garantida."]
style File fill:#e1f5fe,stroke:#01579b
style AESGCM fill:#fff3e0,stroke:#e65100
style Encrypted fill:#e8f5e9,stroke:#2e7d32
style DecryptFail fill:#ffebee,stroke:#c62828 💻 4. Especificação Técnica & Código de Referência
// aes_vault_cli.py
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
def encrypt_file(filepath: str, key: bytes, output_path: str):
with open(filepath, 'rb') as f:
plaintext = f.read()
aesgcm = AESGCM(key)
nonce = os.urandom(12)
ciphertext = aesgcm.encrypt(nonce, plaintext, None)
with open(output_path, 'wb') as f:
f.write(nonce + ciphertext)
print(f"Arquivo cifrado com sucesso em: {output_path}")
def decrypt_file(filepath: str, key: bytes, output_path: str):
with open(filepath, 'rb') as f:
data = f.read()
nonce, ciphertext = data[:12], data[12:]
aesgcm = AESGCM(key)
plaintext = aesgcm.decrypt(nonce, ciphertext, None) # Lança InvalidTag se violado
with open(output_path, 'wb') as f:
f.write(plaintext)
print(f"Arquivo decifrado e verificado com sucesso em: {output_path}")
📦 5. Critérios de Avaliação e Entrega
- Cifragem e decifragem de arquivos executando sem erros em AES-256-GCM.
- Teste de corrupção intencional de bytes comprovando a rejeição pelo GCM.
- Utilização estrita de vetores de inicialização de alta entropia sem repetição.