[go: up one dir, main page]

Skip to content

Commit

Permalink
Add final comments. Allow message length to change
Browse files Browse the repository at this point in the history
  • Loading branch information
HK-Transfield committed Oct 22, 2021
1 parent 3d92ac7 commit 4db9e86
Show file tree
Hide file tree
Showing 10 changed files with 352 additions and 106 deletions.
62 changes: 50 additions & 12 deletions Main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
from QKE import Emulation
#!/usr/bin/env python3
# ---------------------------------------------------------------------------
__author__ = "Harmon Transfield"
# ---------------------------------------------------------------------------
"""
Main method, runs the entire application. Allows for different configurations
with respect to the type of emulation the user would like to run and the
length of qubits they want to send
"""
# ---------------------------------------------------------------------------

from QKE.Emulation import QKEEmulator

emulator = None
Expand All @@ -9,28 +19,56 @@
print("\nQuantum-Key Exchange Emulator, by Harmon Transfield")
print("------------------------------------------------------\n")

# Configure what type of emulation the user wants to run
while True:
run_type_input = input(
"What type of QKE do you want to run?\n1. Standard QKE\n2. Intercept and Resend\n3. MITM Attack\nEnter (1, 2, 3): "
)
break

# Just add some very basic validation
if run_type_input not in ('1', '2', '3'):
print("Invalid input, please enter 1, 2, or 3")
else:
break

# Configure how many qubits the stream length will be
while True:
qubit_length_input = input(
"How many Qubits do you want to use?\n1. 16\n2. 256 \n3. 1048\nEnter (1, 2, 3): "
"\nHow many Qubits do you want to use?\n1. 16\n2. 256 \n3. 1048\nEnter (1, 2, 3): "
)
break

# More basic validation
if run_type_input not in ('1', '2', '3'):
print("Invalid input, please enter 1, 2, or 3")
else:
break

# Set a message length
while True:
message_length_input = int(
input("\nEnter the length of the message (16 - 4096): "))

# More basic validation
if message_length_input < 16 or message_length_input > 4096:
print("Invalid input, please enter a number ")
else:
break

# Create a new emulation session
emulator = QKEEmulator(run_type=run_type_dict[run_type_input],
message_length=message_length_input,
qubit_length=qubit_length_dict[qubit_length_input])

successful_QKE = emulator.run_QKE()
successful_encryption = emulator.run_symmetric_encryption()

if successful_QKE:
print("The QKE Algorithm performed successfully!")
# We need to generate some keys first before attempting encryption
QKE_session = emulator.run_QKE()
if QKE_session:
print("The emulation successfully performed a QKE!")
else:
print("Oh no! looks like someone messed up the keys")
print("The emulation could not produce matching keys")

