SecureNotary is a command-line system for cryptographically certifying documents. It combines RSA-4096 digital signatures, AES-256-GCM authenticated encryption, and SHA-256 hashing to provide tamper-evident certification that any third party can independently verify using only the notary's public key.
| Actor | Role |
|---|---|
| Dr. Ferreira (notary) | Generates the RSA-4096 key pair, certifies documents, manages the encrypted vault, and issues JSON certificates. |
| Maria (citizen) | Submits documents for certification and later presents the certificate to third parties. |
| Bank (third-party verifier) | Receives the original document + JSON certificate + public key and independently verifies authenticity and integrity. |
┌───────────────────────────────────────────────────────────┐
│ CERTIFICATION │
│ │
│ Document ──► SHA-256 ──► Hash │
│ ├──► JSON payload │
│ Metadata ───────────────────►│ │
│ └──► RSA-PSS Sign ──► Cert │
│ │
│ Document ──► AES-256-GCM Encrypt ──► vault/doc.enc │
└───────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────┐
│ VERIFICATION │
│ │
│ Certificate (.json) ──► RSA-PSS Verify ◄── Public Key │
│ │ │ │
│ ▼ ▼ │
│ Hash (cert) VALID / INVALID │
│ │ │
│ Document (original) ──► SHA-256 ──► Hash (actual) │
│ │ │
│ Hash comparison ──► MATCH / MISMATCH │
└───────────────────────────────────────────────────────────┘
| Primitive | Algorithm | Parameters | Justification |
|---|---|---|---|
| Hash | SHA-256 | 256-bit digest | 128-bit collision resistance; universally supported |
| Digital Signature | RSA-PSS + SHA-256 | 4096-bit key, MAX salt | Provably secure in the random oracle model; PSS preferred over PKCS#1 v1.5 (avoids ROBOT-class attacks) |
| Symmetric Encryption | AES-256-GCM | 256-bit key, 96-bit nonce | AEAD mode — single primitive for confidentiality + integrity + authenticity |
| Key Derivation | PBKDF2-HMAC-SHA256 | 480 000 iterations, 128-bit salt | Exceeds OWASP 2023 minimum (210 000 iterations); ~0.5 s per operation |
Blob format (vault files):
salt(16 B) ‖ nonce(12 B) ‖ ciphertext+GCM-tag(variable)
- Python 3.11 or later
pip install cryptography
# 1. Clone the repository
git clone https://github.com/rodrigues-francisco/SecureNotary.git
cd SecureNotary
# 2. Install the only dependency
pip install cryptography
# 3. Launch the interactive menu
python src/main.pyThe working directory must be the repository root when running src/main.py; the script enforces this automatically via os.chdir.
The repository ships with a ready-to-use RSA-4096 key pair (password: notario123), two certified documents, and their encrypted vault copies. You can verify a document immediately without generating new keys:
- Select [2] Verify Certificate
- Provide one of the paths below:
| Field | Path |
|---|---|
| Original document | test_docs/contrato_arrendamento.txt |
| Certificate | certificates/<id>.json |
| Public key | keys/public_key.pem |
To test tamper detection, use test_docs/contrato_arrendamento_adulterado.txt instead of the original.
SecureNotary/
├── src/
│ ├── main.py # Interactive CLI entry point
│ ├── crypto_ops.py # Cryptographic primitives (hash, sign, encrypt)
│ ├── key_manager.py # RSA key generation, loading, and persistence
│ └── notary.py # Business logic: certify, verify, recover, list
│
├── certificates/ # Issued certificates (JSON) — demo data included
├── vault/ # AES-256-GCM encrypted documents — demo data included
├── test_docs/ # Sample documents: original + tampered version
├── recovered/ # Output directory for recovered documents
├── keys/ # RSA-4096 demo key pair (password: notario123)
│
├── relatorio.pdf # Technical report
├── .gitignore
├── LICENSE
└── README.md
Each .json certificate contains:
{
"cert_id": "<md5-of-cert-payload>",
"document_name": "contrato_arrendamento.txt",
"sha256": "<sha256-hex>",
"timestamp_utc": "2026-06-15T...",
"notary": "Dr. António Ferreira",
"vault_file": "vault/contrato_arrendamento.txt.enc",
"signature": "<base64-RSA-PSS-signature>"
}The signature field covers the entire JSON payload (minus itself), providing cryptographic binding between the document hash, metadata, and the notary's private key.
Francisco Rodrigues and Igor Freitas — UTAD, 2026