Ir para o conteúdo

CRYPTO-DESIGN.md — Modelo de Cifragem do Anotae

Documento técnico descrevendo a implementação de criptografia do Anotae. Referência para auditoria de segurança.

Versão: 1.0 Última atualização: 2026-04-30 Implementado em: v0.2


1. Visão geral

O Anotae usa criptografia em múltiplas camadas para proteger dados clínicos em repouso:

Camada 1: OS filesystem encryption (responsabilidade do usuário)
Camada 2: Vault SQLite (futuro: sqlite3mc page-level encryption)
Camada 3: Campo-level encryption (ChaCha20-Poly1305 AEAD) ← IMPLEMENTADO
Camada 4: Integridade SHA-256 por encounter ← IMPLEMENTADO

2. KDF — Derivação de chave-mestra

Algoritmo: Argon2id (RFC 9106, vencedor da Password Hashing Competition 2015)

Parâmetros padrão: - time_cost = 3 (iterações) - memory_cost = 65536 (64 MiB em KiB) - parallelism = 1 - hash_len = 32 (bytes)

Parâmetros fallback (hardware < 4 GB RAM): - time_cost = 2 - memory_cost = 19456 (~19 MiB) - parallelism = 1

Detecção de hardware: os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES"). Se falhar (Windows), assume hardware adequado.

Salt: 32 bytes gerados por secrets.token_bytes(32) na criação do vault. Armazenado em texto claro em vault_meta (necessário para derivar a chave).

Implementação: anotae/persistence/crypto.py::derive_master_key()

3. Derivação de sub-chaves

Algoritmo: HKDF-SHA256 (RFC 5869)

A master key é derivada em 3 sub-chaves com contextos distintos:

Chave Info (contexto HKDF) Uso
vault_key anotae-vault-encryption-key-v1 Criptografia do vault (futuro sqlite3mc) + verificação de senha
field_key anotae-field-encryption-key-v1 Criptografia de campos PII (CPF)
audit_key anotae-audit-mac-key-v1 MAC de audit logs (futuro)

Isolamento: Comprometimento de uma chave não compromete as outras (HKDF com info distinto garante independência).

Implementação: anotae/persistence/crypto.py::derive_keys()

4. Criptografia de campos — ChaCha20-Poly1305

Algoritmo: ChaCha20-Poly1305 AEAD (RFC 8439) - Cifra autenticada (confidencialidade + integridade) - Nonce: 12 bytes gerados por secrets.token_bytes(12) - Tag: 16 bytes de autenticação (embutido no output)

Formato de saída: nonce (12 bytes) || ciphertext || tag (16 bytes)

Campos cifrados atualmente: - professional_cpfprofessional_cpf_encrypted (BLOB no SQLite)

Implementação: - anotae/persistence/crypto.py::encrypt_field() - anotae/persistence/crypto.py::decrypt_field()

5. Verificação de senha

Na criação do vault, um token de verificação é cifrado com vault_key:

encrypt_field(b"anotae-vault-ok-v1", vault_key)

Na abertura, o token é decifrado. Se falhar (InvalidTag), a senha está errada.

Isto evita armazenar hash da senha — a verificação é implícita.

Implementação: anotae/persistence/vault.py::_verify_password()

6. Integridade — SHA-256

Cada encounter tem hash SHA-256 calculado sobre representação canônica JSON (campos clínicos, excluindo hash e audit_log).

Verificação: secrets.compare_digest() para comparação em tempo constante (evita timing attacks).

Implementação: - anotae/persistence/crypto.py::compute_encounter_hash() - anotae/persistence/crypto.py::verify_encounter_hash() - anotae/core/models.py::Encounter.canonical_bytes()

7. Memória — Limpeza de chaves

Best-effort em Python — a linguagem não garante controle total sobre memória.

  • VaultKeys.secure_zero(): zera vault_key, field_key, audit_key via ctypes.memset
  • Chamado em VaultManager.close()
  • Master key zerada imediatamente após derivação das sub-chaves

Limitações conhecidas: Python pode manter cópias em memória (GC, interning). Mitigação completa requer extensão C ou linguagem com controle manual de memória.

Implementação: anotae/persistence/crypto.py::_secure_zero_bytes()

8. Backup

  • Backups são cópias do vault.db (já cifrado em campo-level)
  • Hash SHA-256 do arquivo de backup para verificação de integridade
  • Retenção configurável (padrão 7)

9. Dependências criptográficas

Pacote Versão Uso Licença
argon2-cffi ≥23.1 KDF Argon2id MIT
cryptography ≥42.0 ChaCha20-Poly1305, HKDF-SHA256 Apache-2.0/BSD

Ambas mantidas ativamente com histórico de segurança sólido.

10. Ameaças mitigadas

Ameaça Mitigação
Roubo do vault.db Campos PII cifrados com ChaCha20-Poly1305
Brute-force da senha Argon2id com m=64MiB t=3 (custo alto por tentativa)
Tampering de encounters SHA-256 por encounter + comparação tempo constante
Chave em memória após logout secure_zero (best-effort)
Reuso de nonce Nonce aleatório 12 bytes por operação via secrets

Este documento deve ser revisado a cada mudança no modelo criptográfico.