A biblioteca cryptography é o padrão de fato para realizar operações criptográficas em
Python. Ela é projetada para ser segura e fácil de usar, evitando que desenvolvedores
cometam erros comuns.
Este tutorial irá cobrir os casos de uso mais importantes:
1. Criptografia Simétrica (Fernet): Para cifrar e decifrar dados com uma única chave
secreta.
2. Funções de Hash: Para garantir a integridade de dados.
3. Criptografia Assimétrica (RSA): Para cifrar com uma chave pública e decifrar com uma
chave privada.
4. Assinaturas Digitais (RSA): Para garantir a autenticidade e a integridade de uma
mensagem.
Pré-requisito: Instalação
Primeiro, você precisa instalar a biblioteca. É simples de fazer usando pip:
pip install cryptography
Parte 1: Criptografia Simétrica com Fernet
A criptografia simétrica usa a mesma chave para cifrar e decifrar. É muito rápida e ideal para
cifrar grandes volumes de dados, como arquivos. Fernet é a implementação de alto nível da
biblioteca, que já inclui tudo o que você precisa de forma segura.
Como funciona o Fernet:
● Usa o algoritmo AES-128 no modo CBC para a cifragem.
● Usa HMAC com SHA256 para garantir que a mensagem não foi alterada (autenticidade).
● É "à prova de futuro", pois o formato foi projetado para permitir a atualização dos
algoritmos sem quebrar a compatibilidade.
Passo 1: Gerar uma Chave
A chave é o segredo mais importante. Você só gera uma vez e a armazena de forma segura.
from [Link] import Fernet
# Gera uma nova chave (faça isso apenas uma vez e guarde-a em um lugar seguro!)
chave = Fernet.generate_key()
# A chave é uma sequência de bytes
print(f"Sua chave secreta (guarde com segurança): {chave}")
# Para uso posterior, você pode salvar a chave em um arquivo
with open("minha_chave.key", "wb") as arquivo_chave:
arquivo_chave.write(chave)
Passo 2: Cifrar e Decifrar uma Mensagem
from [Link] import Fernet
# Suponha que você já salvou a chave e está lendo-a de um arquivo
with open("minha_chave.key", "rb") as arquivo_chave:
chave = arquivo_chave.read()
# Crie uma instância do Fernet com a chave
f = Fernet(chave)
# A mensagem que você quer proteger (precisa ser em bytes)
mensagem_original = b"Este eh um segredo que ninguem pode saber."
# Cifrar a mensagem
token_cifrado = [Link](mensagem_original)
print(f"\nMensagem Original: {mensagem_original.decode('utf-8')}")
print(f"Token Cifrado: {token_cifrado}")
# --- Agora, vamos decifrar ---
# Use a mesma instância 'f' (ou crie uma nova com a mesma chave)
mensagem_decifrada = [Link](token_cifrado)
print(f"\nMensagem Decifrada: {mensagem_decifrada.decode('utf-8')}")
# O que acontece se o token for alterado?
token_alterado = token_cifrado[:-1] + b'!' # Alterando o último byte
try:
[Link](token_alterado)
except Exception as e:
print(f"\nTentativa de decifrar token alterado falhou! Erro: {e}")
Parte 2: Funções de Hash (Integridade de Dados)
Um hash é uma "impressão digital" de um dado. É uma via de mão única: fácil de calcular, mas
praticamente impossível de reverter. É usado para verificar se um arquivo ou mensagem foi
alterado.
A biblioteca padrão do Python, hashlib, é excelente para isso, mas o conceito é fundamental
para a criptografia.
import hashlib
# Dados de entrada (precisam ser em bytes)
dados = b"Quero garantir que este texto nao seja alterado."
# Crie um objeto hash usando um algoritmo seguro como o SHA-256
h = hashlib.sha256()
# Atualize o objeto com os dados
[Link](dados)
# Obtenha a "impressão digital" em formato hexadecimal
hash_original = [Link]()
print(f"O hash SHA-256 dos dados originais é:\n{hash_original}")
# Agora, vamos alterar minimamente os dados
dados_alterados = b"Quero garantir que este texto nao seja alterads." # Troquei 'o' por 's'
hash_alterado = hashlib.sha256(dados_alterados).hexdigest()
print(f"\nO hash SHA-256 dos dados alterados é:\n{hash_alterado}")
print(f"\nOs hashes são iguais? {hash_original == hash_alterado}")
Observação: Uma pequena mudança na entrada gera um hash completamente diferente
(efeito avalanche).
Parte 3 e 4: Criptografia Assimétrica e Assinaturas com RSA
A criptografia assimétrica usa um par de chaves:
● Chave Pública: Compartilhada com todos. Usada para cifrar mensagens e verificar
assinaturas.
● Chave Privada: Mantida em segredo absoluto. Usada para decifrar mensagens e criar
assinaturas.
Para essas operações, usamos a camada hazmat (hazardous materials) da biblioteca, que nos
dá mais controle, mas exige mais cuidado.
Passo 1: Gerar o Par de Chaves RSA
from [Link] import rsa
from [Link] import serialization
# Gere uma chave privada RSA
chave_privada = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
# Obtenha a chave pública correspondente
chave_publica = chave_privada.public_key()
# Para armazenar as chaves, precisamos serializá-las
# Salvar a chave privada em formato PEM
pem_privado = chave_privada.private_bytes(
encoding=[Link],
format=[Link].PKCS8,
encryption_algorithm=[Link]() # Para o exemplo, não vamos proteger com
senha
)
with open('chave_privada.pem', 'wb') as f:
[Link](pem_privado)
# Salvar a chave pública em formato PEM
pem_publico = chave_publica.public_bytes(
encoding=[Link],
format=[Link]
)
with open('chave_publica.pem', 'wb') as f:
[Link](pem_publico)
print("Chaves pública e privada salvas em arquivos .pem!")
Passo 2: Cifrar com a Chave Pública e Decifrar com a Chave Privada
from [Link] import padding
from [Link] import hashes
# Mensagem a ser cifrada
mensagem_secreta = b'Dados confidenciais para serem enviados com seguranca.'
# Cifrar usando a chave pública
texto_cifrado = chave_publica.encrypt(
mensagem_secreta,
[Link](
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
print(f"\nTexto Cifrado (RSA):\n{texto_cifrado.hex()}")
# Decifrar usando a chave privada
texto_decifrado = chave_privada.decrypt(
texto_cifrado,
[Link](
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
print(f"\nTexto Decifrado:\n{texto_decifrado.decode('utf-8')}")
Importante: O padding é crucial para a segurança do RSA. Use sempre OAEP para cifragem.
Passo 3: Assinar com a Chave Privada e Verificar com a Chave Pública
A assinatura prova que a mensagem veio de você (autenticidade) e que não foi alterada
(integridade).
from [Link] import padding
from [Link] import hashes
from [Link] import InvalidSignature
# Mensagem ou documento que queremos assinar
documento = b"Este e um contrato importante. Eu concordo com os termos."
# Assinar o documento com a chave privada
assinatura = chave_privada.sign(
documento,
[Link](
mgf=padding.MGF1(hashes.SHA256()),
salt_length=[Link].MAX_LENGTH
),
hashes.SHA256()
)
print(f"\nAssinatura Gerada:\n{[Link]()}")
# --- Agora, outra pessoa com a sua chave pública pode verificar ---
# Verificar a assinatura com a chave pública
try:
chave_publica.verify(
assinatura,
documento,
[Link](
mgf=padding.MGF1(hashes.SHA256()),
salt_length=[Link].MAX_LENGTH
),
hashes.SHA256()
)
print("\nA assinatura e VALIDA. O documento e autentico e integro.")
except InvalidSignature:
print("\nA assinatura e INVALIDA. O documento foi alterado ou nao foi assinado pelo dono da
chave.")
# Teste com um documento alterado
documento_falso = b"Este e um contrato importante. EU NAO concordo com os termos."
try:
chave_publica.verify(assinatura, documento_falso, [Link](...), hashes.SHA256())
except InvalidSignature:
print("\nTeste com documento falso: A assinatura e INVALIDA, como esperado.")
Importante: Para assinaturas, o padding recomendado é o PSS.
Este tutorial cobre os fundamentos essenciais. A biblioteca cryptography é extremamente
poderosa e pode fazer muito mais, mas dominar estes três pilares (simétrica, assimétrica e
hashes) já fornece uma base excelente para qualquer estudante de segurança da
computação.