Merge remote-tracking branch 'origin/main'

# Conflicts:
#	IS/Lab/Lab2/des_vs_aes256.py
This commit is contained in:
Student 2025-08-12 08:23:22 +05:30
commit 4ca2829e4e
13 changed files with 1201 additions and 87 deletions

View file

@ -0,0 +1,28 @@
AREA RESET, DATA, READONLY
EXPORT __Vectors
__Vectors
DCD 0x10001000
DCD Reset_Handler
ALIGN
AREA mycode,CODE,READONLY
ENTRY
EXPORT Reset_Handler
Reset_Handler
MOV R2, #5
LDR R0, =SRC
LDR R1, =SRC + 36
Loop
LDR R3, [R0]
LDR R4, [R1]
STR R3, [R1], #-4
STR R4, [R0], #4
SUBS R2, #1
BNE Loop
STOP
B STOP
AREA mydate, DATA, READWRITE
SRC DCD 0x00000032, 0x12345644, 0x00000005, 0x00000098, 0x000000AB, 0x000000CD, 0x00000055, 0x00000032, 0x000000CA, 0x00000045
END

34
ES/Lab/Lab3/ADDER.asm Normal file
View file

@ -0,0 +1,34 @@
AREA RESET, DATA, READONLY
EXPORT __Vectors
__Vectors
DCD 0x10001000
DCD Reset_Handler
ALIGN
AREA MYCODE, CODE, READONLY
ENTRY
EXPORT Reset_Handler
Reset_Handler
LDR R0, =SRC
MOV R3, #10
UP
LDR R1, [R0], #4
ADDS R2, R1
ADC R5, #0
SUBS R3, #1
BNE UP;
LDR R4, =Result
STR R2, [R4]
STR R5, [R4]
SRC DCD 0x12345678, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 0x00000008, 0x00000009
AREA mydata, DATA, READWRITE
Result
DCD 0
END

44
ES/Lab/Lab3/add128bit.asm Normal file
View file

@ -0,0 +1,44 @@
AREA RESET, DATA, READONLY
EXPORT __Vectors
__Vectors
DCD 0x10001000
DCD Reset_Handler
ALIGN
AREA MYCODE, CODE, READONLY
ENTRY
EXPORT Reset_Handler
Reset_Handler
LDR R1, =N1
LDR R2, =N2
MOV R3, #4
UP
LDR R4, [R1], #4
LDR R5, [R2], #4
ADCS R6, R5, R4
SUB R3, #1
TEQ R3, #0
BNE UP;
LDR R8, =Result
STR R2, [R8], #4
STR R5, [R8]
STOP
B STOP
ALIGN
N1 DCD 0x10002000, 0x30004000, 0x50006000, 0x70008000
N2 DCD 0x10002000, 0x30004000, 0x50006000, 0x70008000
AREA mydata, DATA, READWRITE
Result DCD 0
END

View file

