Skip to content

code-quality: PostGIS encryption key derivation uses raw SHA-256 without proper KDF #380

Description

@evan-zhang11

Description

The derive_key function in backend/src/postgis.rs uses a single SHA-256 hash of the app_secret to derive an AES-256 encryption key:

fn derive_key(secret: &str) -> [u8; 32] {
    let mut hasher = Sha256::new();
    hasher.update(secret.as_bytes());
    let digest = hasher.finalize();
    let mut key = [0_u8; 32];
    key.copy_from_slice(&digest);
    key
}

This key is used to encrypt/decrypt PostGIS connection passwords via AES-256-GCM.

Problem

  • No salt: Using a raw hash without salt means the same secret always produces the same key
  • No iterations/work factor: A single SHA-256 round provides no computational resistance against brute-force attacks
  • Not a proper KDF: SHA-256 is a hash function, not a key derivation function

Mitigating Factors

  • The app_secret is system-generated (UUID-based) with good entropy, stored in the DuckDB database
  • The encrypted passwords are only accessible to someone who already has DB access
  • So the attack surface is limited to scenarios where the app_secret is compromised

Recommendation

Replace with a proper KDF:

  • HKDF (HMAC-based Key Derivation Function) — simple, fast, appropriate when source key material has good entropy
  • PBKDF2/scrypt/argon2 — if the app_secret could ever be weak or user-provided

Example using HKDF:

use hkdf::Hkdf;
use sha2::Sha256;

fn derive_key(secret: &str) -> [u8; 32] {
    let hk = Hkdf::<Sha256>::new(Some(b"mapflow-postgis-encryption"), secret.as_bytes());
    let mut key = [0u8; 32];
    hk.expand(b"aes-256-gcm-key", &mut key).expect("32 bytes");
    key
}

Severity

Low-Medium — The app_secret has good entropy, but the key derivation pattern is incorrect and should use a proper KDF.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions