From 47104db99b3ae41b4920ab353c5d247a5d459475 Mon Sep 17 00:00:00 2001 From: aitbc Date: Thu, 23 Apr 2026 17:26:41 +0200 Subject: [PATCH] security: replace SHA-256 with PBKDF2-HMAC-SHA256 for key derivation - scripts/utils/keystore.py: use PBKDF2 with 100,000 iterations - cli/keystore_auth.py: use PBKDF2 with 100,000 iterations - cli/aitbc_cli.py: use PBKDF2 with 100,000 iterations - apps/agent-coordinator/scripts/agent_daemon.py: use PBKDF2 with 100,000 iterations Fixes 4/25 CodeQL alerts related to weak cryptographic hashing. Note: cli/utils/__init__.py already uses Argon2 which is more secure. --- apps/agent-coordinator/scripts/agent_daemon.py | 4 ++-- cli/aitbc_cli.py | 4 ++-- cli/keystore_auth.py | 5 +++-- scripts/utils/keystore.py | 6 +++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/agent-coordinator/scripts/agent_daemon.py b/apps/agent-coordinator/scripts/agent_daemon.py index 8fafb574..a3af63c4 100755 --- a/apps/agent-coordinator/scripts/agent_daemon.py +++ b/apps/agent-coordinator/scripts/agent_daemon.py @@ -68,8 +68,8 @@ def decrypt_wallet(keystore_path: Path, password: str) -> bytes: else: salt = bytes.fromhex(kdfparams.get('salt', '')) - # Simple KDF: hash(password + salt) - matches scripts/utils/keystore.py - dk = hashlib.sha256(password.encode() + salt).digest() + # Use PBKDF2 for secure key derivation (100,000 iterations for security) + dk = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000, dklen=32) fernet_key = base64.urlsafe_b64encode(dk) f = Fernet(fernet_key) diff --git a/cli/aitbc_cli.py b/cli/aitbc_cli.py index 4b4fbc39..76cdc5aa 100755 --- a/cli/aitbc_cli.py +++ b/cli/aitbc_cli.py @@ -77,8 +77,8 @@ def decrypt_private_key(keystore_path: Path, password: str) -> str: # Fallback for older format salt = bytes.fromhex(kdfparams.get('salt', '')) - # Simple KDF: hash(password + salt) - matches scripts/utils/keystore.py - dk = hashlib.sha256(password.encode() + salt).digest() + # Use PBKDF2 for secure key derivation (100,000 iterations for security) + dk = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000, dklen=32) fernet_key = base64.urlsafe_b64encode(dk) f = Fernet(fernet_key) diff --git a/cli/keystore_auth.py b/cli/keystore_auth.py index cc205f89..5c33bdd2 100644 --- a/cli/keystore_auth.py +++ b/cli/keystore_auth.py @@ -17,11 +17,12 @@ from cryptography.fernet import Fernet def derive_key(password: str, salt: bytes = b"") -> tuple[bytes, bytes]: - """Derive a 32-byte key from the password using SHA-256.""" + """Derive a 32-byte key from the password using PBKDF2-HMAC-SHA256.""" if not salt: import secrets salt = secrets.token_bytes(16) - dk = hashlib.sha256(password.encode() + salt).digest() + # Use PBKDF2 for secure key derivation (100,000 iterations for security) + dk = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000, dklen=32) return base64.urlsafe_b64encode(dk), salt diff --git a/scripts/utils/keystore.py b/scripts/utils/keystore.py index f675f7a1..be9bcf2b 100644 --- a/scripts/utils/keystore.py +++ b/scripts/utils/keystore.py @@ -19,11 +19,11 @@ from cryptography.fernet import Fernet def derive_key(password: str, salt: bytes = b"") -> bytes: - """Derive a 32-byte key from the password using SHA-256.""" + """Derive a 32-byte key from the password using PBKDF2-HMAC-SHA256.""" if not salt: salt = secrets.token_bytes(16) - # Simple KDF: hash(password + salt) - dk = hashlib.sha256(password.encode() + salt).digest() + # Use PBKDF2 for secure key derivation (100,000 iterations for security) + dk = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000, dklen=32) return base64.urlsafe_b64encode(dk), salt