@ -1,33 +1,196 @@
from crypto.Cipher import DES3
from Crypto.Cipher import DES, DES3, AES
from Crypto.Util.Padding import pad, unpad
import time
from bokeh.plotting import figure, show, output_file
from bokeh.models import HoverTool, ColumnDataSource
from bokeh.layouts import column, row
import bokeh.palettes as bp
def des_pad(text):
n = len(text) % 8
return text + (b' ' * n)
def pad_key(key, length):
return key.ljust(length)[:length].encode('utf-8')
def des_128(ptext, key):
cipher=DES.new(key, DES.MODE_ECB)
def encrypt_with_timing(cipher_func, ptext, key, *args):
# Use more precise timing for microsecond measurements
start_time = time.perf_counter()
result = cipher_func(ptext, key, *args)
end_time = time.perf_counter()
return result, end_time - start_time
def des_encrypt(ptext, key, mode):
key = pad_key(key, 8)
cipher = DES.new(key, mode)
padded_text = pad(ptext.encode('utf-8'), DES.block_size)
return cipher.encrypt(padded_text)
def des_192(ptext, key):
def des3_encrypt(ptext, key, key_size, mode):
if key_size == 128:
key = pad_key(key, 16)
elif key_size == 192:
key = pad_key(key, 24)
else: # 256 bit uses 192 bit key (DES3 limitation)
key = pad_key(key, 24)
def des_256(ptext, key):
cipher = DES3.new(key, mode)
padded_text = pad(ptext.encode('utf-8'), DES3.block_size)
return cipher.encrypt(padded_text)
def aes_128(ptext, key):
def aes_192(ptext, key):
def aes_256(ptext, key):
def aes_encrypt(ptext, key, key_size, mode):
if key_size == 128:
key = pad_key(key, 16)
elif key_size == 192:
key = pad_key(key, 24)
else: # 256
key = pad_key(key, 32)
def bokeh_graph():
cipher = AES.new(key, mode)
padded_text = pad(ptext.encode('utf-8'), AES.block_size)
return cipher.encrypt(padded_text)
def des_128(ptext, key, mode=DES.MODE_ECB):
return des_encrypt(ptext, key, mode)
def des_192(ptext, key, mode=DES3.MODE_ECB):
return des3_encrypt(ptext, key, 192, mode)
def des_256(ptext, key, mode=DES3.MODE_ECB):
return des3_encrypt(ptext, key, 256, mode)
def aes_128(ptext, key, mode=AES.MODE_ECB):
return aes_encrypt(ptext, key, 128, mode)
def aes_192(ptext, key, mode=AES.MODE_ECB):
return aes_encrypt(ptext, key, 192, mode)
def aes_256(ptext, key, mode=AES.MODE_ECB):
return aes_encrypt(ptext, key, 256, mode)
def bokeh_graph(timing_data):
output_file("encryption_performance.html")
from bokeh.models import LinearColorMapper, ColorBar, BasicTicker, PrintfTickFormatter
from bokeh.transform import transform
import math
algorithms = list(timing_data.keys())
messages = [f"Msg {i+1}" for i in range(len(next(iter(timing_data.values()))))]
# Convert all times to microseconds for better visibility
def to_microseconds(seconds):
return seconds * 1_000_000
# Chart 2: Performance variability - Box plot style using circles and lines
p2 = figure(x_range=algorithms, title="Performance Distribution Across Messages",
toolbar_location=None, tools="", width=800, height=400)
for i, algo_name in enumerate(algorithms):
times_us = [to_microseconds(t) for t in timing_data[algo_name]]
# Calculate statistics
mean_time = sum(times_us) / len(times_us)
min_time = min(times_us)
max_time = max(times_us)
# Plot range line
p2.line([i, i], [min_time, max_time], line_width=2, color=colors[i], alpha=0.6)
# Plot individual points
y_positions = times_us
x_positions = [i + (j - 2) * 0.1 for j in range(len(times_us))] # Spread points horizontally
p2.circle(x_positions, y_positions, size=8, color=colors[i], alpha=0.8)
# Plot mean as a diamond
p2.diamond([i], [mean_time], size=12, color=colors[i], line_color="black", line_width=1)
p2.xaxis.major_label_orientation = 45
p2.yaxis.axis_label = "Execution Time (microseconds)"
p2.xaxis.axis_label = "Encryption Algorithm"
p2.xaxis.ticker = BasicTicker()
p2.xaxis.formatter = PrintfTickFormatter(format="%s")
hover2 = HoverTool(tooltips=[("Time (μs)", "@y{0.00}")], mode='vline')
p2.add_tools(hover2)
# Chart 4: Relative performance comparison (normalized to fastest)
p4 = figure(x_range=algorithms, title="Relative Performance (Normalized to Fastest Algorithm)",
toolbar_location=None, tools="", width=800, height=400)
# Find the fastest average time
fastest_avg = min(avg_times)
relative_times = [avg / fastest_avg for avg in avg_times]
bars4 = p4.vbar(x=algorithms, top=relative_times, width=0.6, color=colors, alpha=0.8)
# Add reference line at 1.0
p4.line([-0.5, len(algorithms)-0.5], [1, 1], line_dash="dashed", line_width=2, color="red", alpha=0.7)
p4.xaxis.major_label_orientation = 45
p4.yaxis.axis_label = "Relative Performance (1.0 = fastest)"
p4.xaxis.axis_label = "Encryption Algorithm"
hover4 = HoverTool(tooltips=[("Algorithm", "@x"), ("Relative Speed", "@top{0.00}x")], renderers=[bars4])
p4.add_tools(hover4)
# Layout all charts
layout = column(
row(p2),
row(p4)
)
show(layout)
def main():
print("The AES/DES Encryptor")
ptext = input("Enter plaintext: ")
key = b'input("Enter key: ")'
print("DES 128 Bit Cyphertext: ", des_128(ptext, key))
print("DES 192 Bit Cyphertext: ", des_192(ptext, key))
print("DES 256 Bit Cyphertext: ", des_256(ptext, key))
print("AES 128 Bit Cyphertext: ", aes_128(ptext, key))
print("AES 192 Bit Cyphertext: ", aes_192(ptext, key))
print("AES 256 Bit Cyphertext: ", aes_256(ptext, key))
print("The AES/DES Encryptor with Performance Analysis")
# Get exactly 5 messages from user
messages = []
print("\nEnter exactly 5 messages to encrypt:")
for i in range(5):
while True:
message = input(f"Message {i+1}: ")
if message.strip(): # Only accept non-empty messages
messages.append(message)
break
else:
print("Please enter a non-empty message.")
key = input("\nEnter key: ")
# Define algorithms to test (using ECB mode only)
algorithms = [
('DES', des_128, DES.MODE_ECB),
('DES3-192', des_192, DES3.MODE_ECB),
('AES-128', aes_128, AES.MODE_ECB),
('AES-192', aes_192, AES.MODE_ECB),
('AES-256', aes_256, AES.MODE_ECB)
]
timing_data = {}
print("\nEncrypting messages and measuring performance...\n")
# Run each message through each algorithm multiple times for better precision
for algo_name, algo_func, mode in algorithms:
timing_data[algo_name] = []
print(f"=== {algo_name} ===")
for i, message in enumerate(messages):
print(f"Message {i+1}: {message[:30]}...")
# Run multiple times and take the best time to reduce noise
best_time = float('inf')
for _ in range(10): # 10 runs for better precision
ctext, exec_time = encrypt_with_timing(algo_func, message, key, mode)
best_time = min(best_time, exec_time)
print(f"{algo_name}: {best_time:.8f}s ({best_time*1000000:.2f}μs)")
timing_data[algo_name].append(best_time)
print()
# Generate performance graphs
print("Generating performance visualization...")
bokeh_graph(timing_data)
print("Performance graphs saved to 'encryption_performance.html'")
if __name__ == '__main__':
main()

