Claude 24f816b6a3
Consolidate 22 sibling repos into layered organism structure
Place useful parts of the surrounding repos into sica-fondt by layer, per the
body model (Ada = membrane; brain/endocrine/capabilities/knowledge non-Ada):

- brain/        LLM reasoning + providers (dapr, hermes, MoMoA)
- capabilities/ REPRAG sidecars: hermes tools/skills, dapr tools, parallel
                dispatch, A51 channels, and the OSINT cluster
- knowledge/    LORAG corpus: 754 cyber-skills, agency personas, secure-coding,
                MITRE ATT&CK data
- reference/    defensive threat-reference (C3, shhbruh doc) + AdaYaml parser

License handling: AGPL sources (worldosint, advanced_evolution, mercury,
Reticulum) and GPL DeTTECT are SPEC-only clean-room/port descriptions — no
copyleft code copied. MIT/Apache/data parts copied as working trees.

Safety: shhbruh escape/persistence material and C3 covert-C2 kept as reference
only, not wired into the running organism. See CONSOLIDATION.md.

https://claude.ai/code/session_01UehUqEXXJJCsHoA4voCU5c
2026-06-10 06:53:01 +00:00

173 lines
5.3 KiB
Python

#!/usr/bin/env python3
"""Agent for implementing AES-256-GCM encryption for data at rest."""
import os
import json
import argparse
from datetime import datetime
from pathlib import Path
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
SALT_SIZE = 16
NONCE_SIZE = 12
KEY_SIZE = 32 # 256 bits
TAG_SIZE = 16
PBKDF2_ITERATIONS = 600_000
def derive_key(password, salt=None):
"""Derive AES-256 key from password using PBKDF2-HMAC-SHA256."""
if salt is None:
salt = os.urandom(SALT_SIZE)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=KEY_SIZE,
salt=salt,
iterations=PBKDF2_ITERATIONS,
)
key = kdf.derive(password.encode("utf-8"))
return key, salt
def encrypt_file(input_path, output_path, password):
"""Encrypt a file using AES-256-GCM with PBKDF2 key derivation."""
key, salt = derive_key(password)
nonce = os.urandom(NONCE_SIZE)
aesgcm = AESGCM(key)
with open(input_path, "rb") as f:
plaintext = f.read()
ciphertext = aesgcm.encrypt(nonce, plaintext, None)
with open(output_path, "wb") as f:
f.write(salt)
f.write(nonce)
f.write(ciphertext)
return {
"input": str(input_path),
"output": str(output_path),
"original_size": len(plaintext),
"encrypted_size": SALT_SIZE + NONCE_SIZE + len(ciphertext),
"algorithm": "AES-256-GCM",
"kdf": f"PBKDF2-HMAC-SHA256 ({PBKDF2_ITERATIONS} iterations)",
}
def decrypt_file(input_path, output_path, password):
"""Decrypt an AES-256-GCM encrypted file."""
with open(input_path, "rb") as f:
salt = f.read(SALT_SIZE)
nonce = f.read(NONCE_SIZE)
ciphertext = f.read()
key, _ = derive_key(password, salt)
aesgcm = AESGCM(key)
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
with open(output_path, "wb") as f:
f.write(plaintext)
return {
"input": str(input_path),
"output": str(output_path),
"decrypted_size": len(plaintext),
}
def encrypt_directory(dir_path, output_dir, password):
"""Encrypt all files in a directory tree."""
src = Path(dir_path)
dst = Path(output_dir)
dst.mkdir(parents=True, exist_ok=True)
results = []
for filepath in src.rglob("*"):
if filepath.is_file():
rel = filepath.relative_to(src)
out = dst / (str(rel) + ".enc")
out.parent.mkdir(parents=True, exist_ok=True)
result = encrypt_file(str(filepath), str(out), password)
results.append(result)
return results
def generate_random_key():
"""Generate a random AES-256 key."""
key = os.urandom(KEY_SIZE)
return {
"key_hex": key.hex(),
"key_size_bits": KEY_SIZE * 8,
"algorithm": "AES-256",
}
def verify_encryption(original_path, encrypted_path, password):
"""Verify encryption by decrypting and comparing."""
with open(original_path, "rb") as f:
original = f.read()
with open(encrypted_path, "rb") as f:
salt = f.read(SALT_SIZE)
nonce = f.read(NONCE_SIZE)
ciphertext = f.read()
key, _ = derive_key(password, salt)
aesgcm = AESGCM(key)
try:
decrypted = aesgcm.decrypt(nonce, ciphertext, None)
match = original == decrypted
return {"status": "PASS" if match else "FAIL", "content_match": match}
except Exception as e:
return {"status": "FAIL", "error": str(e)}
def main():
parser = argparse.ArgumentParser(description="AES-256-GCM Encryption Agent")
parser.add_argument("--action", required=True,
choices=["encrypt", "decrypt", "encrypt_dir", "genkey", "verify"])
parser.add_argument("--input", help="Input file or directory")
parser.add_argument("--output", help="Output file or directory")
parser.add_argument("--password", help="Encryption password")
parser.add_argument("--report", default="aes_encryption_report.json")
args = parser.parse_args()
report = {"generated_at": datetime.utcnow().isoformat(), "action": args.action}
if args.action == "encrypt":
result = encrypt_file(args.input, args.output, args.password)
report["result"] = result
print(f"[+] Encrypted: {args.input} -> {args.output}")
elif args.action == "decrypt":
result = decrypt_file(args.input, args.output, args.password)
report["result"] = result
print(f"[+] Decrypted: {args.input} -> {args.output}")
elif args.action == "encrypt_dir":
results = encrypt_directory(args.input, args.output, args.password)
report["results"] = results
print(f"[+] Encrypted {len(results)} files")
elif args.action == "genkey":
result = generate_random_key()
report["result"] = result
print(f"[+] Key: {result['key_hex']}")
elif args.action == "verify":
result = verify_encryption(args.input, args.output, args.password)
report["result"] = result
print(f"[+] Verification: {result['status']}")
with open(args.report, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"[+] Report saved to {args.report}")
if __name__ == "__main__":
main()