Logo UFPR Logo Licenciatura em Computação

CÓDIGO DA DISCIPLINA: DEE345

SEGURANÇA DIGITAL - Aula 7

Professor Jéfer Benedett Dörr

Prof. Jéfer Benedett Dörr

Departamento de Engenharias e Exatas - UFPR/Palotina

Docente de Segurança da Informação

Aula 7: Criptografia I – Hash e Criptografia Simétrica

Objetivos de Aprendizagem

Incidentes de Segurança Notáveis: Banco Inter

O Banco Inter esteve envolvido em dois casos de segurança de grande repercussão. É importante distinguir um do outro, pois foram de naturezas diferentes: um foi um vazamento de dados em massa e o outro uma falha de exposição de informações.

Caso 1: Vazamento de Dados e Extorsão (2018)

O que aconteceu: Este foi o incidente mais grave. Em maio de 2018, veio a público que um hacker obteve acesso a um grande volume de dados de clientes, incluindo informações pessoais, senhas, fotos de documentos e dados de cartões. O invasor tentou extorquir o banco e, com a recusa, vazou os dados.

Causa: A investigação apontou para um acesso não autorizado aos sistemas do banco, possivelmente facilitado por uma falha de segurança interna.

Consequência: O Ministério Público do Distrito Federal e Territórios (MPDFT) abriu uma ação civil pública. O caso foi encerrado com um acordo de R$ 1,5 milhão, que foi destinado a instituições de caridade e órgãos de combate a crimes cibernéticos.

Caso 2: Falha de Exposição de Dados (2019)

O que aconteceu: Em fevereiro de 2019, foi descoberta uma falha de segurança no sistema do banco, e não um vazamento em massa como o anterior. Ao realizar uma transferência para outra conta do Inter, o sistema exibia o nome completo, o CPF e o e-mail do destinatário antes de a transação ser confirmada.

Causa: Foi uma falha de programação na interface de transferência, que expunha mais dados do que o necessário.

Consequência: A vulnerabilidade criava um risco para golpes de phishing direcionados, pois um fraudador poderia obter dados de um cliente apenas sabendo o número de sua conta. O banco corrigiu a falha após ser notificado pela imprensa. Não gerou multa, mas serviu de alerta sobre a importância da privacidade por padrão (privacy by design).

1. Esteganografia

Arte de ocultar mensagens ou arquivos dentro de outro arquivo, sem alterar visivelmente sua aparência.

História

Ferramentas Práticas

steghide


# Embutir secret.txt em cover.jpg
steghide embed -cf cover.jpg -ef secret.txt

# Extrair secret.txt de cover.jpg
steghide extract -sf cover.jpg

# Inspecionar metadados EXIF (exiftool)
sudo apt install libimage-exiftool-perl
exiftool cover.jpg
  

Prática: Baixe um JPG de exemplo e um TXT pequeno; use steghide para esconder e depois recuperar.

Prática: Use OpenStego para ocultar um texto em uma imagem PNG e extraia com Steghide. Compare resultados com OutGuess e discuta resistência a análises.

2. Hash Criptográfico

Função matemática que gera uma “impressão digital” (digest) de tamanho fixo a partir de dados de qualquer tamanho.

Propriedades

Exemplos e comandos


# MD5
echo -n "senha123" | md5sum

# SHA-1
echo -n "senha123" | sha1sum

# SHA-256
echo -n "senha123" | sha256sum

# Criar e verificar checksum de arquivo
sha256sum arquivo.iso > checksum.txt
sha256sum -c checksum.txt

  

Problema das colisões

SHAttered foi o nome dado ao primeiro ataque de colisão bem-sucedido e público contra o algoritmo de hash SHA-1 (um "primo" mais seguro do MD5), realizado pelo Google e pelo CWI Amsterdam em 2017.

Eles conseguiram criar dois arquivos PDF completamente diferentes que, quando analisados pelo algoritmo SHA-1, geravam a mesma impressão digital (hash).