File diff suppressed because one or more lines are too long

View file

@ -1,87 +1,176 @@
from Crypto.Cipher import DES, AES
from Crypto.Util.Padding import pad, unpad
import time
import numpy as np
from Crypto.Cipher import AES, DES
from Crypto.Util.Padding import pad, unpad
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource
from bokeh.io import output_file
from bokeh.models import HoverTool
from bokeh.layouts import column
from bokeh.palettes import Category10
def aes_cipher(key):
return AES.new(key.encode('utf-8'), AES.MODE_ECB)
def benchmark_encryption_decryption(cipher_func, data, key):
# Measure encryption time
start_time = time.time()
encrypted = cipher_func(data, key)
encrypt_time = time.time() - start_time
def aes_en(ptext, key):
cipher = aes_cipher(key)
ptext = pad(ptext.encode('utf-8'), AES.block_size)
return cipher.encrypt(ptext)
# Measure decryption time
start_time = time.time()
decrypted = cipher_func(encrypted, key, decrypt=True)
decrypt_time = time.time() - start_time
def aes_de(ctext, key):
cipher = aes_cipher(key)
decrypted = cipher.decrypt(ctext)
return unpad(decrypted, AES.block_size).decode('utf-8')
return encrypt_time, decrypt_time
def aes256_pad_key(key):
return key.ljust(32)[:32]
def des_cipher(key):
return DES.new(key.encode('utf-8'), DES.MODE_ECB)
def des_cipher(data, key, decrypt=False):
cipher = DES.new(key.encode('utf-8'), DES.MODE_ECB)
if decrypt:
return unpad(cipher.decrypt(data), DES.block_size).decode('utf-8')
else:
padded_data = pad(data.encode('utf-8'), DES.block_size)
return cipher.encrypt(padded_data)
def des_en(ptext, key):
cipher = des_cipher(key)
ptext = pad(ptext.encode('utf-8'), DES.block_size)
return cipher.encrypt(ptext)
def des_de(ctext, key):
cipher = des_cipher(key)
decrypted = cipher.decrypt(ctext)
return unpad(decrypted, DES.block_size).decode('utf-8')
def aes_cipher(data, key, decrypt=False):
cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
if decrypt:
return unpad(cipher.decrypt(data), AES.block_size).decode('utf-8')
else:
padded_data = pad(data.encode('utf-8'), AES.block_size)
return cipher.encrypt(padded_data)
def des_pad_key(key):
return key.ljust(8)[:8]
def time_encryption_progressive(encrypt_func, plaintext, key, max_iterations=1000):
"""Time encryption across different iteration counts"""
iteration_counts = np.logspace(1, np.log10(max_iterations), 10, dtype=int)
times_per_iteration = []
for iterations in iteration_counts:
start_time = time.time()
for _ in range(iterations):
encrypt_func(plaintext, key)
end_time = time.time()
total_time = end_time - start_time
times_per_iteration.append(total_time / iterations)
return iteration_counts, times_per_iteration
def time_decryption_progressive(decrypt_func, ciphertext, key, max_iterations=1000):
"""Time decryption across different iteration counts"""
iteration_counts = np.logspace(1, np.log10(max_iterations), 10, dtype=int)
times_per_iteration = []
for iterations in iteration_counts:
start_time = time.time()
for _ in range(iterations):
decrypt_func(ciphertext, key)
end_time = time.time()
total_time = end_time - start_time
times_per_iteration.append(total_time / iterations)
return iteration_counts, times_per_iteration
def benchmark_ciphers(plaintext, raw_key, max_iterations=1000):
# Prepare keys
aes_key = aes256_pad_key(raw_key)
des_key = des_pad_key(raw_key)
# Get ciphertexts for decryption timing
aes_ciphertext = aes_en(plaintext, aes_key)
des_ciphertext = des_en(plaintext, des_key)
# Time encryption progressively
aes_enc_iterations, aes_enc_times = time_encryption_progressive(aes_en, plaintext, aes_key, max_iterations)
des_enc_iterations, des_enc_times = time_encryption_progressive(des_en, plaintext, des_key, max_iterations)
# Time decryption progressively
aes_dec_iterations, aes_dec_times = time_decryption_progressive(aes_de, aes_ciphertext, aes_key, max_iterations)
des_dec_iterations, des_dec_times = time_decryption_progressive(des_de, des_ciphertext, des_key, max_iterations)
return {
'aes_enc_iterations': aes_enc_iterations,
'aes_enc_times': aes_enc_times,
'des_enc_iterations': des_enc_iterations,
'des_enc_times': des_enc_times,
'aes_dec_iterations': aes_dec_iterations,
'aes_dec_times': aes_dec_times,
'des_dec_iterations': des_dec_iterations,
'des_dec_times': des_dec_times
}
def create_plot(title, plaintext_length):
return figure(
title=f"{title}\nPlaintext length: {plaintext_length} chars",
x_axis_label="Number of Iterations",
y_axis_label="Time per Operation (seconds)",
x_axis_type="log",
y_axis_type="log",
width=800,
height=400,
background_fill_color="#fafafa",
border_fill_color="whitesmoke"
)
def add_line_and_markers(plot, x_data, y_data, color, label):
plot.line(x_data, y_data, line_width=3, color=color, alpha=0.8, legend_label=label)
plot.scatter(x_data, y_data, size=8, color=color, alpha=0.8)
def plot_results(results, plaintext_length):
colors = Category10[4]
# Create plots
p1 = create_plot("Encryption Performance: Time per Operation", plaintext_length)
p2 = create_plot("Decryption Performance: Time per Operation", plaintext_length)
# Add data to plots
add_line_and_markers(p1, results['aes_enc_iterations'], results['aes_enc_times'], colors[0], "AES-256 Encryption")
add_line_and_markers(p1, results['des_enc_iterations'], results['des_enc_times'], colors[1], "DES Encryption")
add_line_and_markers(p2, results['aes_dec_iterations'], results['aes_dec_times'], colors[2], "AES-256 Decryption")
add_line_and_markers(p2, results['des_dec_iterations'], results['des_dec_times'], colors[3], "DES Decryption")
# Add hover tools and styling
hover = HoverTool(tooltips=[("Algorithm", "@legend_label"), ("Iterations", "@x"), ("Time per Op", "@y{0.0000000} sec")])
for p in [p1, p2]:
p.add_tools(hover)
p.legend.location = "top_right"
p.legend.click_policy = "hide"
p.legend.background_fill_alpha = 0.8
p.grid.grid_line_alpha = 0.3
show(column(p1, p2))
def main():
message = "Performance Testing of Encryption Algorithms"
print("AES-256 vs DES Performance Comparison")
print("=====================================")
# Test with different key sizes
des_key = "12345678" # 8 bytes for DES
aes_key = "12345678901234567890123456789012" # 32 bytes for AES-256
plaintext = input("Enter plaintext: ")
key = input("Enter key: ")
max_iterations = int(input("Enter maximum number of iterations (default 1000): ") or "1000")
# Benchmark DES
des_encrypt_time, des_decrypt_time = benchmark_encryption_decryption(des_cipher, message, des_key)
print(f"\nBenchmarking across iteration ranges up to {max_iterations}...")
results = benchmark_ciphers(plaintext, key, max_iterations)
# Benchmark AES-256
aes_encrypt_time, aes_decrypt_time = benchmark_encryption_decryption(aes_cipher, message, aes_key)
# Calculate average times for comparison
avg_aes_enc = np.mean(results['aes_enc_times'])
avg_des_enc = np.mean(results['des_enc_times'])
avg_aes_dec = np.mean(results['aes_dec_times'])
avg_des_dec = np.mean(results['des_dec_times'])
# Print results
print("Performance Results:")
print("-" * 40)
print(f"DES Encryption: {des_encrypt_time:.9f} seconds")
print(f"DES Decryption: {des_decrypt_time:.9f} seconds")
print(f"AES-256 Encryption: {aes_encrypt_time:.9f} seconds")
print(f"AES-256 Decryption: {aes_decrypt_time:.9f} seconds")
print("\nAverage Results (time per operation):")
print(f"AES-256 Encryption: {avg_aes_enc:.8f} seconds")
print(f"DES Encryption: {avg_des_enc:.8f} seconds")
print(f"AES-256 Decryption: {avg_aes_dec:.8f} seconds")
print(f"DES Decryption: {avg_des_dec:.8f} seconds")
# Create Bokeh visualization
algorithms = ['DES', 'AES-256']
encrypt_times = [des_encrypt_time, aes_encrypt_time]
decrypt_times = [des_decrypt_time, aes_decrypt_time]
# Create the plot
p = figure(x_range=algorithms, height=400, title="Encryption/Decryption Performance Comparison",
toolbar_location=None, responsive=True)
p.vbar(x='algorithm', top='encrypt_time', width=0.4, color='blue', alpha=0.7, legend_label="Encryption",
source=ColumnDataSource(data=dict(algorithm=algorithms, encrypt_time=encrypt_times)))
p.vbar(x='algorithm', top='decrypt_time', width=0.4, color='red', alpha=0.7, legend_label="Decryption",
source=ColumnDataSource(data=dict(algorithm=algorithms, decrypt_time=decrypt_times)))
p.legend.location = "top_right"
p.xaxis.axis_label = "Algorithm"
p.yaxis.axis_label = "Time (seconds)"
p.title.text_font_size = "14px"
# Save and show the plot
output_file("encryption_performance.html")
show(p)
print("\nSpeed comparison:")
if avg_aes_enc < avg_des_enc:
ratio = avg_des_enc / avg_aes_enc
print(f"AES-256 encryption is {ratio:.2f}x faster than DES")
else:
ratio = avg_aes_enc / avg_des_enc
print(f"DES encryption is {ratio:.2f}x faster than AES-256")
plot_results(results, len(plaintext))
if __name__ == '__main__':
main()
main()

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,61 @@
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
def aes_cipher(key):
return AES.new(key.encode('utf-8'), AES.MODE_ECB)
def aes_en(ptext, key):
cipher = aes_cipher(key)
ptext = pad(ptext.encode('utf-8'), AES.block_size)
return cipher.encrypt(ptext)
def aes_de(ctext, key):
cipher = aes_cipher(key)
decrypted = cipher.decrypt(ctext)
return unpad(decrypted, AES.block_size).decode('utf-8')
def aespad_key(key):
return key.ljust(24)[:24]
def aes_en_trace(ptext, key):
key = aespad_key(key)
key_bytes = key.encode('utf-8')
cipher = AES.new(key_bytes, AES.MODE_ECB)
blocks = pad(ptext.encode('utf-8'), AES.block_size)
print("AES-192 (ECB) concise steps:")
print(" • Key expansion: Nk=6, Nb=4, Nr=12 → 13 round keys")
print(" • Initial round: AddRoundKey")
print(" • Main rounds (1..11): SubBytes → ShiftRows → MixColumns → AddRoundKey")
print(" • Final round (12): SubBytes → ShiftRows → AddRoundKey\n")
out = bytearray()
for i in range(0, len(blocks), 16):
block = blocks[i:i+16]
print(f"Block {i//16} plaintext: {block.hex()}")
print(" Round 0: AddRoundKey")
for r in range(1, 12):
print(f" Round {r}: SubBytes → ShiftRows → MixColumns → AddRoundKey")
print(" Round 12: SubBytes → ShiftRows → AddRoundKey")
cblock = cipher.encrypt(block)
print(f" Ciphertext block: {cblock.hex()}\n")
out.extend(cblock)
return bytes(out)
def main():
default_pt = "MIT AES DEMO"
default_key = "MIT-AES-192-DEMO-KEY-24!"
ptext = input(f"Enter plaintext (blank={default_pt}): ").strip()
key = input(f"Enter key (blank={default_key}): ").strip()
if not ptext:
ptext = default_pt
if not key:
key = default_key
ctext = aes_en_trace(ptext, key)
print("Ciphertext:", ctext.hex())
print("Decrypted:", aes_de(ctext, aespad_key(key)))
if __name__ == '__main__':
main()

View file

@ -0,0 +1,120 @@
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()