Criptografia assimétrica: RSA e chaves públicas e privadas

1. Fundamentos da Criptografia Assimétrica

A criptografia assimétrica representa uma evolução fundamental em relação à criptografia simétrica. Enquanto a criptografia simétrica utiliza uma única chave secreta compartilhada entre as partes para cifrar e decifrar dados, a criptografia assimétrica emprega um par de chaves matematicamente relacionadas: uma chave pública, que pode ser distribuída livremente, e uma chave privada, que deve ser mantida em segredo absoluto.

A segurança do RSA repousa na dificuldade computacional de fatorar números inteiros grandes em seus fatores primos. Enquanto multiplicar dois números primos grandes é trivial, determinar quais primos foram multiplicados para obter um número composto é computacionalmente inviável para números suficientemente grandes. Esta assimetria entre facilidade de multiplicação e dificuldade de fatoração é a base matemática que torna o RSA seguro.

2. Como o RSA Funciona na Prática

O algoritmo RSA envolve três etapas principais: geração de chaves, cifração e decifração.

Geração das chaves:

  1. Escolhem-se dois números primos grandes e distintos, p e q.
  2. Calcula-se n = p × q. O valor n é utilizado como módulo tanto para a chave pública quanto para a privada.
  3. Calcula-se a função totiente de Euler: φ(n) = (p-1) × (q-1).
  4. Escolhe-se um expoente público e tal que 1 < e < φ(n) e e seja coprimo com φ(n). O valor mais comum é e = 65537.
  5. Determina-se o expoente privado d tal que d × e ≡ 1 (mod φ(n)).

A chave pública é composta por (n, e) e a chave privada por (n, d).

Cifração e decifração:

  • Cifração: c = m^e mod n, onde m é a mensagem em formato numérico e c é o texto cifrado.
  • Decifração: m = c^d mod n, onde c é o texto cifrado e m é a mensagem original recuperada.

Tamanhos de chave recomendados:

Atualmente, recomenda-se no mínimo 2048 bits para chaves RSA. Chaves de 1024 bits são consideradas inseguras desde 2015. Para aplicações que exigem segurança de longo prazo (10+ anos), recomenda-se 4096 bits. O custo do aumento de segurança é desempenho: chaves de 4096 bits são aproximadamente 4-8 vezes mais lentas que chaves de 2048 bits.

3. Usos Principais do RSA em Aplicações

Cifração de dados pequenos: O RSA é ideal para cifrar pequenas quantidades de dados, como chaves simétricas (ex: chave AES de 256 bits), tokens de autenticação ou senhas. Devido ao seu custo computacional, não é adequado para cifrar grandes volumes de dados diretamente.

Assinatura digital: O RSA permite que o proprietário da chave privada assine digitalmente um documento. Qualquer pessoa com a chave pública pode verificar a autenticidade e integridade da assinatura. O processo envolve cifrar um hash do documento com a chave privada — qualquer um pode decifrar com a chave pública e comparar o hash.

Troca segura de chaves: Em protocolos como TLS/SSL, o RSA é utilizado para estabelecer um canal seguro. O cliente cifra uma chave simétrica temporária com a chave pública do servidor, e apenas o servidor pode decifrá-la com sua chave privada. A partir daí, a comunicação continua usando criptografia simétrica, que é mais eficiente.

4. Implementação Segura com Código

Abaixo, exemplos utilizando a biblioteca cryptography em Python.

Geração de par de chaves:

from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization

# Gerar chave privada de 2048 bits
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

# Extrair chave pública
public_key = private_key.public_key()

# Serializar chave privada para PEM
private_pem = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.PKCS8,
    encryption_algorithm=serialization.NoEncryption()
)

# Serializar chave pública para PEM
public_pem = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
)

print("Chave privada gerada:")
print(private_pem.decode())
print("\nChave pública gerada:")
print(public_pem.decode())

Cifração e decifração com OAEP (padding seguro):

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

mensagem = b"Mensagem secreta para cifrar com RSA"

# Cifrar com chave pública
cifrado = public_key.encrypt(
    mensagem,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

print(f"Mensagem cifrada (hex): {cifrado.hex()[:50]}...")

# Decifrar com chave privada
decifrado = private_key.decrypt(
    cifrado,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

print(f"Mensagem decifrada: {decifrado.decode()}")

Assinatura e verificação:

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.exceptions import InvalidSignature

dados = b"Documento importante para assinar"

# Assinar com chave privada
assinatura = private_key.sign(
    dados,
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    hashes.SHA256()
)

print(f"Assinatura gerada (hex): {assinatura.hex()[:50]}...")

# Verificar com chave pública
try:
    public_key.verify(
        assinatura,
        dados,
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    print("Assinatura válida!")
except InvalidSignature:
    print("Assinatura inválida!")

5. Riscos Comuns e Erros de Desenvolvimento

Uso de padding inseguro: O padding PKCS#1 v1.5 para cifração é vulnerável a ataques de oráculo (como o ataque Bleichenbacher). Sempre utilize OAEP (Optimal Asymmetric Encryption Padding) para cifração e PSS (Probabilistic Signature Scheme) para assinaturas.

Tamanho de chave insuficiente: Chaves RSA com menos de 2048 bits são consideradas inseguras. Chaves de 1024 bits podem ser quebradas por agências governamentais e organizações com recursos computacionais significativos.

Reutilização inadequada de chaves: Utilizar a mesma chave RSA para cifração e assinatura pode introduzir vulnerabilidades. Em protocolos bem projetados, chaves diferentes são usadas para cada propósito.

6. Boas Práticas para Devs

  • Nunca armazene chaves privadas no código-fonte ou em variáveis de ambiente de repositórios. Utilize sistemas de gerenciamento de segredos como HashiCorp Vault, AWS KMS ou Azure Key Vault.
  • Utilize bibliotecas consolidadas e atualizadas como OpenSSL, Bouncy Castle (Java) ou a biblioteca cryptography (Python). Evite implementar algoritmos criptográficos manualmente.
  • Combine RSA com criptografia simétrica para lidar com grandes volumes de dados. Gere uma chave AES aleatória, cifre os dados com AES e cifre apenas a chave AES com RSA (criptografia híbrida).

7. Limitações e Alternativas ao RSA

Desempenho: RSA é significativamente mais lento que criptografia de curva elíptica (ECC) para níveis equivalentes de segurança. Uma chave RSA de 3072 bits oferece segurança comparável a uma chave ECC de 256 bits, mas com desempenho muito inferior.

Ameaça quântica: Algoritmos quânticos, como o algoritmo de Shor, podem quebrar o RSA em tempo polinomial. Embora computadores quânticos práticos ainda não existam, sistemas que precisam de segurança de longo prazo devem considerar criptografia pós-quântica.

Alternativas modernas: Para novas aplicações, considere:
- ECDSA (Elliptic Curve Digital Signature Algorithm) para assinaturas
- Ed25519 para assinaturas com melhor desempenho e segurança
- Curvas elípticas Diffie-Hellman (ECDH) para troca de chaves

O RSA continua sendo amplamente utilizado e é perfeitamente adequado para muitos cenários, especialmente em sistemas legados e infraestrutura de chave pública (PKI). No entanto, para novos projetos, avalie se alternativas baseadas em curvas elípticas atendem melhor aos requisitos de desempenho e segurança.

Referências