Baixe dois PDFs “shAttered” (https://shattered.io/) e confirme a mesma saída MD5:


md5sum shattered-1.pdf shattered-2.pdf
  

Experimento: Baixe dois PDFs com a mesma colisão MD5 (ex.: disponíveis em shAttered.io) e confirme com md5sum.

3. Fundamentos de Criptografia e Princípio de Kerckhoffs

3.1 Áreas de Estudo

3.2 História Rápida

3.3 Princípio de Kerckhoffs (1883)

“A segurança de um cifrador deve residir unicamente no segredo da chave, não no segredo do algoritmo.”

3.4 Criptografia Moderna

Algoritmos públicos com espaço de chaves tão grande que torna inviável tentativa exaustiva (ex.: AES com chaves de 128/192/256 bits).

Ferramentas

3.5 One-Time Pad (Vernam-Mauborgne)

Único cifrador matematicamente inquebrável se a chave for:

Exemplo via XOR


# Gerar pad aleatório
dd if=/dev/urandom of=pad.bin bs=1024 count=1

# Cifrar com XOR
python3 -c "with open('msg.txt', 'rb') as m, open('pad.bin', 'rb') as p: print([a^b for a,b in zip(m.read(), p.read())])" > cipher.bin
  

Exemplo via XOR


# Gerar pad aleatório
dd if=/dev/urandom bs=1 count=64 of=pad.bin

# Converter mensagem para binário
xxd -p mensagem.txt > msg.hex

# XOR byte a byte
paste <(xxd -p pad.bin) msg.hex | \
  awk '{printf "%02x", strtonum("0x"$1) ^ strtonum("0x"$2)}' > cipher.hex

# Para decifrar
paste <(xxd -p pad.bin) cipher.hex | \
  awk '{printf "%02x", strtonum("0x"$1) ^ strtonum("0x"$2)}' | \
  xxd -r -p > mensagem_restored.txt
  

Exemplo de geração de pad aleatório e cifragem com XOR (em Linux):


head -c 1024 /dev/urandom > pad.bin

xxd -p mensagem.txt > message.hex
xxd -p pad.bin > pad.hex

# XOR byte a byte
paste -d' ' pad.hex message.hex | \
  awk '{printf "%02x", strtonum("0x"$1) ^ strtonum("0x"$2)}' > cipher.hex
    

Prática: Use Cryptool para simular uma Cifra de César e quebre-a com análise de frequência. Implemente um One-Time Pad em SageMath.

4. Criptografia Simétrica

Mesma chave para cifrar e decifrar. É rápida e adequada para grandes volumes de dados, mas requer compartilhamento seguro da chave.

4.1 Algoritmos Clássicos

4.2 AES (Advanced Encryption Standard)

Padrão atual, suporta chaves de 128, 192 e 256 bits.

4.3 Modos de Operação

GCM oferece autenticação, enquanto ECB é inseguro. Teste falhas com openssl.


# AES-256-CBC
openssl enc -aes-256-cbc -salt \
  -in segredo.txt -out segredo.enc \
  -pass pass:"MinhaCh@ve123"

# AES-256-GCM (autenticado)
openssl enc -aes-256-gcm -salt \
  -in segredo.txt -out segredo_gcm.enc \
  -pass pass:"MinhaCh@ve123"

# Descriptografar CBC
openssl enc -d -aes-256-cbc \
  -in segredo.enc -out dec.txt \
  -pass pass:"MinhaCh@ve123"

# Descriptografar GCM
openssl enc -d -aes-256-gcm \
  -in segredo_gcm.enc -out dec_gcm.txt \
  -pass pass:"MinhaCh@ve123"
  

Prática: Cifre um arquivo em GCM, altere bytes do ciphertext e observe falha de autenticação ao decifrar.

Prática: Criptografe um arquivo com openssl em AES-256-GCM e modifique o ciphertext para observar falhas. Implemente AES-CBC com PyCryptodome em Python.

🔐 Guia de Criptografia

OpenSSL AES-256-GCM e Python AES-CBC

🛡️ Parte 1: OpenSSL com AES-256-GCM

1. Criptografar um arquivo

Passo 1: Criar um arquivo de teste
echo "Dados confidenciais para teste" > arquivo.txt
Passo 2: Criptografar com AES-256-GCM
openssl enc -aes-256-gcm -in arquivo.txt -out arquivo.enc -k minhasenha

2. Observar falhas modificando o ciphertext

Passo 3: Fazer backup do arquivo criptografado
cp arquivo.enc arquivo_backup.enc
Passo 4: Modificar o ciphertext (corromper dados)
# Modificar alguns bytes do arquivo criptografado
echo "dados_corrompidos" >> arquivo.enc
Passo 5: Tentar descriptografar o arquivo modificado
openssl enc -d -aes-256-gcm -in arquivo.enc -out arquivo_desc.txt -k minhasenha
⚠️ Resultado esperado: O OpenSSL falhará na descriptografia devido à verificação de integridade do GCM, mostrando um erro de autenticação.

🐍 Parte 2: Implementação AES-CBC com PyCryptodome

1. Instalação

Instalar PyCryptodome:
pip install pycryptodome

2. Código Python completo

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
import base64

class AESCipher:
    def __init__(self, key):
        # Garante que a chave tenha 32 bytes (256 bits)
        self.key = key.ljust(32)[:32].encode('utf-8')
    
    def encrypt(self, plaintext):
        """Criptografa texto usando AES-CBC"""
        # Gera IV aleatório de 16 bytes
        iv = get_random_bytes(16)
        
        # Cria cipher em modo CBC
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        
        # Aplica padding PKCS7 e criptografa
        padded_text = pad(plaintext.encode('utf-8'), AES.block_size)
        ciphertext = cipher.encrypt(padded_text)
        
        # Combina IV + ciphertext e codifica em base64
        encrypted_data = base64.b64encode(iv + ciphertext)
        return encrypted_data.decode('utf-8')
    
    def decrypt(self, encrypted_data):
        """Descriptografa texto usando AES-CBC"""
        try:
            # Decodifica de base64
            encrypted_bytes = base64.b64decode(encrypted_data)
            
            # Separa IV (primeiros 16 bytes) do ciphertext
            iv = encrypted_bytes[:16]
            ciphertext = encrypted_bytes[16:]
            
            # Cria cipher em modo CBC
            cipher = AES.new(self.key, AES.MODE_CBC, iv)
            
            # Descriptografa e remove padding
            padded_plaintext = cipher.decrypt(ciphertext)
            plaintext = unpad(padded_plaintext, AES.block_size)
            
            return plaintext.decode('utf-8')
        
        except Exception as e:
            return f"Erro na descriptografia: {str(e)}"

# Exemplo de uso
if __name__ == "__main__":
    # Inicializa o cipher com uma chave
    cipher = AESCipher("minha_chave_secreta_123")
    
    # Texto a ser criptografado
    texto_original = "Este é um texto confidencial para teste!"
    print(f"Texto original: {texto_original}")
    
    # Criptografar
    texto_criptografado = cipher.encrypt(texto_original)
    print(f"Texto criptografado: {texto_criptografado}")
    
    # Descriptografar
    texto_descriptografado = cipher.decrypt(texto_criptografado)
    print(f"Texto descriptografado: {texto_descriptografado}")
    
    # Teste com dados corrompidos
    print("\n--- Teste com dados corrompidos ---")
    dados_corrompidos = texto_criptografado[:-5] + "XXXXX"
    resultado_corrompido = cipher.decrypt(dados_corrompidos)
    print(f"Resultado com corrupção: {resultado_corrompido}")

3. Criptografia de arquivos

def encrypt_file(file_path, key, output_path):
    """Criptografa um arquivo usando AES-CBC"""
    cipher_obj = AESCipher(key)
    
    # Lê o arquivo
    with open(file_path, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Criptografa o conteúdo
    encrypted_content = cipher_obj.encrypt(content)
    
    # Salva arquivo criptografado
    with open(output_path, 'w') as f:
        f.write(encrypted_content)
    
    print(f"Arquivo criptografado salvo em: {output_path}")

def decrypt_file(encrypted_file_path, key, output_path):
    """Descriptografa um arquivo usando AES-CBC"""
    cipher_obj = AESCipher(key)
    
    # Lê arquivo criptografado
    with open(encrypted_file_path, 'r') as f:
        encrypted_content = f.read()
    
    # Descriptografa
    decrypted_content = cipher_obj.decrypt(encrypted_content)
    
    # Salva arquivo descriptografado
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(decrypted_content)
    
    print(f"Arquivo descriptografado salvo em: {output_path}")

# Exemplo de uso com arquivos
encrypt_file('documento.txt', 'minha_chave', 'documento_enc.txt')
decrypt_file('documento_enc.txt', 'minha_chave', 'documento_dec.txt')

🔍 Comparação: GCM vs CBC

AES-256-GCM (OpenSSL)

  • Vantagens: Autenticação integrada, detecta modificações
  • Segurança: Muito alta, modo recomendado
  • Falha: Rejeita dados modificados automaticamente

AES-CBC (Python)

  • Características: Modo clássico, requer padding
  • Segurança: Boa, mas sem verificação de integridade
  • Vulnerabilidade: Susceptível a padding oracle attacks
⚠️ Aviso de Segurança:
  • Use sempre chaves fortes e aleatórias
  • Nunca reutilize IVs com a mesma chave
  • Para produção, prefira AES-GCM
  • Implemente verificação de integridade adicional com CBC

4.4 Comandos práticos com openssl


# Criptografar com AES-256-CBC
openssl enc -aes-256-cbc -salt -in segredo.txt -out segredo.enc -pass pass:"MinhaCh@ve123"

# Descriptografar
openssl enc -d -aes-256-cbc -in segredo.enc -out segredo-decrypted.txt -pass pass:"MinhaCh@ve123"

# Gerar IV aleatório e visualizar em hex
openssl rand -hex 16
  

# OpenSSL AES-256-GCM
openssl enc -aes-256-gcm -salt -in segredo.txt -out segredo.enc -pass pass:"MinhaCh@ve123"

# GnuPG AES-256
gpg --symmetric --cipher-algo AES256 segredo.txt

# PyCryptodome AES-GCM
python3 -c "from Crypto.Cipher import AES; from Crypto.Random import get_random_bytes; key=get_random_bytes(32); nonce=get_random_bytes(12); cipher=AES.new(key, AES.MODE_GCM, nonce=nonce); ciphertext, tag=cipher.encrypt_and_digest(b'segredo'); print(ciphertext, tag)"
  

Prática: Crie um arquivo de texto, cifre com AES-256-GCM (use openssl enc -aes-256-gcm) e experimente modificar bytes do ciphertext para observar falha de autenticação no decrypt.

Prática: Cifragem AES-256-GCM e Verificação de Autenticação

📚 Fundamentos Teóricos

AES-256-GCM (Galois/Counter Mode) é um modo de operação que fornece:

  • Confidencialidade: Cifra de bloco AES de 256 bits
  • Autenticação: Tag GCM (16 bytes) para verificar integridade
  • Nonce: Valor único (12 bytes recomendado) para cada operação

Qualquer modificação no ciphertext ou tag invalida a decifragem.

🔧 Passo a Passo Prático

1. Criar arquivo de texto original

echo "Dado sensível que precisa ser protegido 12345" > documento_original.txt

Verifique o conteúdo: cat documento_original.txt

2. Gerar chave e IV (Initialization Vector)

Chave AES-256 (32 bytes):

openssl rand -hex 32 > chave.aes

Nonce (12 bytes para GCM):

openssl rand -hex 12 > nonce.aes

Visualize os valores gerados:
echo "Chave: $(cat chave.aes)"
echo "Nonce: $(cat nonce.aes)"

3. Cifrar o arquivo com AES-256-GCM

openssl enc -aes-256-gcm \ -in documento_original.txt \ -out documento_cifrado.bin \ -K $(cat chave.aes) \ -iv $(cat nonce.aes) \ -a

Parâmetros importantes:

  • -aes-256-gcm: Algoritmo e modo de operação
  • -K: Chave hexadecimal (32 bytes)
  • -iv: Nonce hexadecimal (12 bytes)
  • -a: Saída em Base64 (opcional, facilita visualização)

4. Modificar o ciphertext (ataque)

A. Versão Base64 (modificação manual):

cat documento_cifrado.bin | base64 --decode > documento_cifrado.raw
hexdump -C documento_cifrado.raw

B. Alterar byte(s) com dd:

printf '\xAA' | dd of=documento_cifrado.raw bs=1 seek=10 count=1 conv=notrunc

C. Converter de volta para Base64:

cat documento_cifrado.raw | base64 > documento_corrompido.bin

⚠️ Tentativa de Decifragem do Arquivo Corrompido

openssl enc -d -aes-256-gcm \ -in documento_corrompido.bin \ -out documento_decifrado.txt \ -K $(cat chave.aes) \ -iv $(cat nonce.aes) \ -a

Saída esperada:
bad decrypt
140736581377600:error:1C800064:Provider routines::bad decrypt:../providers/implementations/ciphers/cipher_gcm.c:921:

O GCM detecta a modificação devido à falha na autenticação.

🔍 Análise Técnica do Resultado

A falha ocorre porque:

  1. O GCM calcula um GHASH durante a decifragem
  2. A tag de autenticação (16 bytes final) não corresponde ao ciphertext modificado
  3. O OpenSSL rejeita antes mesmo de tentar decifrar

Compare com CBC: Modificações em AES-CBC não são detectadas, apenas causam "lixo" na saída.

📊 Fluxo Completo do Experimento

    +-------------------+       +---------------+       +-------------------+
    | Arquivo Original  | ----> | Cifragem GCM  | ----> | Ciphertext Válido |
    +-------------------+       +---------------+       +-------------------+
                                                                 |
                                                                 v
    +-------------------+       +---------------+       +-------------------+
    | Decifragem Falha  | <-----| Modificação   | <----- | Ciphertext       |
    +-------------------+       | Maliciosa     |       | Corrompido       |
                                +---------------+       +-------------------+

🧪 Extensão do Experimento

Teste 1: Modificar apenas a tag GCM (últimos 16 bytes):

dd if=/dev/random of=documento_cifrado.raw bs=1 seek=$(($(stat -c%s documento_cifrado.raw)-16)) count=16 conv=notrunc

Teste 2: Usar nonce incorreto:

openssl rand -hex 12 > nonce_errado.aes
openssl enc -d -aes-256-gcm [...] -iv $(cat nonce_errado.aes)

5. Ataques de Dicionário (Exemplo Rápido)

Gerar wordlist


# Crunch: tamanho 6-8 usando letras e números
crunch 6 8 abcdefghijklmnopqrstuvwxyz0123456789 -o wordlist.txt
  

Quebra de hashes


# John the Ripper
john --wordlist=wordlist.txt hashes.txt

# Hydra (FTP)
hydra -l usuario -P wordlist.txt ftp://192.168.1.20
  

Esses comandos devem ser usados em ambiente controlado e autorizado.

Quiz de Avaliação – Aula 7

1. Qual propriedade de uma função hash garante que uma pequena mudança no input produza um hash completamente diferente?

CORRETO! A sensibilidade (avalanche effect) faz com que qualquer mudança mínima no input altere drasticamente o hash.
INCORRETO. A propriedade que garante mudança drástica no digest é a Sensibilidade, não o Determinismo ou Rapidez.

2. Qual comando em Linux gera diretamente o hash SHA-256 de uma string “teste”?

CORRETO! Usando -n evita o newline, e sha256sum gera o hash SHA-256.
INCORRETO. O comando correto é echo -n "teste" | sha256sum, não md5sum ou sha1sum.

3. Qual ferramenta utilizamos para ocultar/extrair mensagens dentro de arquivos JPEG?

CORRETO! O steghide é usado para embutir e extrair dados de imagens sem alterar visivelmente o arquivo.
INCORRETO. A ferramenta correta para esteganografia é steghide, não gpg, openssl ou john.

4. Qual afirmação descreve corretamente o Princípio de Kerckhoffs?

CORRETO! Kerckhoffs afirma que apenas a chave deve ser secreta; o algoritmo pode ser público.
INCORRETO. O Princípio de Kerckhoffs sustenta que a segurança está na chave, não no algoritmo.

5. Qual dos seguintes é um cifrador simétrico que hoje é considerado inseguro pelo tamanho da chave?

CORRETO! O DES usa chaves de apenas 56 bits, hoje vulnerável a força bruta.
INCORRETO. DES é o algoritmo inseguro; AES, Blowfish e Twofish ainda são considerados fortes.

6. Qual modo de operação de AES fornece autenticação de integridade além de confidencialidade?

CORRETO! O modo GCM é autenticado, garantindo tanto confidencialidade quanto integridade.
INCORRETO. Apenas o modo GCM oferece autenticação além de cifra; ECB, CBC e CTR não.

7. Qual característica é essencial para um One-Time Pad ser inquebrável?

CORRETO! O One-Time Pad exige chave verdadeiramente aleatória, do tamanho da mensagem e usada uma única vez.
INCORRETO. Se a chave for reutilizada, o OTP perde sua inviolabilidade. Ela deve ser aleatória, do tamanho da mensagem e usada só uma vez.