diff --git a/delivery1/cryptLib/decryptionFuncts.py b/delivery1/cryptLib/decryptionFuncts.py deleted file mode 100644 index 5d7379a..0000000 --- a/delivery1/cryptLib/decryptionFuncts.py +++ /dev/null @@ -1,26 +0,0 @@ -import sys - -from cryptography.hazmat.primitives import serialization, hashes -from cryptography.hazmat.primitives.asymmetric import rsa, padding - - -def decryptFile(private_key, cipher_text): - plain_text = private_key.decrypt( - cipher_text, - padding.OAEP( - mgf=padding.MGF1(algorithm=hashes.SHA256()), - algorithm=hashes.SHA256(), - label=None - ) - ) - return plain_text - - -def load_private_key(file, paswd=None): - with open(file, 'rb') as key_file: - private_key = serialization.load_pem_private_key( - key_file.read(), - password=paswd, - ) - - return private_key diff --git a/delivery1/cryptLib/encryptionFuncts.py b/delivery1/cryptLib/encryptionFuncts.py deleted file mode 100644 index 4531dcc..0000000 --- a/delivery1/cryptLib/encryptionFuncts.py +++ /dev/null @@ -1,23 +0,0 @@ -import sys - -from cryptography.hazmat.primitives import serialization, hashes -from cryptography.hazmat.primitives.asymmetric import rsa, padding - -def encryptFile(public_key, text): - ciphertext = public_key.encrypt( - text, - padding.OAEP( - mgf=padding.MGF1(algorithm=hashes.SHA256()), - algorithm=hashes.SHA256(), - label=None - ) - ) - return ciphertext - -def load_public_key(file): - with open(file, 'rb') as key_file: - public_key = serialization.load_pem_public_key( - key_file.read(), - ) - - return public_key diff --git a/delivery1/lib/decryption_functs.py b/delivery1/lib/decryption_functs.py new file mode 100644 index 0000000..31799b6 --- /dev/null +++ b/delivery1/lib/decryption_functs.py @@ -0,0 +1,69 @@ +import sys + +from cryptography.hazmat.primitives import serialization, hashes +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.backends import default_backend + + + +# function to decrypt data using a symmetric key +def decrypt_symmetric(key, ciphertext): + # generate a random IV + iv = ciphertext[:16] + + # decipher the data using AES in CFB mode + ciphertext = ciphertext[16:] + cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend()) + decryptor = cipher.decryptor() + + return decryptor.update(ciphertext) + decryptor.finalize() + + +# function that calls and combines the symmetric and asymmetric decryption +def decrypt_hybrid(private_key, encrypted_data): + # extract the encrypted symmetric key and the encrypted data (remember that the data is symmetric + asymmetric) + encrypted_symmetric_key = encrypted_data[:private_key.key_size // 8] + encrypted_data = encrypted_data[private_key.key_size // 8:] + + # decrypt the symmetric key using the RSA private key + symmetric_key = private_key.decrypt( + encrypted_symmetric_key, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None + ) + ) + + # decrypt the data using the decrypted symmetric key + return decrypt_symmetric(symmetric_key, encrypted_data) + + +# main function to decrypt the file +def decrypt_file(private_key, encrypted_file, decrypted_file): + with open(encrypted_file, 'rb') as f: + encrypted_content = f.read() + + decrypted_content = decrypt_hybrid(private_key, encrypted_content) + + with open(decrypted_file, 'wb') as f: + f.write(decrypted_content) + + +# function to load a private key from a file +def load_private_key(file, passwd=None): + if passwd is not None: + passwd = passwd.encode('utf-8') + + try: + with open(file, 'rb') as key_file: + private_key = serialization.load_pem_private_key( + key_file.read(), + password=passwd, + ) + except ValueError as e: + raise ValueError("Error: The password is not valid.") from e + + + return private_key diff --git a/delivery1/lib/digest.py b/delivery1/lib/digest.py new file mode 100644 index 0000000..2b7452f --- /dev/null +++ b/delivery1/lib/digest.py @@ -0,0 +1,7 @@ +import cryptography.hazmat.primitives.hashes + + +def get_hash(data): + digest = cryptography.hazmat.primitives.hashes.Hash(cryptography.hazmat.primitives.hashes.SHA256()) + digest.update(data) + return digest.finalize() \ No newline at end of file diff --git a/delivery1/lib/encryption_functs.py b/delivery1/lib/encryption_functs.py new file mode 100644 index 0000000..c788a97 --- /dev/null +++ b/delivery1/lib/encryption_functs.py @@ -0,0 +1,67 @@ +import sys, os + +from cryptography.hazmat.primitives import serialization, hashes +from cryptography.hazmat.primitives.asymmetric import rsa, padding +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.backends import default_backend + + +# function to generate a 256-bit symmetric key +def generate_symmetric_key(): + return os.urandom(32) + + +# function to encrypt data using a symmetric key +def encrypt_symmetric(key, plain_text): + # generate a random IV + iv = os.urandom(16) + + # cipher the data using AES in CFB mode + cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend()) + encryptor = cipher.encryptor() + ciphertext = encryptor.update(plain_text) + encryptor.finalize() + + return iv + ciphertext + + +# function that calls and combines the symmetric and asymmetric encryption +def encrypt_hybrid(public_key, plaintext): + # generate a random symmetric key + symmetric_key = generate_symmetric_key() + + encrypted_data = encrypt_symmetric(symmetric_key, plaintext) + + # encrypt the symmetric key with the public key + encrypted_symmetric_key = public_key.encrypt( + symmetric_key, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), + algorithm=hashes.SHA256(), + label=None + ) + ) + + # combine the symmetric key and the encrypted data + return encrypted_symmetric_key + encrypted_data + + +# main function to encrypt the file +def encrypt_file(public_key, original_file, encrypted_file): + with open(original_file, 'rb') as f: + plaintext = f.read() + + encrypted_content = encrypt_hybrid(public_key, plaintext) + + with open(encrypted_file, 'wb') as f: + f.write(encrypted_content) + + +# function to load a public key from a file +def load_public_key(file): + with open(file, 'rb') as key_file: + public_key = serialization.load_pem_public_key( + key_file.read(), + ) + + return public_key diff --git a/delivery1/cryptLib/keyPair.py b/delivery1/lib/key_pair.py similarity index 89% rename from delivery1/cryptLib/keyPair.py rename to delivery1/lib/key_pair.py index fe7c7e4..c0d28fa 100644 --- a/delivery1/cryptLib/keyPair.py +++ b/delivery1/lib/key_pair.py @@ -4,8 +4,7 @@ from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import rsa, padding -def generate_key_pair(passwd=None): - pub_name, priv_name, key_size = sys.argv[1:] +def generate_key_pair(pub_name, priv_name, key_size, passwd=None): private_key = rsa.generate_private_key( public_exponent=65537, @@ -33,6 +32,3 @@ def generate_key_pair(passwd=None): format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.BestAvailableEncryption(passwd.encode()) )) - - return pub_name, priv_name - diff --git a/delivery1/lib/tests/test_digest.py b/delivery1/lib/tests/test_digest.py new file mode 100644 index 0000000..3800eaf --- /dev/null +++ b/delivery1/lib/tests/test_digest.py @@ -0,0 +1,36 @@ +import os + +from digest import * + +def test_equal_string(): + string_one = "Hello, World!" + string_two = "Hello, World!" + + assert get_hash(bytes(string_one, 'utf-8')) == get_hash(bytes(string_two, 'utf-8')) + + +def test_diff_string(): + string_one = "Hello, World!" + string_two = "Hello, World" + + assert get_hash(bytes(string_one, 'utf-8')) != get_hash(bytes(string_two, 'utf-8')) + + +def test_equal_file(): + # create equal files + os.system("dd if=/dev/zero of=test.txt bs=1024 count=1000 >/dev/null 2>&1") + os.system("dd if=/dev/zero of=test2.txt bs=1024 count=1000 >/dev/null 2>&1") + + assert get_hash(open("test.txt", "rb").read()) == get_hash(open("test2.txt", "rb").read()) + os.remove("test.txt") + os.remove("test2.txt") + + +def test_diff_file(): + # create different files + os.system("dd if=/dev/urandom of=test.txt bs=1024 count=1000 >/dev/null 2>&1") + os.system("dd if=/dev/urandom of=test2.txt bs=1024 count=1000 >/dev/null 2>&1") + + assert get_hash(open("test.txt", "rb").read()) != get_hash(open("test2.txt", "rb").read()) + os.remove("test.txt") + os.remove("test2.txt") \ No newline at end of file diff --git a/delivery1/lib/tests/test_encryption.py b/delivery1/lib/tests/test_encryption.py new file mode 100644 index 0000000..f7944ff --- /dev/null +++ b/delivery1/lib/tests/test_encryption.py @@ -0,0 +1,187 @@ +import os + +from decryption_functs import * +from encryption_functs import * +from key_pair import * + +def test_encryption_no_pwd(): + # create a file to encrypt + with open("test.txt", "w") as f: + f.write("Hello, World!") + + # generate a key pair + generate_key_pair('public.pem', 'private.pem', '2048') + + # load the public and private keys + public_key = load_public_key("public.pem") + private_key = load_private_key("private.pem") + + # encrypt the file + encrypt_file(public_key, "test.txt", "test.enc") + + # decrypt the file + decrypt_file(private_key, "test.enc", "test.dec") + + # check that the decrypted file is the same as the original + with open("test.dec", "r") as f: + assert f.read() == "Hello, World!" + + # cleanup + os.remove("test.txt") + os.remove("test.enc") + os.remove("test.dec") + os.remove("public.pem") + os.remove("private.pem") + + +def test_encryption_with_pwd(): + # create a file to encrypt + with open("test.txt", "w") as f: + f.write("Hello, World!") + + # generate a key pair + generate_key_pair('public.pem', 'private.pem', '2048', 'password') + + # load the public and private keys + public_key = load_public_key("public.pem") + private_key = load_private_key("private.pem", 'password') + + # encrypt the file + encrypt_file(public_key, "test.txt", "test.enc") + + # decrypt the file + decrypt_file(private_key, "test.enc", "test.dec") + + # check that the decrypted file is the same as the original + with open("test.dec", "r") as f: + assert f.read() == "Hello, World!" + + # remove the files + os.remove("test.txt") + os.remove("test.enc") + os.remove("test.dec") + os.remove("public.pem") + os.remove("private.pem") + + +def test_load_private_key_wrong_pwd(): + # generate a key pair + generate_key_pair('public.pem', 'private.pem', '2048', 'password') + + # try to load the private key with the wrong password + try: + load_private_key("private.pem", 'wrong_password') + except ValueError as e: + assert str(e) == "Error: The password is not valid." + + +def test_1mb_file_with_pwd(): + # create a 1mb file to encrypt + os.system("dd if=/dev/urandom of=test.txt bs=1024 count=1000 >/dev/null 2>&1") + + # generate a key pair + generate_key_pair('public.pem', 'private.pem', '2048', 'password') + + # load the public and private keys + public_key = load_public_key("public.pem") + private_key = load_private_key("private.pem", 'password') + + # encrypt the file + encrypt_file(public_key, "test.txt", "test.enc") + + # decrypt the file + decrypt_file(private_key, "test.enc", "test.dec") + + # check that the decrypted file is the same as the original + assert open("test.txt", "rb").read() == open("test.dec", "rb").read() + + # remove the files + os.remove("test.txt") + os.remove("test.enc") + os.remove("test.dec") + os.remove("public.pem") + os.remove("private.pem") + + +def test_1mb_file_no_pwd(): + # create a 1mb file to encrypt + os.system("dd if=/dev/urandom of=test.txt bs=1024 count=1000 >/dev/null 2>&1") + + # generate a key pair + generate_key_pair('public.pem', 'private.pem', '2048') + + # load the public and private keys + public_key = load_public_key("public.pem") + private_key = load_private_key("private.pem") + + # encrypt the file + encrypt_file(public_key, "test.txt", "test.enc") + + # decrypt the file + decrypt_file(private_key, "test.enc", "test.dec") + + # check that the decrypted file is the same as the original + assert open("test.txt", "rb").read() == open("test.dec", "rb").read() + + # remove the files + os.remove("test.txt") + os.remove("test.enc") + os.remove("test.dec") + os.remove("public.pem") + os.remove("private.pem") + + +def test_100mb_file_with_pwd(): + # create a 100mb file to encrypt + os.system("dd if=/dev/urandom of=test.txt bs=1024 count=100000 >/dev/null 2>&1") + + # generate a key pair + generate_key_pair('public.pem', 'private.pem', '2048', 'password') + + # load the public and private keys + public_key = load_public_key("public.pem") + private_key = load_private_key("private.pem", 'password') + + # encrypt the file + encrypt_file(public_key, "test.txt", "test.enc") + + # decrypt the file + decrypt_file(private_key, "test.enc", "test.dec") + + # check that the decrypted file is the same as the original + assert open("test.txt", "rb").read() == open("test.dec", "rb").read() + + # remove the files + os.remove("test.txt") + os.remove("test.enc") + os.remove("test.dec") + os.remove("public.pem") + os.remove("private.pem") + + +def test_100mb_file_no_pwd(): + # create a 100mb file to encrypt + os.system("dd if=/dev/urandom of=test.txt bs=1024 count=100000 >/dev/null 2>&1") + + # generate a key pair + generate_key_pair('public.pem', 'private.pem', '2048') + + # load the public and private keys + public_key = load_public_key("public.pem") + private_key = load_private_key("private.pem") + + # encrypt the file + encrypt_file(public_key, "test.txt", "test.enc") + + # decrypt the file + decrypt_file(private_key, "test.enc", "test.dec") + + # check that the decrypted file is the same as the original + assert open("test.txt", "rb").read() == open("test.dec", "rb").read() + + # remove the files + os.remove("test.txt") + os.remove("test.enc") + os.remove("test.dec") + os.remove("public.pem") + os.remove("private.pem")