Added Lab2/Lab3 IS

This commit is contained in:
sherlock 2025-08-12 02:15:01 +05:30
parent a8ced71b76
commit 4cab136b7a
6 changed files with 636 additions and 0 deletions

View file

@ -0,0 +1,122 @@
import time
from dataclasses import dataclass
from Crypto.Hash import SHA256
from Crypto.Protocol.KDF import HKDF
from Crypto.Util import number
def rfc3526_group14() -> tuple[int, int]:
"""
Return the 2048-bit MODP Group (Group 14) parameters from RFC 3526.
g = 2
p is the safe prime specified in RFC 3526, section 3.
"""
# RFC 3526 Group 14 (2048-bit MODP) prime (hex, concatenated)
p_hex = (
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
"83655D23DCA3AD961C62F356208552BB9ED529077096966D"
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
"15728E5A8AACAA68FFFFFFFFFFFFFFFF"
)
p = int(p_hex, 16)
g = 2
return p, g
def int_to_fixed_length_bytes(value: int, length_bits: int) -> bytes:
length_bytes = (length_bits + 7) // 8
return value.to_bytes(length_bytes, byteorder="big")
def generate_keypair(p: int, g: int, private_bits: int = 256) -> tuple[int, int]:
"""
Generate a Diffie-Hellman private/public key pair.
- private_bits controls the size of the secret exponent for performance and security.
256 bits is a common choice for Group 14.
"""
a = 0
while a < 2:
a = number.getRandomNBitInteger(private_bits)
A = pow(g, a, p)
return a, A
def derive_shared_key(peer_public: int, private: int, p: int, key_len: int = 32) -> bytes:
"""
Compute the shared secret and derive a symmetric key using HKDF-SHA256.
Returns key_len bytes (default 32 bytes = 256-bit key).
"""
shared_secret = pow(peer_public, private, p)
# Use fixed-length big-endian encoding of the shared secret for KDF input
shared_bytes = int_to_fixed_length_bytes(shared_secret, p.bit_length())
key = HKDF(shared_bytes, key_len, salt=None, hashmod=SHA256, context=b"DH key")
return key
@dataclass
class TimingResult:
alice_keygen_s: float
bob_keygen_s: float
alice_exchange_s: float
bob_exchange_s: float
def measure_timings(p: int, g: int, private_bits: int = 256) -> TimingResult:
start = time.perf_counter()
a_priv, a_pub = generate_keypair(p, g, private_bits)
alice_keygen_s = time.perf_counter() - start
start = time.perf_counter()
b_priv, b_pub = generate_keypair(p, g, private_bits)
bob_keygen_s = time.perf_counter() - start
# Exchange
start = time.perf_counter()
a_key = derive_shared_key(b_pub, a_priv, p)
alice_exchange_s = time.perf_counter() - start
start = time.perf_counter()
b_key = derive_shared_key(a_pub, b_priv, p)
bob_exchange_s = time.perf_counter() - start
# Sanity check
if a_key != b_key:
raise RuntimeError("Derived keys do not match. Check parameters.")
return TimingResult(
alice_keygen_s=alice_keygen_s,
bob_keygen_s=bob_keygen_s,
alice_exchange_s=alice_exchange_s,
bob_exchange_s=bob_exchange_s,
)
def main():
p, g = rfc3526_group14()
timings = measure_timings(p, g, private_bits=256)
print("Diffie-Hellman (RFC3526 Group 14, g=2)")
print(f"Prime bits: {p.bit_length()}\n")
print("Timings (seconds):")
print(f"- Alice key generation: {timings.alice_keygen_s:.6f}")
print(f"- Bob key generation: {timings.bob_keygen_s:.6f}")
print(f"- Alice key exchange: {timings.alice_exchange_s:.6f}")
print(f"- Bob key exchange: {timings.bob_exchange_s:.6f}")
if __name__ == "__main__":
main()

58
IS/Lab/Lab3/ECC.py Normal file
View file