if successful_encryption:
print("Message sucessfully Ciphered")
# Keys have been generated, we can now perform a symmetric encryption
encryption_session = emulator.run_symmetric_encryption()
if encryption_session:
print("The emulation successfully performed a symmetric encryption")
else:
print("The emulation could not perform a symmetric encyption")
8 changes: 3 additions & 5 deletions QKE/Channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
"""
# ---------------------------------------------------------------------------

import numpy as np
from numpy.random import randint

from .Qubit import Qubit
from .XOR import cipher

Expand All @@ -29,14 +27,14 @@ def __init__(self, ql: int):
self.qubit_length = ql

##################################################################
# SETTERS and GENERAL UTILITIES
# GENERAL UTILITIES
##################################################################

def set_random(self) -> list:
def generate_random(self) -> list:
"""Returns a random list of 1s and 0s"""
return randint(2, size=self.qubit_length).tolist()

def set_message(self, message_size: int) -> int:
def generate_message(self, message_size: int) -> int:
"""Returns a message as a random list of 1s and 0s"""
return randint(2, size=message_size).tolist()

Expand Down
112 changes: 80 additions & 32 deletions QKE/Emulation.py
Original file line number Diff line number Diff line change
@@ -1,86 +1,132 @@
#!/usr/bin/env python3
# ---------------------------------------------------------------------------
__author__ = "Harmon Transfield"
# ---------------------------------------------------------------------------
"""
Implements an emulation of the QKE algorithm, followed by the secure exchange
of a symmetrically encrypted message using the key produced by QKE.
"""
# ---------------------------------------------------------------------------

from .Channel import QuantumChannel

qubit_lengths = [16, 256, 1024]
message_size = 2048 # Use if wanting to have a randomized message
# message_size = 2048


class QKEEmulator:
def __init__(self, qubit_length: int, run_type: str = None):
self.qubit_length = qubit_length
self.qc = QuantumChannel(self.qubit_length)
"""This class represents an emulation of a QKE."""
def __init__(self,
qubit_length: int,
message_length: int = 512,
run_type: str = None):
"""Constructor. Instantiates a new QKEEmulator.
Parameters
----------
qubit_length : int
The maximum number of qubits that will be sent in the stream.
Used to instantiate a new QuantumChannel.
message_length : int
How long the randomly generated message will be
run_type : str (Optional)
A flag that signals what kind of emulation you want to execute:
- standard: Executes a QKE without any attacks (default)
- intercept: Executes a QKE with a intercept-resend MITM attack
- attack: Executes a QKE with a confidential MITM attack
"""
self.qc = QuantumChannel(qubit_length)
self.run_type = run_type
self.message_length = message_length
self.alice_key = None
self.bob_key = None
self.eve_key = None

def run_QKE(self) -> bool:
"""Starts a new QKE session.
This algorithm uses 3 characters:
1. Alice (Transmitter)
2. Bob (Receiver)
3. Eve (Eavesdropper)
Returns
----------
bool
True if Bob and Alice's keys are matching, or Eve's key matches Alice and Bob's key.
"""

# Alice generates randoms values and polarizations
alice_vals = self.qc.generate_random()
alice_pols = self.qc.generate_random()

# Step 1: Alice generates randoms values and polarizations
alice_vals = self.qc.set_random()
alice_pols = self.qc.set_random()
# Alice creates qubits and sends them through the stream
self.qc.encode_qubits(alice_vals, alice_pols)

print(
"-----------------------------------------------------------------"
)
print("------------------------------------------------------")
print("Alice's Values\n{}\n".format(alice_vals))
print("Alice's Polarizations\n{}\n".format(alice_pols))

# Alice creates qubits and sends them through the stream
self.qc.encode_qubits(alice_vals, alice_pols)
print("------------------------------------------------------")

# Interception! Eve retrieves qubits and measures them with her own polarizations
if self.run_type == "intercept":
eve_pols = self.qc.set_random()
eve_pols = self.qc.generate_random()
eve_interception = self.qc.measure_qubits(eve_pols)

print(
"-----------------------------------------------------------------"
)
print("Eve's Polarizations\n{}\n".format(eve_pols))
print("Eve's Intercepted Results\n{}\n".format(eve_interception))

bob_pols = self.qc.set_random()
# Bob measures the qubits using his own random polarizations
bob_pols = self.qc.generate_random()
bob_measurements = self.qc.measure_qubits(bob_pols)

print(
"-----------------------------------------------------------------"
)
print("Bob's Polarizations\n{}\n".format(bob_pols))
print("Bob's Measured Results\n{}\n".format(bob_measurements))

# Eve has access to the qubit stream and the exchanged polarizations
if self.run_type == "attack":
eve_interception = self.qc.measure_qubits(bob_pols)
self.eve_key = self.qc.generate_key(alice_pols, bob_pols,
eve_interception)

print("Eve's Intercepted Resutls (With Bob's polarization)\n{}\n".
print("Eve's Intercepted Results (With Bob's polarization)\n{}\n".
format(eve_interception))
print("Eve's Malicious Key\n{}\n".format(self.eve_key))

# Alice and Bob generate a secret key and discard the rest of the qubits
self.alice_key = self.qc.generate_key(alice_pols, bob_pols, alice_vals)
self.bob_key = self.qc.generate_key(alice_pols, bob_pols,
bob_measurements)
print(
"-----------------------------------------------------------------"
)

print("------------------------------------------------------")
print("Alice's Key\n{}\n".format(self.alice_key))
print("Bob's Key\n{}\n".format(self.alice_key))
print("Bob's Key\n{}\n".format(self.bob_key))

if self.run_type == "attack":
print("Eve's Malicious Key\n{}\n".format(self.eve_key))

if self.eve_key is not None:
return self.eve_key == self.alice_key and self.eve_key == self.bob_key

return self.alice_key == self.bob_key

def run_symmetric_encryption(self) -> bool:
"""Performs a symmetric encryption using a key.
"""
try:
alice_message = self.qc.set_message(message_size)
alice_message = self.qc.generate_message(self.message_length)

alice_cipher = self.qc.cipher_message(alice_message,
self.alice_key)
bob_message = self.qc.cipher_message(alice_cipher, self.bob_key)

print(
"-----------------------------------------------------------------"
)
print("------------------------------------------------------")
print("Alice's Message\n{}\n".format(
self.qc.list_to_string(alice_message)))
print("Cipher\n{}\n".format(self.qc.list_to_string(alice_cipher)))
print("Bob's Message\n{}\n".format(
self.qc.list_to_string(bob_message)))

Expand All @@ -92,7 +138,9 @@ def run_symmetric_encryption(self) -> bool:
self.qc.list_to_string(alice_message)))

return self.qc.list_to_string(
alice_message) == self.qc.list_to_string(eve_message)
alice_message) == self.qc.list_to_string(
eve_message) and self.qc.list_to_string(
bob_message) == self.qc.list_to_string(eve_message)

return self.qc.list_to_string(
alice_message) == self.qc.list_to_string(bob_message)
Expand Down
4 changes: 2 additions & 2 deletions QKE/XOR.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def cipher(message: list, key: list) -> list:
Raises
----------
ZeroDivisionError
If there is no key passed in, resulting in there
There is no key passed in, resulting in there
being a modulo division with zero
"""

Expand All @@ -46,4 +46,4 @@ def cipher(message: list, key: list) -> list:
return ciphered_message

except ZeroDivisionError:
print("Error: The key does not exist")
print("Error: Cannot encrypt with an empty key!")
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ python3 Main.py
---
To run tests
```
pip -r Requirements.txt
pip install -r Requirements.txt
python3 -m pytest
```
42 changes: 0 additions & 42 deletions Tests/test_QKE.py

This file was deleted.

Loading

0 comments on commit 4db9e86

Please sign in to comment.