diff --git a/IS/Lab/Lab2/aes_des_bit.py b/IS/Lab/Lab2/aes_des_bit.py index 102768f..f176d95 100644 --- a/IS/Lab/Lab2/aes_des_bit.py +++ b/IS/Lab/Lab2/aes_des_bit.py @@ -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() diff --git a/IS/Lab/Lab2/des_vs_aes256.html b/IS/Lab/Lab2/des_vs_aes256.html new file mode 100644 index 0000000..6946309 --- /dev/null +++ b/IS/Lab/Lab2/des_vs_aes256.html @@ -0,0 +1,61 @@ + + + + + Bokeh Plot + + + + + +
+ + + + + \ No newline at end of file diff --git a/IS/Lab/Lab2/des_vs_aes256.py b/IS/Lab/Lab2/des_vs_aes256.py index e69de29..e903caa 100644 --- a/IS/Lab/Lab2/des_vs_aes256.py +++ b/IS/Lab/Lab2/des_vs_aes256.py @@ -0,0 +1,176 @@ +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 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 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 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_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 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(): + print("AES-256 vs DES Performance Comparison") + print("=====================================") + + plaintext = input("Enter plaintext: ") + key = input("Enter key: ") + max_iterations = int(input("Enter maximum number of iterations (default 1000): ") or "1000") + + print(f"\nBenchmarking across iteration ranges up to {max_iterations}...") + results = benchmark_ciphers(plaintext, key, max_iterations) + + # 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("\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") + + 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() diff --git a/IS/Lab/Lab2/encryption_performance.html b/IS/Lab/Lab2/encryption_performance.html new file mode 100644 index 0000000..fee1247 --- /dev/null +++ b/IS/Lab/Lab2/encryption_performance.html @@ -0,0 +1,61 @@ + + + + + Bokeh Plot + + + + + +
+ + + + + \ No newline at end of file