@ -0,0 +1,58 @@
from Crypto.PublicKey import ECC
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
import binascii
def ecc_keygen(curve: str = 'P-256') -> ECC.EccKey:
return ECC.generate(curve=curve)
def ecc_encrypt(plaintext: str, recipient_public_key: ECC.EccKey):
eph_private = ECC.generate(curve=recipient_public_key.curve)
shared_point = recipient_public_key.pointQ * eph_private.d
shared_x = int(shared_point.x)
aes_key = SHA256.new(shared_x.to_bytes(32, 'big')).digest()
cipher = AES.new(aes_key, AES.MODE_GCM)
ciphertext, tag = cipher.encrypt_and_digest(plaintext.encode('utf-8'))
return {
'ephemeral_pub_der': eph_private.public_key().export_key(format='DER'),
'nonce': cipher.nonce,
'tag': tag,
'ciphertext': ciphertext,
}
def ecc_decrypt(enc: dict, recipient_private_key: ECC.EccKey) -> str:
eph_public = ECC.import_key(enc['ephemeral_pub_der'])
shared_point = eph_public.pointQ * recipient_private_key.d
shared_x = int(shared_point.x)
aes_key = SHA256.new(shared_x.to_bytes(32, 'big')).digest()
cipher = AES.new(aes_key, AES.MODE_GCM, nonce=enc['nonce'])
plaintext = cipher.decrypt_and_verify(enc['ciphertext'], enc['tag'])
return plaintext.decode('utf-8')
def main():
print('Welcome to ECC (ECIES-style)')
ptext = input('Enter plaintext: ')
priv_key = ecc_keygen()
pub_key = priv_key.public_key()
print('\nPublic Key (Qx, Qy):')
print('Qx =', hex(int(pub_key.pointQ.x)))
print('Qy =', hex(int(pub_key.pointQ.y)))
enc = ecc_encrypt(ptext, pub_key)
print("\nYour ciphertext (hex):", binascii.hexlify(enc['ciphertext']).decode())
decrypted = ecc_decrypt(enc, priv_key)
print('Your decrypted plaintext:', decrypted)
if __name__ == '__main__':
main()

57
IS/Lab/Lab3/ElGamal.py Normal file
View file

