1"""
2Cryptography Fundamentals Demo
3==============================
4
5Educational demonstration of core cryptographic primitives:
6- AES-GCM symmetric encryption/decryption
7- RSA key generation and hybrid encryption
8- Digital signatures with Ed25519
9- Key exchange simulation with X25519
10- Fallback implementations using hashlib/hmac
11
12Requirements:
13 pip install cryptography (optional - fallback provided)
14
15This is a DEFENSIVE/EDUCATIONAL example. All operations demonstrate
16how to properly use cryptographic libraries for data protection.
17"""
18
19import os
20import hashlib
21import hmac
22import base64
23import struct
24import json
25
26# ============================================================
27# Section 1: Check for cryptography library availability
28# ============================================================
29
30try:
31 from cryptography.hazmat.primitives.ciphers.aead import AESGCM
32 from cryptography.hazmat.primitives.asymmetric import rsa, padding, ed25519, x25519
33 from cryptography.hazmat.primitives import hashes, serialization
34 HAS_CRYPTOGRAPHY = True
35except ImportError:
36 HAS_CRYPTOGRAPHY = False
37
38print("=" * 65)
39print(" Cryptography Fundamentals Demo")
40print("=" * 65)
41print(f"\n cryptography library available: {HAS_CRYPTOGRAPHY}")
42print()
43
44
45# ============================================================
46# Section 2: AES-GCM Symmetric Encryption
47# ============================================================
48
49print("-" * 65)
50print(" Section 2: AES-GCM Symmetric Encryption")
51print("-" * 65)
52
53if HAS_CRYPTOGRAPHY:
54 # Generate a random 256-bit key
55 key = AESGCM.generate_key(bit_length=256)
56 print(f"\n AES-256 Key (hex): {key.hex()[:32]}...")
57
58 # AES-GCM provides both confidentiality and authenticity
59 aesgcm = AESGCM(key)
60 nonce = os.urandom(12) # 96-bit nonce recommended for GCM
61 plaintext = b"Sensitive data: credit card 4111-1111-1111-1111"
62 associated_data = b"metadata:user_id=42"
63
64 # Encrypt with authenticated associated data (AAD)
65 ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
66 print(f" Nonce (hex): {nonce.hex()}")
67 print(f" Plaintext: {plaintext.decode()}")
68 print(f" Ciphertext (hex): {ciphertext.hex()[:48]}...")
69 print(f" Ciphertext length: {len(ciphertext)} bytes")
70 print(f" (plaintext {len(plaintext)} + auth tag 16 = {len(plaintext) + 16})")
71
72 # Decrypt
73 decrypted = aesgcm.decrypt(nonce, ciphertext, associated_data)
74 print(f" Decrypted: {decrypted.decode()}")
75 print(f" Match: {decrypted == plaintext}")
76
77 # Demonstrate tamper detection
78 tampered = bytearray(ciphertext)
79 tampered[0] ^= 0xFF # Flip bits in first byte
80 try:
81 aesgcm.decrypt(nonce, bytes(tampered), associated_data)
82 print(" Tamper detection: FAILED (should not reach here)")
83 except Exception:
84 print(" Tamper detection: Authentication tag mismatch detected!")
85else:
86 print("\n [cryptography not installed - showing fallback]")
87
88print()
89
90# --- Fallback: XOR stream cipher concept with HMAC auth ---
91print(" -- Fallback: HMAC-authenticated encryption concept --")
92
93def fallback_encrypt(key_bytes: bytes, plaintext: bytes) -> dict:
94 """
95 Educational fallback using HMAC for authentication.
96 NOT production-ready - use AES-GCM via cryptography library.
97 """
98 # Derive separate keys for encryption and MAC
99 enc_key = hashlib.sha256(key_bytes + b"enc").digest()
100 mac_key = hashlib.sha256(key_bytes + b"mac").digest()
101
102 # Simple XOR stream (educational only)
103 iv = os.urandom(16)
104 stream = hashlib.sha256(enc_key + iv).digest()
105 # Extend stream for longer messages
106 extended = stream
107 while len(extended) < len(plaintext):
108 extended += hashlib.sha256(enc_key + extended[-32:]).digest()
109 ct = bytes(p ^ s for p, s in zip(plaintext, extended))
110
111 # HMAC for authentication
112 tag = hmac.new(mac_key, iv + ct, hashlib.sha256).digest()
113 return {"iv": iv, "ciphertext": ct, "tag": tag}
114
115
116def fallback_decrypt(key_bytes: bytes, bundle: dict) -> bytes:
117 """Decrypt and verify the fallback encryption."""
118 enc_key = hashlib.sha256(key_bytes + b"enc").digest()
119 mac_key = hashlib.sha256(key_bytes + b"mac").digest()
120
121 # Verify HMAC first (encrypt-then-MAC pattern)
122 expected_tag = hmac.new(
123 mac_key, bundle["iv"] + bundle["ciphertext"], hashlib.sha256
124 ).digest()
125 if not hmac.compare_digest(expected_tag, bundle["tag"]):
126 raise ValueError("Authentication failed - data tampered!")
127
128 # Decrypt
129 stream = hashlib.sha256(enc_key + bundle["iv"]).digest()
130 extended = stream
131 while len(extended) < len(bundle["ciphertext"]):
132 extended += hashlib.sha256(enc_key + extended[-32:]).digest()
133 return bytes(c ^ s for c, s in zip(bundle["ciphertext"], extended))
134
135
136fb_key = os.urandom(32)
137fb_plain = b"Hello, fallback encryption!"
138fb_bundle = fallback_encrypt(fb_key, fb_plain)
139fb_decrypted = fallback_decrypt(fb_key, fb_bundle)
140print(f" Plaintext: {fb_plain.decode()}")
141print(f" IV (hex): {fb_bundle['iv'].hex()}")
142print(f" Ciphertext (hex): {fb_bundle['ciphertext'].hex()}")
143print(f" HMAC tag (hex): {fb_bundle['tag'].hex()[:32]}...")
144print(f" Decrypted: {fb_decrypted.decode()}")
145print(f" Match: {fb_decrypted == fb_plain}")
146print()
147
148
149# ============================================================
150# Section 3: RSA Key Generation and Hybrid Encryption
151# ============================================================
152
153print("-" * 65)
154print(" Section 3: RSA Key Generation & Hybrid Encryption")
155print("-" * 65)
156
157if HAS_CRYPTOGRAPHY:
158 # Generate RSA key pair
159 private_key = rsa.generate_private_key(
160 public_exponent=65537,
161 key_size=2048,
162 )
163 public_key = private_key.public_key()
164
165 pub_pem = public_key.public_bytes(
166 encoding=serialization.Encoding.PEM,
167 format=serialization.PublicFormat.SubjectPublicKeyInfo,
168 )
169 print(f"\n RSA-2048 public key generated")
170 print(f" PEM format (first line): {pub_pem.decode().split(chr(10))[0]}")
171
172 # Hybrid encryption: RSA encrypts an AES key, AES encrypts the data
173 # Step 1: Generate random AES session key
174 session_key = os.urandom(32)
175
176 # Step 2: RSA-encrypt the session key
177 encrypted_session_key = public_key.encrypt(
178 session_key,
179 padding.OAEP(
180 mgf=padding.MGF1(algorithm=hashes.SHA256()),
181 algorithm=hashes.SHA256(),
182 label=None,
183 ),
184 )
185 print(f" Session key (hex): {session_key.hex()[:24]}...")
186 print(f" RSA-encrypted key length: {len(encrypted_session_key)} bytes")
187
188 # Step 3: AES-GCM encrypt the actual data with the session key
189 aesgcm_hybrid = AESGCM(session_key)
190 hybrid_nonce = os.urandom(12)
191 hybrid_data = b"Large payload encrypted with AES, key protected by RSA"
192 hybrid_ct = aesgcm_hybrid.encrypt(hybrid_nonce, hybrid_data, None)
193 print(f" Hybrid ciphertext length: {len(hybrid_ct)} bytes")
194
195 # Receiver: RSA-decrypt session key, then AES-decrypt data
196 recovered_key = private_key.decrypt(
197 encrypted_session_key,
198 padding.OAEP(
199 mgf=padding.MGF1(algorithm=hashes.SHA256()),
200 algorithm=hashes.SHA256(),
201 label=None,
202 ),
203 )
204 recovered_plain = AESGCM(recovered_key).decrypt(hybrid_nonce, hybrid_ct, None)
205 print(f" Decrypted payload: {recovered_plain.decode()}")
206 print(f" Key recovery match: {recovered_key == session_key}")
207else:
208 print("\n [cryptography not installed]")
209 print(" RSA hybrid encryption requires the cryptography library.")
210 print(" Install with: pip install cryptography")
211print()
212
213
214# ============================================================
215# Section 4: Digital Signatures with Ed25519
216# ============================================================
217
218print("-" * 65)
219print(" Section 4: Digital Signatures (Ed25519)")
220print("-" * 65)
221
222if HAS_CRYPTOGRAPHY:
223 # Ed25519: fast, secure, small signatures
224 signing_key = ed25519.Ed25519PrivateKey.generate()
225 verify_key = signing_key.public_key()
226
227 message = b"Transfer $1000 from Alice to Bob"
228 signature = signing_key.sign(message)
229
230 print(f"\n Message: {message.decode()}")
231 print(f" Signature (hex): {signature.hex()[:48]}...")
232 print(f" Signature length: {len(signature)} bytes")
233
234 # Verify valid signature
235 try:
236 verify_key.verify(signature, message)
237 print(" Verification: VALID")
238 except Exception:
239 print(" Verification: INVALID")
240
241 # Verify tampered message
242 tampered_msg = b"Transfer $9999 from Alice to Bob"
243 try:
244 verify_key.verify(signature, tampered_msg)
245 print(" Tampered verify: VALID (should not happen!)")
246 except Exception:
247 print(" Tampered verify: INVALID (tamper detected!)")
248else:
249 print("\n [cryptography not installed]")
250 print(" Ed25519 requires the cryptography library.")
251print()
252
253# --- Fallback: HMAC-based message authentication ---
254print(" -- Fallback: HMAC-based message authentication --")
255secret = os.urandom(32)
256msg = b"Important message to authenticate"
257mac_tag = hmac.new(secret, msg, hashlib.sha256).digest()
258print(f" Message: {msg.decode()}")
259print(f" HMAC-SHA256 (hex): {mac_tag.hex()}")
260verify_ok = hmac.compare_digest(
261 mac_tag, hmac.new(secret, msg, hashlib.sha256).digest()
262)
263print(f" Verification: {'VALID' if verify_ok else 'INVALID'}")
264print()
265
266
267# ============================================================
268# Section 5: Key Exchange with X25519
269# ============================================================
270
271print("-" * 65)
272print(" Section 5: Key Exchange (X25519 / Diffie-Hellman)")
273print("-" * 65)
274
275if HAS_CRYPTOGRAPHY:
276 # X25519 Diffie-Hellman key exchange
277 alice_private = x25519.X25519PrivateKey.generate()
278 alice_public = alice_private.public_key()
279
280 bob_private = x25519.X25519PrivateKey.generate()
281 bob_public = bob_private.public_key()
282
283 # Both sides compute the same shared secret
284 alice_shared = alice_private.exchange(bob_public)
285 bob_shared = bob_private.exchange(alice_public)
286
287 print(f"\n Alice's shared secret: {alice_shared.hex()[:32]}...")
288 print(f" Bob's shared secret: {bob_shared.hex()[:32]}...")
289 print(f" Secrets match: {alice_shared == bob_shared}")
290
291 # Derive an encryption key from the shared secret
292 derived_key = hashlib.sha256(alice_shared).digest()
293 print(f" Derived AES key: {derived_key.hex()[:32]}...")
294else:
295 print("\n [cryptography not installed]")
296 print(" X25519 requires the cryptography library.")
297
298print()
299
300# --- Fallback: Simplified DH concept with small numbers ---
301print(" -- Fallback: Diffie-Hellman concept (small numbers) --")
302# Educational only - real DH uses much larger primes
303p = 23 # Small prime (real: 2048+ bits)
304g = 5 # Generator
305
306alice_secret = 6 # Alice's private key
307bob_secret = 15 # Bob's private key
308
309alice_pub = pow(g, alice_secret, p) # g^a mod p
310bob_pub = pow(g, bob_secret, p) # g^b mod p
311
312alice_computed = pow(bob_pub, alice_secret, p) # (g^b)^a mod p
313bob_computed = pow(alice_pub, bob_secret, p) # (g^a)^b mod p
314
315print(f" Parameters: p={p}, g={g}")
316print(f" Alice: secret={alice_secret}, public={alice_pub}")
317print(f" Bob: secret={bob_secret}, public={bob_pub}")
318print(f" Alice computes shared: {alice_computed}")
319print(f" Bob computes shared: {bob_computed}")
320print(f" Secrets match: {alice_computed == bob_computed}")
321print()
322
323
324# ============================================================
325# Section 6: Summary
326# ============================================================
327
328print("=" * 65)
329print(" Summary of Cryptographic Primitives")
330print("=" * 65)
331print("""
332 Primitive | Use Case | Key Size
333 -----------------+---------------------------+----------
334 AES-GCM | Symmetric encryption | 128/256-bit
335 RSA-OAEP | Asymmetric / hybrid enc | 2048+ bit
336 Ed25519 | Digital signatures | 256-bit
337 X25519 | Key exchange (ECDH) | 256-bit
338 HMAC-SHA256 | Message authentication | 256-bit
339 PBKDF2/Argon2 | Password hashing | N/A
340
341 Best Practices:
342 - Never implement your own crypto primitives
343 - Use authenticated encryption (AES-GCM, not AES-CBC alone)
344 - Use hybrid encryption for large data (RSA + AES)
345 - Rotate keys regularly
346 - Use constant-time comparison for MACs/signatures
347""")