diff --git a/instruction.md b/instruction.md index 86df49b5333547653c3b520c1980fab977490cab..76ef81f82961299f7625ddd0e044d9026b06cc13 100644 --- a/instruction.md +++ b/instruction.md @@ -12,54 +12,31 @@ This has been written in Python3 in the context of Viken KARABOGHOSSIAN's projec The project contains the following files: * `requirements.txt`: the list of all required Python3 packages. * `instruction.md`: this file, which contains the instructions to better understand and use the scripts. -* ```interative_plots.py``` : command line tool to interactively decide which algorithms, operations and metrics to visualize. -* ```automated_plots.py```: an automated script to generate and save automatically the required plots. -* ```scenarios.py```: command line tool to interactively create scenario, where a scenario is defined by two end users, a bandwidth and a latency. An end user is defined by its : memory/RAM capacity, plaintext size (size of the transmitted package), and a processor frequency. -* ```main.py```: command line tool to study a scenario and save the result in csv file +* ```main.py```: command line tool to interactively do the comparative study. * `/plots`: a folder in which the plots will be saved. -* `/ciphers_src`: a folder that contains the python implementation of the ciphers we study. +* `/src`: a folder that contains both the python implementation of the ciphers we study and utils fonction for the orrect execution of the main script. * `/doc`: a folder that contains the documentation generated by sphinx. +* `/Litterature`: a folder that contains litterature for the internship. -## Usage (interactive ploting) +## Usage 1. Open the root folder of your project in a terminal. This folder should contain: - * The ```interactive_plots.py``` script - * The csv file containing the results you want to plot (delimiter = ',') + * The ```main.py``` script * This file (`instructions.md`) -2. You will be prompted questions. Answer them and click `enter`. - -## Usage (automated ploting) -1. Open the root folder of your project in a terminal. This folder should contain: - * The ```automated_plots.py``` script - * The csv file containing the results you want to plot (delimiter = ',') - * This file (`instructions.md`) -2. Before executing the script, check the following parameters: - * filepath - * metrics_choices - * operation_choices - * algo_choices -3. Then type: ```python3 automated_plots.py``` -4. Check your results in `/results` - -## Usage (main) - +2. Execute the ```main.py``` script by typing ```python3 main.py```. You will be prompted questions. Answer them and click `enter`. +3. If you decided to save the plot, check them in `/plots` ## Content -The tool was designed to take as input a csv file containing information about the performance evaluation of encryption schemes. As the project studied block cipher and stream cipher, the tool can handle the two following lists of headers: -* Block cipher: -|algo|key_length|block_length|operation|integrity|implementation_size|ram_consumption|throughput|execution_time|memory_usage|encrypted_file_size| - -* Stream cipher: -|algo|key_length|nonce_length|operation|integrity|implementation_size|ram_consumption|throughput|execution_time|memory_usage|encrypted_file_size| +The tool was designed to make a comparative study between a set of symmetric encryption cipher. +It is based on the comparisons of the costs of each cipher in a given scenario (a scebario is a set of two node), where ciher's cost is a weighted summation of the cipher's performances. ------------ ## Improvement and future work: - -* Render the program more flexible. E.g., take csv for which the headers are not known. -* Add autocompletion for paremeter selection (rich.prompt Completion) +* Render the program more flexible. +* Improve the measurments of ciphers' perfomance. ## More to come: -... + # PROGRAM STARTS \ No newline at end of file diff --git a/main.py b/main.py index 596a24bf14e011c36bbfe0ed9b535b35ebb1775e..78128f18655211e564f20783e7aed41a174c959d 100644 --- a/main.py +++ b/main.py @@ -10,8 +10,6 @@ from rich.prompt import Prompt from rich.console import Console from rich.markdown import Markdown import matplotlib.pyplot as plt -import datetime - class Transmission: @@ -29,21 +27,25 @@ class Transmission: self.plaintext_size = len(self.plaintext) ###### Set up the scenario - choice = Prompt.ask("\nChoose between the following scenarios:\n1: end_to_end\n2: ground_to_satellite\n3: satellite_to_satellite\n", - choices=['1', '2', '3'], default='1') + choice = Prompt.ask("\nChoose between the following scenarios:\n0: default \n1: end_to_end\n2: ground_to_satellite\n3: satellite_to_satellite\n", + choices=['0', '1', '2', '3'], default='0') + if choice == '0': + self.scene = 'default' + default = node(1, 1, 1/self.plaintext_size, self.plaintext) + self.scenarii = scenario(default, default, 1, 1, 1, self.plaintext) if choice == '1': self.scene = 'end_to_end' end_user = node(16e9, 8e9, 3.5e9, self.plaintext) - self.scenarii = scenario(end_user, end_user, 13e9, 1600e3, self.plaintext) + self.scenarii = scenario(end_user, end_user, 13e9, 1600e3, 3 * 10 ** 8, self.plaintext) elif choice == '2': self.scene = 'ground_to_satellite' satellite = node(2e9, 512e6, 100e6, self.plaintext) ground_station = node(1e12, 32e9, 4e9, self.plaintext) - self.scenarii = scenario(ground_station, satellite, 13e9, 500e3, self.plaintext) + self.scenarii = scenario(ground_station, satellite, 13e9, 500e3, 3 * 10 ** 8, self.plaintext) elif choice == '3': self.scene = 'satellite_to_satellite' satellite = node(2e9, 512e6, 100e6, self.plaintext) - self.scenarii = scenario(satellite, satellite, 281.7e12, 7371e3, self.plaintext) + self.scenarii = scenario(satellite, satellite, 281.7e12, 7371e3, 3 * 10 ** 8, self.plaintext) def run_analysis(self): @@ -57,46 +59,38 @@ class Transmission: for cipher in self.scenarii.costs[mode].keys(): for combination in self.scenarii.costs[mode][cipher].keys(): plt.barh(combination, self.scenarii.costs[mode][cipher][combination]) + plt.ylabel("Algorithm-key_size/nonce_block_size") + plt.xlabel("Cost") + plt.yticks(fontsize=9) + plt.title(f"Comparative anaysis for a {self.plaintext_size}byte long message") + plt.tight_layout() # Ensures labels don't overlap plt.show() - # Automatic saving - if Prompt.ask("Do you want to save the plot?", choices=['y', 'n'], default='n') == "y": - date = datetime.datetime.now() - for mode in self.scenarii.costs.keys(): - for cipher in self.scenarii.costs[mode].keys(): - for combination in self.scenarii.costs[mode][cipher].keys(): - plt.barh(combination, self.scenarii.costs[mode][cipher][combination]) - plt.savefig('plots/' + 'cost_' + self.scene + '-' + str(date.year) + str(date.month) + - str(date.day) + '-' + str(date.hour) + str(date.minute) + '.png') - - # Clear after saving - plt.clf() - plt.cla() - # Keep only the best combinations self.scenarii.choose_the_better() plt.figure('Now only the best combination for each cipher in a ' + self.scene + ' scenario') + for mode in self.scenarii.costs.keys(): for cipher in self.scenarii.costs[mode].keys(): - for combination in self.scenarii.costs[mode][cipher].keys(): - plt.barh(combination, self.scenarii.costs[mode][cipher][combination]) + combinations = list(self.scenarii.costs[mode][cipher].keys()) + costs = list(self.scenarii.costs[mode][cipher].values()) + + bars = plt.barh(combinations, costs) + + # Adding text labels for each bar + for bar, cost in zip(bars, costs): + label = f'{cost:.6f}' if cost > 0.000001 else f'{cost:.2e}' + plt.text(bar.get_width(), bar.get_y() + bar.get_height()/2, label, + va='center', fontsize=8, color='black', fontweight='bold') + + plt.ylabel("Algorithm-key_size/nonce_block_size") + plt.xlabel("Cost") + plt.yticks(fontsize=9) + plt.title(f"Comparative analysis for a {self.plaintext_size} byte long message") + plt.tight_layout() # Ensures labels don't overlap plt.show() - # Automatic saving - if Prompt.ask("Do you want to save the plot?", choices=['y', 'n'], default='n') == "y": - date = datetime.datetime.now() - for mode in self.scenarii.costs.keys(): - for cipher in self.scenarii.costs[mode].keys(): - for combination in self.scenarii.costs[mode][cipher].keys(): - plt.barh(combination, self.scenarii.costs[mode][cipher][combination]) - plt.savefig('plots/' + 'cost_' + self.scene + '-' + str(date.year) + str(date.month) + - str(date.day) + '-' + str(date.hour) + str(date.minute) + '.png') - - # Clear after saving - plt.clf() - plt.cla() - if __name__ == "__main__": diff --git a/src/ciphers_src/stream_cipher/AES_measuring.py b/src/ciphers_src/stream_cipher/AES_measuring.py index 6108aab88d0d0b901342f8f227120ad9d80faebc..d42374af7b3c400af9c566a72069b1849e2bf995 100644 --- a/src/ciphers_src/stream_cipher/AES_measuring.py +++ b/src/ciphers_src/stream_cipher/AES_measuring.py @@ -14,7 +14,8 @@ from src.ciphers_src.util import measure_software_performance MODE = AES.MODE_CTR -LENGTHS = [[16,nonce] for nonce in range(16)] + [[24 , nonce] for nonce in range(16)] + [[32,nonce] for nonce in range(16)] +#LENGTHS = [[16,nonce] for nonce in range(16)] + [[24 , nonce] for nonce in range(16)] + [[32,nonce] for nonce in range(16)] +LENGTHS = [[16,nonce] for nonce in [8,12]] + [[24 , nonce] for nonce in [8,12]] + [[32,nonce] for nonce in [8,12]] KEY_SIZES = [length[0] for length in LENGTHS] NONCE_SIZES = [length[1] for length in LENGTHS] KEYS = [os.urandom(key_size) for key_size in KEY_SIZES] # Generate a random N-byte long key diff --git a/src/scenarios.py b/src/scenarios.py index 29f2e77ffebd99e96690fcdea670139236650410..4705cea79e3f46702672799f4fa59603229baa7c 100644 --- a/src/scenarios.py +++ b/src/scenarios.py @@ -28,14 +28,12 @@ CIPHER = { } } -SIGNAL_CELERITY = 3 * 10 ** 8 # OEM signal celerity class node : def __init__(self,storage_capacity, RAM_capacity, processor_frequency, plaintext) -> None: self.storage_capacity = storage_capacity self.RAM_capacity = RAM_capacity self.processor_frequency = processor_frequency - stream = self._cipher_analysis('stream', plaintext) block = self._cipher_analysis('block', plaintext) integrity = (stream[1]==block[1]) == True @@ -44,6 +42,7 @@ class node : "stream" : stream[0], "block" : block[0] } + self.normalization() def _cipher_analysis(self, mode, plaintext): @@ -140,12 +139,12 @@ class node : for mode in ['stream','block']: min_max_metrics = { - 'encrytion' : { + 'encryption' : { "implementation_size": [], "ram_consumption": [], "throughput": [], "execution_time": [], - "memory_usage": [], + #"memory_usage": [], "encrypted_file_size": [], #"cpu_cycles": [encryption[6], decryption[6], encryption[6]+ decryption[6]], }, @@ -154,7 +153,7 @@ class node : "ram_consumption": [], "throughput": [], "execution_time": [], - "memory_usage": [], + #"memory_usage": [], "encrypted_file_size": [], #"cpu_cycles": [encryption[6], decryption[6], encryption[6]+ decryption[6]], }, @@ -163,7 +162,7 @@ class node : "ram_consumption": [], "throughput": [], "execution_time": [], - "memory_usage": [], + #"memory_usage": [], "encrypted_file_size": [], #"cpu_cycles": [encryption[6], decryption[6], encryption[6]+ decryption[6]], }, @@ -171,32 +170,36 @@ class node : # add them all in a min_max_metrics dictionnary for cipher in self.ciphers_data[mode].keys() : - for operation in self.ciphers_data[mode][cipher].keys(): - for metric in self.ciphers_data[mode][cipher][operation].keys(): - min_max_metrics[operation][metric].append(self.ciphers_data[mode][cipher][operation][metric]) + for combinaison in self.ciphers_data[mode][cipher].keys(): + for operation in self.ciphers_data[mode][cipher][combinaison].keys(): + if operation != "integrity": + for metric in self.ciphers_data[mode][cipher][combinaison][operation].keys(): + min_max_metrics[operation][metric].append(self.ciphers_data[mode][cipher][combinaison][operation][metric]) # just keep the max and min value for operation in min_max_metrics.keys(): for metric in min_max_metrics[operation].keys(): - max = max(min_max_metrics[operation][metric]) - min = min(min_max_metrics[operation][metric]) - min_max_metrics[operation][metric] = [min, max] + maxim = max(min_max_metrics[operation][metric]) + minim = min(min_max_metrics[operation][metric]) + min_max_metrics[operation][metric] = [minim, maxim] # now normalize for cipher in self.ciphers_data[mode].keys() : - for operation in self.ciphers_data[mode][cipher].keys(): - for metric in self.ciphers_data[mode][cipher][operation].keys(): - maxim = min_max_metrics[operation][metric][1] - minim = min_max_metrics[operation][metric][0] - if [max, min] == [0,0]: - pass - if not (metric == "throughput") : - self.ciphers_data[mode][cipher][operation][metric] -= minim - else : - self.ciphers_data[mode][cipher][operation][metric] = \ - maxim - self.ciphers_data[mode][cipher][operation][metric] - - self.ciphers_data[mode][cipher][operation][metric] /= (maxim-minim) + for combinaison in self.ciphers_data[mode][cipher].keys(): + for operation in self.ciphers_data[mode][cipher][combinaison].keys(): + if operation != "integrity": + for metric in self.ciphers_data[mode][cipher][combinaison][operation].keys(): + maxim = min_max_metrics[operation][metric][1] + minim = min_max_metrics[operation][metric][0] + if [maxim, minim] != [0,0]: + if maxim == minim : + minim=0 + if not (metric == "throughput") : + self.ciphers_data[mode][cipher][combinaison][operation][metric] -= minim + else : + self.ciphers_data[mode][cipher][combinaison][operation][metric] = \ + maxim - self.ciphers_data[mode][cipher][combinaison][operation][metric] + self.ciphers_data[mode][cipher][combinaison][operation][metric] /= (maxim-minim) @@ -204,12 +207,12 @@ class node : class scenario : - def __init__(self, node1, node2, bandwidth, distance, plaintext) -> None: + def __init__(self, node1, node2, bandwidth, distance, signal_celerity, plaintext) -> None: self.node1 = node1 self.node2 = node2 self.bandwidth = bandwidth self.distance = distance - self.latency = distance/SIGNAL_CELERITY + self.latency = distance/signal_celerity self.weights = self._weights(plaintext) self.costs = { @@ -217,8 +220,6 @@ class scenario : 'block' : self._ciphers_cost('block', plaintext) } - - def _weights(self, message):