@ -0,0 +1,57 @@
import random
from Crypto.Util.number import getPrime
def elgamal_keygen(bits=512):
p = getPrime(bits)
g = random.randint(2, p-1)
x = random.randint(1, p-2) # private key
h = pow(g, x, p) # public key component
return (p, g, h), x
def elgamal_encrypt(message, pub_key):
p, g, h = pub_key
m = int.from_bytes(message.encode('utf-8'), 'big')
if m >= p:
raise ValueError("Message too large for key size")
k = random.randint(1, p-2)
c1 = pow(g, k, p)
c2 = (m * pow(h, k, p)) % p
return (c1, c2)
def elgamal_decrypt(ciphertext, priv_key, pub_key):
c1, c2 = ciphertext
p, g, h = pub_key
x = priv_key
s = pow(c1, x, p)
s_inv = pow(s, p-2, p) # modular inverse
m = (c2 * s_inv) % p
return m.to_bytes((m.bit_length() + 7) // 8, 'big').decode('utf-8')
def main():
print("Welcome to ElGamal")
ptext = input("Enter plaintext: ")
# Generate keys
pub_key, priv_key = elgamal_keygen()
p, g, h = pub_key
print(f"\nPublic Key (p, g, h):")
print(f"p = {hex(p)}")
print(f"g = {g}")
print(f"h = {hex(h)}")
# Encrypt
ctext = elgamal_encrypt(ptext, pub_key)
print(f"\nCiphertext (c1, c2):")
print(f"c1 = {hex(ctext[0])}")
print(f"c2 = {hex(ctext[1])}")
# Decrypt
decrypted = elgamal_decrypt(ctext, priv_key, pub_key)
print(f"Decrypted: {decrypted}")
if __name__ == '__main__':
main()

299
IS/Lab/Lab3/FileTransfer.py Normal file
View file

@ -0,0 +1,299 @@
import os
import time
import binascii
from Crypto.PublicKey import RSA, ECC
from Crypto.Cipher import PKCS1_OAEP, AES
from Crypto.Hash import SHA256
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
from bokeh.plotting import figure, show, output_file
from bokeh.layouts import gridplot
from bokeh.models import HoverTool
def generate_test_file(size_mb):
"""Generate test file of specified size in MB"""
filename = f"test_file_{size_mb}MB.txt"
with open(filename, 'wb') as f:
# Write random data
for _ in range(size_mb * 1024): # 1MB = 1024KB
f.write(get_random_bytes(1024))
return filename
def rsa_keygen_timed():
"""Generate RSA key pair and measure time"""
start = time.time()
key = RSA.generate(2048)
gen_time = time.time() - start
return key, gen_time
def ecc_keygen_timed():
"""Generate ECC key pair and measure time"""
start = time.time()
key = ECC.generate(curve='secp256r1')
gen_time = time.time() - start
return key, gen_time
def rsa_encrypt_file(filename, pub_key):
"""Encrypt file using RSA with AES hybrid encryption"""
start = time.time()
# Generate AES key
aes_key = get_random_bytes(32) # 256-bit AES key
# Encrypt AES key with RSA
rsa_cipher = PKCS1_OAEP.new(pub_key)
encrypted_aes_key = rsa_cipher.encrypt(aes_key)
# Encrypt file with AES
aes_cipher = AES.new(aes_key, AES.MODE_CBC)
iv = aes_cipher.iv
with open(filename, 'rb') as f:
plaintext = f.read()
padded_plaintext = pad(plaintext, AES.block_size)
ciphertext = aes_cipher.encrypt(padded_plaintext)
enc_time = time.time() - start
encrypted_data = {
'encrypted_aes_key': encrypted_aes_key,
'iv': iv,
'ciphertext': ciphertext
}
return encrypted_data, enc_time
def rsa_decrypt_file(encrypted_data, priv_key):
"""Decrypt file using RSA with AES hybrid decryption"""
start = time.time()
# Decrypt AES key with RSA
rsa_cipher = PKCS1_OAEP.new(priv_key)
aes_key = rsa_cipher.decrypt(encrypted_data['encrypted_aes_key'])
# Decrypt file with AES
aes_cipher = AES.new(aes_key, AES.MODE_CBC, encrypted_data['iv'])
padded_plaintext = aes_cipher.decrypt(encrypted_data['ciphertext'])
plaintext = unpad(padded_plaintext, AES.block_size)
dec_time = time.time() - start
return plaintext, dec_time
def ecc_encrypt_file(filename, pub_key):
"""Encrypt file using ECC with AES hybrid encryption"""
start = time.time()
# Generate ephemeral key pair
eph_private = ECC.generate(curve='secp256r1')
# Compute shared secret
shared_point = pub_key.pointQ * eph_private.d
shared_x = int(shared_point.x)
aes_key = SHA256.new(shared_x.to_bytes(32, 'big')).digest()
# Encrypt file with AES
aes_cipher = AES.new(aes_key, AES.MODE_GCM)
with open(filename, 'rb') as f:
plaintext = f.read()
ciphertext, tag = aes_cipher.encrypt_and_digest(plaintext)
enc_time = time.time() - start
encrypted_data = {
'ephemeral_pub_der': eph_private.public_key().export_key(format='DER'),
'nonce': aes_cipher.nonce,
'tag': tag,
'ciphertext': ciphertext
}
return encrypted_data, enc_time
def ecc_decrypt_file(encrypted_data, priv_key):
"""Decrypt file using ECC with AES hybrid decryption"""
start = time.time()
# Import ephemeral public key
eph_public = ECC.import_key(encrypted_data['ephemeral_pub_der'])
# Compute shared secret
shared_point = eph_public.pointQ * priv_key.d
shared_x = int(shared_point.x)
aes_key = SHA256.new(shared_x.to_bytes(32, 'big')).digest()
# Decrypt file with AES
aes_cipher = AES.new(aes_key, AES.MODE_GCM, nonce=encrypted_data['nonce'])
plaintext = aes_cipher.decrypt_and_verify(encrypted_data['ciphertext'], encrypted_data['tag'])
dec_time = time.time() - start
return plaintext, dec_time
def measure_performance(file_sizes):
"""Measure performance for both RSA and ECC"""
results = {
'file_sizes': file_sizes,
'rsa_keygen': [],
'ecc_keygen': [],
'rsa_encrypt': [],
'rsa_decrypt': [],
'ecc_encrypt': [],
'ecc_decrypt': [],
'rsa_key_size': 0,
'ecc_key_size': 0
}
print("Performance Testing - RSA vs ECC File Transfer")
print("=" * 50)
# Generate keys once
rsa_key, rsa_keygen_time = rsa_keygen_timed()
ecc_key, ecc_keygen_time = ecc_keygen_timed()
# Calculate key sizes
results['rsa_key_size'] = len(rsa_key.export_key('DER'))
results['ecc_key_size'] = len(ecc_key.export_key(format='DER'))
print(f"RSA Key Generation Time: {rsa_keygen_time:.4f} seconds")
print(f"ECC Key Generation Time: {ecc_keygen_time:.4f} seconds")
print(f"RSA Key Size: {results['rsa_key_size']} bytes")
print(f"ECC Key Size: {results['ecc_key_size']} bytes")
print()
for size in file_sizes:
print(f"Testing {size}MB file...")
# Generate test file
filename = generate_test_file(size)
try:
# RSA performance
rsa_pub = rsa_key.publickey()
encrypted_rsa, rsa_enc_time = rsa_encrypt_file(filename, rsa_pub)
decrypted_rsa, rsa_dec_time = rsa_decrypt_file(encrypted_rsa, rsa_key)
# ECC performance
ecc_pub = ecc_key.public_key()
encrypted_ecc, ecc_enc_time = ecc_encrypt_file(filename, ecc_pub)
decrypted_ecc, ecc_dec_time = ecc_decrypt_file(encrypted_ecc, ecc_key)
# Store results
results['rsa_keygen'].append(rsa_keygen_time)
results['ecc_keygen'].append(ecc_keygen_time)
results['rsa_encrypt'].append(rsa_enc_time)
results['rsa_decrypt'].append(rsa_dec_time)
results['ecc_encrypt'].append(ecc_enc_time)
results['ecc_decrypt'].append(ecc_dec_time)
print(f" RSA - Encrypt: {rsa_enc_time:.4f}s, Decrypt: {rsa_dec_time:.4f}s")
print(f" ECC - Encrypt: {ecc_enc_time:.4f}s, Decrypt: {ecc_dec_time:.4f}s")
finally:
# Clean up test file
if os.path.exists(filename):
os.remove(filename)
print()
return results
def create_performance_graphs(results):
"""Create performance comparison graphs using Bokeh"""
output_file("file_transfer_performance.html")
file_sizes = results['file_sizes']
# Encryption time comparison
p1 = figure(title="Encryption Time Comparison", x_axis_label="File Size (MB)",
y_axis_label="Time (seconds)", width=400, height=300)
p1.line(file_sizes, results['rsa_encrypt'], legend_label="RSA", line_color="red", line_width=2)
p1.circle(file_sizes, results['rsa_encrypt'], color="red", size=6)
p1.line(file_sizes, results['ecc_encrypt'], legend_label="ECC", line_color="blue", line_width=2)
p1.circle(file_sizes, results['ecc_encrypt'], color="blue", size=6)
p1.legend.location = "top_left"
# Decryption time comparison
p2 = figure(title="Decryption Time Comparison", x_axis_label="File Size (MB)",
y_axis_label="Time (seconds)", width=400, height=300)
p2.line(file_sizes, results['rsa_decrypt'], legend_label="RSA", line_color="red", line_width=2)
p2.circle(file_sizes, results['rsa_decrypt'], color="red", size=6)
p2.line(file_sizes, results['ecc_decrypt'], legend_label="ECC", line_color="blue", line_width=2)
p2.circle(file_sizes, results['ecc_decrypt'], color="blue", size=6)
p2.legend.location = "top_left"
# Key generation comparison
p3 = figure(title="Key Generation Time", x_axis_label="Algorithm",
y_axis_label="Time (seconds)", width=400, height=300,
x_range=["RSA", "ECC"])
p3.vbar(x=["RSA", "ECC"], top=[results['rsa_keygen'][0], results['ecc_keygen'][0]],
width=0.5, color=["red", "blue"])
# Key size comparison
p4 = figure(title="Key Size Comparison", x_axis_label="Algorithm",
y_axis_label="Size (bytes)", width=400, height=300,
x_range=["RSA", "ECC"])
p4.vbar(x=["RSA", "ECC"], top=[results['rsa_key_size'], results['ecc_key_size']],
width=0.5, color=["red", "blue"])
# Create grid layout
grid = gridplot([[p1, p2], [p3, p4]])
show(grid)
def print_security_analysis():
"""Print security analysis and comparison"""
print("\nSecurity Analysis - RSA vs ECC")
print("=" * 50)
print("RSA (2048-bit):")
print(" • Security Level: ~112 bits")
print(" • Key Size: Large (2048+ bits)")
print(" • Resistance: Integer factorization problem")
print(" • Quantum Threat: Vulnerable to Shor's algorithm")
print(" • Computational Overhead: High for large keys")
print()
print("ECC (secp256r1):")
print(" • Security Level: ~128 bits")
print(" • Key Size: Small (256 bits)")
print(" • Resistance: Elliptic curve discrete logarithm problem")
print(" • Quantum Threat: Vulnerable to modified Shor's algorithm")
print(" • Computational Overhead: Lower than equivalent RSA")
print()
print("Summary:")
print(" • ECC provides equivalent security with smaller keys")
print(" • ECC is more efficient for mobile/embedded systems")
print(" • RSA is more widely supported and established")
print(" • Both require post-quantum alternatives for future security")
def main():
"""Main function to run the file transfer comparison"""
file_sizes = [1, 5, 10] # MB
print("Secure File Transfer System - RSA vs ECC Comparison")
print("=" * 60)
# Measure performance
results = measure_performance(file_sizes)
# Create performance graphs
create_performance_graphs(results)
# Print security analysis
print_security_analysis()
print(f"\nPerformance graphs saved to: file_transfer_performance.html")
print("Open the HTML file in your browser to view the interactive graphs.")
if __name__ == '__main__':
main()

39
IS/Lab/Lab3/RSA.py Normal file
View file

@ -0,0 +1,39 @@
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import binascii
def rsa_keygen(bits=2048):
key = RSA.generate(bits)
return key
def rsa_en(ptext, pub_key):
cipher = PKCS1_OAEP.new(pub_key)
ctext = cipher.encrypt(ptext.encode('utf-8'))
return ctext
def rsa_de(ctext, priv_key):
cipher = PKCS1_OAEP.new(priv_key)
decrypted = cipher.decrypt(ctext)
return decrypted.decode('utf-8')
def main():
print("Welcome to RSA")
ptext = input("Enter plaintext: ")
# RSA key pair
key = rsa_keygen()
pub_key = key.publickey()
priv_key = key
print("\nPublic Key (n, e):")
print("n =", hex(pub_key.n))
print("e =", pub_key.e)
ctext = rsa_en(ptext, pub_key)
print("\nYour ciphertext (hex):", binascii.hexlify(ctext).decode())
decrypted = rsa_de(ctext, priv_key)
print("Your decrypted plaintext:", decrypted)
if __name__ == '__main__':
main()