mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 21:54:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
144 lines
5.2 KiB
Python
144 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for implementing end-to-end encryption (E2EE) for messaging using X25519 + AES-GCM."""
|
|
|
|
import json
|
|
import argparse
|
|
import os
|
|
|
|
try:
|
|
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey
|
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
|
from cryptography.hazmat.primitives import hashes, serialization
|
|
HAS_CRYPTO = True
|
|
except ImportError:
|
|
HAS_CRYPTO = False
|
|
|
|
NONCE_SIZE = 12
|
|
KEY_SIZE = 32
|
|
HKDF_INFO = b"e2ee-messaging-v1"
|
|
|
|
|
|
def generate_keypair():
|
|
"""Generate X25519 key pair for Diffie-Hellman key exchange."""
|
|
private_key = X25519PrivateKey.generate()
|
|
public_key = private_key.public_key()
|
|
priv_bytes = private_key.private_bytes(
|
|
serialization.Encoding.Raw, serialization.PrivateFormat.Raw, serialization.NoEncryption()
|
|
)
|
|
pub_bytes = public_key.public_bytes(serialization.Encoding.Raw, serialization.PublicFormat.Raw)
|
|
return {
|
|
"private_key_hex": priv_bytes.hex(),
|
|
"public_key_hex": pub_bytes.hex(),
|
|
"algorithm": "X25519",
|
|
}
|
|
|
|
|
|
def derive_shared_secret(my_private_hex, their_public_hex):
|
|
"""Derive shared secret using X25519 ECDH + HKDF-SHA256."""
|
|
my_private = X25519PrivateKey.from_private_bytes(bytes.fromhex(my_private_hex))
|
|
their_public = X25519PublicKey.from_public_bytes(bytes.fromhex(their_public_hex))
|
|
shared_key = my_private.exchange(their_public)
|
|
derived_key = HKDF(
|
|
algorithm=hashes.SHA256(), length=KEY_SIZE, salt=None, info=HKDF_INFO
|
|
).derive(shared_key)
|
|
return derived_key
|
|
|
|
|
|
def encrypt_message(message, shared_key_hex):
|
|
"""Encrypt a message using AES-256-GCM with a shared key."""
|
|
key = bytes.fromhex(shared_key_hex)
|
|
nonce = os.urandom(NONCE_SIZE)
|
|
aesgcm = AESGCM(key)
|
|
ciphertext = aesgcm.encrypt(nonce, message.encode("utf-8"), None)
|
|
return {
|
|
"nonce_hex": nonce.hex(),
|
|
"ciphertext_hex": ciphertext.hex(),
|
|
"algorithm": "AES-256-GCM",
|
|
}
|
|
|
|
|
|
def decrypt_message(nonce_hex, ciphertext_hex, shared_key_hex):
|
|
"""Decrypt a message using AES-256-GCM."""
|
|
key = bytes.fromhex(shared_key_hex)
|
|
nonce = bytes.fromhex(nonce_hex)
|
|
ciphertext = bytes.fromhex(ciphertext_hex)
|
|
aesgcm = AESGCM(key)
|
|
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
|
|
return {"plaintext": plaintext.decode("utf-8")}
|
|
|
|
|
|
def simulate_key_exchange(alice_name="Alice", bob_name="Bob"):
|
|
"""Simulate a complete key exchange between two parties."""
|
|
alice_kp = generate_keypair()
|
|
bob_kp = generate_keypair()
|
|
|
|
alice_shared = derive_shared_secret(alice_kp["private_key_hex"], bob_kp["public_key_hex"])
|
|
bob_shared = derive_shared_secret(bob_kp["private_key_hex"], alice_kp["public_key_hex"])
|
|
|
|
keys_match = alice_shared == bob_shared
|
|
return {
|
|
"alice_public_key": alice_kp["public_key_hex"],
|
|
"bob_public_key": bob_kp["public_key_hex"],
|
|
"shared_secret_match": keys_match,
|
|
"shared_key_hex": alice_shared.hex() if keys_match else None,
|
|
"key_exchange": "X25519 ECDH",
|
|
"kdf": "HKDF-SHA256",
|
|
"encryption": "AES-256-GCM",
|
|
}
|
|
|
|
|
|
def demo_full_flow():
|
|
"""Demonstrate complete E2EE message flow."""
|
|
kx = simulate_key_exchange()
|
|
if not kx["shared_secret_match"]:
|
|
return {"error": "Key exchange failed"}
|
|
shared_key = kx["shared_key_hex"]
|
|
test_message = "Hello, this is an end-to-end encrypted message."
|
|
encrypted = encrypt_message(test_message, shared_key)
|
|
decrypted = decrypt_message(encrypted["nonce_hex"], encrypted["ciphertext_hex"], shared_key)
|
|
return {
|
|
"key_exchange": kx,
|
|
"original_message": test_message,
|
|
"encrypted": encrypted,
|
|
"decrypted": decrypted,
|
|
"integrity_check": decrypted["plaintext"] == test_message,
|
|
}
|
|
|
|
|
|
def main():
|
|
if not HAS_CRYPTO:
|
|
print(json.dumps({"error": "cryptography library not installed"}))
|
|
return
|
|
parser = argparse.ArgumentParser(description="E2EE Messaging Agent (X25519 + AES-256-GCM)")
|
|
sub = parser.add_subparsers(dest="command")
|
|
sub.add_parser("keygen", help="Generate X25519 key pair")
|
|
sub.add_parser("exchange", help="Simulate key exchange")
|
|
sub.add_parser("demo", help="Full E2EE demo flow")
|
|
e = sub.add_parser("encrypt", help="Encrypt message")
|
|
e.add_argument("--message", required=True)
|
|
e.add_argument("--key", required=True, help="Shared key hex")
|
|
d = sub.add_parser("decrypt", help="Decrypt message")
|
|
d.add_argument("--nonce", required=True)
|
|
d.add_argument("--ciphertext", required=True)
|
|
d.add_argument("--key", required=True, help="Shared key hex")
|
|
args = parser.parse_args()
|
|
if args.command == "keygen":
|
|
result = generate_keypair()
|
|
elif args.command == "exchange":
|
|
result = simulate_key_exchange()
|
|
elif args.command == "demo":
|
|
result = demo_full_flow()
|
|
elif args.command == "encrypt":
|
|
result = encrypt_message(args.message, args.key)
|
|
elif args.command == "decrypt":
|
|
result = decrypt_message(args.nonce, args.ciphertext, args.key)
|
|
else:
|
|
parser.print_help()
|
|
return
|
|
print(json.dumps(result, indent=2, default=str))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|