From 7202cf26b98c5f19735285799a86866d5506dfa5 Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 5 Mar 2024 10:47:18 +0000 Subject: [PATCH 01/14] pbenc_aes_ctr in python --- TPs/TP02/py/input.txt.dec | 1 - TPs/TP02/py/input.txt.enc | 2 +- TPs/TP02/py/input.txt.enc.dec | 1 + TPs/TP02/py/pbenc_aes_ctr.py | 109 ++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 TPs/TP02/py/input.txt.enc.dec create mode 100644 TPs/TP02/py/pbenc_aes_ctr.py diff --git a/TPs/TP02/py/input.txt.dec b/TPs/TP02/py/input.txt.dec index afe74b8..e69de29 100644 --- a/TPs/TP02/py/input.txt.dec +++ b/TPs/TP02/py/input.txt.dec @@ -1 +0,0 @@ -panda é fixe!!! diff --git a/TPs/TP02/py/input.txt.enc b/TPs/TP02/py/input.txt.enc index 7517ad9..ce7432a 100644 --- a/TPs/TP02/py/input.txt.enc +++ b/TPs/TP02/py/input.txt.enc @@ -1 +1 @@ -[n "[vշ4Z![n{V#쁻 \ No newline at end of file +US9hM(#cboe@].J?K.k|Davz>Z:"] \ No newline at end of file diff --git a/TPs/TP02/py/input.txt.enc.dec b/TPs/TP02/py/input.txt.enc.dec new file mode 100644 index 0000000..afe74b8 --- /dev/null +++ b/TPs/TP02/py/input.txt.enc.dec @@ -0,0 +1 @@ +panda é fixe!!! diff --git a/TPs/TP02/py/pbenc_aes_ctr.py b/TPs/TP02/py/pbenc_aes_ctr.py new file mode 100644 index 0000000..b494cf7 --- /dev/null +++ b/TPs/TP02/py/pbenc_aes_ctr.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 + +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC +from cryptography.hazmat.primitives import hashes +import os +import argparse + + + +def encrypt(input_file, password): + inp = open(input_file,"rb") + out = open(f"{input_file}.enc","wb") + + plaintext = inp.read() + print(f"plaintext len : {len(plaintext)}") + + + # Derive the key from the password using PBKDF2 + salt = os.urandom(16) + kdf = PBKDF2HMAC( + algorithm=hashes.SHA256(), + length=32, + salt=salt, + iterations=100000 + ) + + key = kdf.derive(password.encode('utf-8')) + iv = os.urandom(16) + + cipher = Cipher(algorithms.AES(key),modes.CTR(iv)) + encryptor = cipher.encryptor() + ciphertext = encryptor.update(plaintext) + + ciphertext = salt + iv + ciphertext + + print(f"plaintext len : {len(plaintext)}") + print(f"ciphertext len : {len(ciphertext)}") + print(f"iv len : {len(iv)}") + + + out.write(ciphertext) + + inp.close() + out.close() + +def decrypt(input_file,password): + inp = open(f"{input_file}","rb") + out = open(f"{input_file}.dec","wb") + + input_bytes = inp.read() + salt = input_bytes[:16] + iv = input_bytes[16:32] + ciphertext = input_bytes[32:] + + kdf = PBKDF2HMAC( + algorithm=hashes.SHA256(), + length=32, + salt=salt, + iterations=100000 + ) + + print(f"plaintext len : {len(ciphertext)}") + print(f"iv len : {len(iv)}") + print(f"salt len : {len(salt)}") + + key = kdf.derive(password.encode('utf-8')) + + # FIX: block size for aes must be 16 bytes + # plaintext needs padding + cipher = Cipher(algorithms.AES(key),modes.CTR(iv)) + decryptor = cipher.decryptor() + plaintext = decryptor.update(ciphertext) + + out.write(plaintext) + + inp.close() + out.close() + +def main(): + parser = argparse.ArgumentParser( + description="Program to perform operations using AES cipher on files", + ) + + subparsers = parser.add_subparsers(dest="operation", help="Operation to perform") + + # Encrypt subcommand + enc_parser = subparsers.add_parser("enc", help="Encrypt a file") + enc_parser.add_argument("fich", help="File to be encrypted") + enc_parser.add_argument("password", help="Pass-phrase to derive the key") + + # Decrypt subcommand + dec_parser = subparsers.add_parser("dec", help="Decrypt a file") + dec_parser.add_argument("fich", help="File to be decrypted") + dec_parser.add_argument("password", help="Pass-phrase to derive the key") + + args = parser.parse_args() + match args.operation: + case "enc": + input_file = args.fich + password = args.password + encrypt(input_file,password) + case "dec": + input_file = args.fich + password = args.password + decrypt(input_file,password) + +if __name__ == "__main__": + main() From 4826f2fe7526c2ef9d61adc2dd68b151db73483e Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 5 Mar 2024 11:18:24 +0000 Subject: [PATCH 02/14] TP03 pbenc_aes_ctr_hmac in python --- TPs/TP03/py/pbenc_aes_ctr_hmac.py | 128 ++++++++++++++++++++++++++++++ TPs/TP03/py/plaintext.txt | 1 + TPs/TP03/py/plaintext.txt.enc | Bin 0 -> 77 bytes TPs/TP03/py/plaintext.txt.enc.dec | 1 + 4 files changed, 130 insertions(+) create mode 100644 TPs/TP03/py/pbenc_aes_ctr_hmac.py create mode 100644 TPs/TP03/py/plaintext.txt create mode 100644 TPs/TP03/py/plaintext.txt.enc create mode 100644 TPs/TP03/py/plaintext.txt.enc.dec diff --git a/TPs/TP03/py/pbenc_aes_ctr_hmac.py b/TPs/TP03/py/pbenc_aes_ctr_hmac.py new file mode 100644 index 0000000..76a0fbf --- /dev/null +++ b/TPs/TP03/py/pbenc_aes_ctr_hmac.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 + +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hmac +import os +import argparse + + + +def encrypt(input_file, password): + inp = open(input_file,"rb") + out = open(f"{input_file}.enc","wb") + + plaintext = inp.read() + print(f"plaintext len : {len(plaintext)}") + + + # Derive the key from the password using PBKDF2 + salt = os.urandom(16) + kdf = PBKDF2HMAC( + algorithm=hashes.SHA256(), + length=64, + salt=salt, + iterations=100000 + ) + # FIX: key length must be 32 bytes + derived_key = kdf.derive(password.encode('utf-8')) + + key = derived_key[:32] + hmac_key = derived_key[32:] + + iv = os.urandom(16) + + cipher = Cipher(algorithms.AES(key),modes.CTR(iv)) + encryptor = cipher.encryptor() + ciphertext = encryptor.update(plaintext) + + ciphertext = salt + iv + ciphertext + + print(f"plaintext len : {len(plaintext)}") + print(f"ciphertext len : {len(ciphertext)}") + print(f"iv len : {len(iv)}") + + h = hmac.HMAC(hmac_key,hashes.SHA256()) + h.update(ciphertext) + tag = h.finalize() + ciphertext = ciphertext + tag + + out.write(ciphertext) + + inp.close() + out.close() + +def decrypt(input_file,password): + inp = open(f"{input_file}","rb") + out = open(f"{input_file}.dec","wb") + + input_bytes = inp.read() + salt = input_bytes[:16] + iv = input_bytes[16:32] + ciphertext = input_bytes[32:-32] + tag = input_bytes[-32:] + + kdf = PBKDF2HMAC( + algorithm=hashes.SHA256(), + length=64, + salt=salt, + iterations=100000 + ) + + print(f"plaintext len : {len(ciphertext)}") + print(f"iv len : {len(iv)}") + print(f"salt len : {len(salt)}") + + derived_key = kdf.derive(password.encode('utf-8')) + hmac_key = derived_key[32:] + key = derived_key[:32] + + # FIX: block size for aes must be 16 bytes + # plaintext needs padding + cipher = Cipher(algorithms.AES(key),modes.CTR(iv)) + decryptor = cipher.decryptor() + plaintext = decryptor.update(ciphertext) + + h = hmac.HMAC(hmac_key,hashes.SHA256()) + h.update(salt + iv + ciphertext) + if (h.finalize() != tag): + print("Error: HMAC verification failed") + return + + + out.write(plaintext) + + inp.close() + out.close() + +def main(): + parser = argparse.ArgumentParser( + description="Program to perform operations using AES cipher on files", + ) + + subparsers = parser.add_subparsers(dest="operation", help="Operation to perform") + + # Encrypt subcommand + enc_parser = subparsers.add_parser("enc", help="Encrypt a file") + enc_parser.add_argument("fich", help="File to be encrypted") + enc_parser.add_argument("password", help="Pass-phrase to derive the key") + + # Decrypt subcommand + dec_parser = subparsers.add_parser("dec", help="Decrypt a file") + dec_parser.add_argument("fich", help="File to be decrypted") + dec_parser.add_argument("password", help="Pass-phrase to derive the key") + + args = parser.parse_args() + match args.operation: + case "enc": + input_file = args.fich + password = args.password + encrypt(input_file,password) + case "dec": + input_file = args.fich + password = args.password + decrypt(input_file,password) + +if __name__ == "__main__": + main() diff --git a/TPs/TP03/py/plaintext.txt b/TPs/TP03/py/plaintext.txt new file mode 100644 index 0000000..549938f --- /dev/null +++ b/TPs/TP03/py/plaintext.txt @@ -0,0 +1 @@ +not very safe \ No newline at end of file diff --git a/TPs/TP03/py/plaintext.txt.enc b/TPs/TP03/py/plaintext.txt.enc new file mode 100644 index 0000000000000000000000000000000000000000..dfd60ebb9ae6f7fcbe9d9d94b446cf21286c482e GIT binary patch literal 77 zcmV-T0J8t8xPVM*C7L+n!;KhNA~6H%mG{D7W(&tt^o3ZOo{Ep8Rj0@m@JYpflWH(p jX`@B`#tYcjy8@l8xd1>^{xOyLzk>j>7yP(s%GSX7 Date: Tue, 5 Mar 2024 11:44:55 +0000 Subject: [PATCH 03/14] Authenticated Chacha20 in python --- TPs/TP03/py/pbenc_chacha20_poly1305.py | 87 ++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 TPs/TP03/py/pbenc_chacha20_poly1305.py diff --git a/TPs/TP03/py/pbenc_chacha20_poly1305.py b/TPs/TP03/py/pbenc_chacha20_poly1305.py new file mode 100644 index 0000000..ff1ea73 --- /dev/null +++ b/TPs/TP03/py/pbenc_chacha20_poly1305.py @@ -0,0 +1,87 @@ +from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 +import argparse +import os + + +def setup(key_file): + key = ChaCha20Poly1305.generate_key() + with open(key_file, "wb") as f: + f.write(key) + + +def encrypt(input_file, key_file): + with open(key_file, "rb") as f: + key = f.read(32) + + with open(input_file, "rb") as f: + plaintext = f.read() + + aad = b"authenticated but unencrypted data" + nonce = os.urandom(12) + + cipher = ChaCha20Poly1305(key) + ciphertext = cipher.encrypt(nonce, plaintext, aad) + + with open(f"{input_file}.enc", "wb") as f: + f.write(nonce + ciphertext) + + + +def decrypt(input_file, key_file): + with open(key_file, "rb") as f: + key = f.read(32) + + with open(input_file, "rb") as f: + input_bytes = f.read() + + aad = b"authenticated but unencrypted data" + nonce = input_bytes[:12] + ciphertext = input_bytes[12:] + + + cipher = ChaCha20Poly1305(key) + plaintext = cipher.decrypt(nonce, ciphertext, aad) + + with open(f"{input_file}.dec", "wb") as f: + f.write(plaintext) + + +def main(): + parser = argparse.ArgumentParser( + description="Program to perform operations using Authenticated ChaCha20 cipher on files", + ) + + subparsers = parser.add_subparsers(dest="operation", help="Operation to perform") + + # Setup subcommand + setup_parser = subparsers.add_parser("setup", help="Setup a key file") + setup_parser.add_argument("fkey", help="File to contain the appropriate key for the ChaCha20 cipher") + + # Encrypt subcommand + enc_parser = subparsers.add_parser("enc", help="Encrypt a file") + enc_parser.add_argument("fich", help="File to be encrypted") + enc_parser.add_argument("fkey", help="File containing the key for the ChaCha20 cipher") + + # Decrypt subcommand + dec_parser = subparsers.add_parser("dec", help="Decrypt a file") + dec_parser.add_argument("fich", help="File to be decrypted") + dec_parser.add_argument("fkey", help="File containing the key for the ChaCha20 cipher") + + args = parser.parse_args() + match args.operation: + case "setup": + key_file = args.fkey + setup(key_file) + case "enc": + input_file = args.fich + key_file = args.fkey + encrypt(input_file,key_file) + case "dec": + input_file = args.fich + key_file = args.fkey + decrypt(input_file,key_file) + case "help": + parser.print_help() + +if __name__ == "__main__": + main() From 9d9261fddde999ee4783d6ee9fc6b1232a94e794 Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 5 Mar 2024 11:51:14 +0000 Subject: [PATCH 04/14] AES-GCM in python --- TPs/TP03/py/pbenc_aes_gcm_hmac.py | 76 +++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 TPs/TP03/py/pbenc_aes_gcm_hmac.py diff --git a/TPs/TP03/py/pbenc_aes_gcm_hmac.py b/TPs/TP03/py/pbenc_aes_gcm_hmac.py new file mode 100644 index 0000000..b21287e --- /dev/null +++ b/TPs/TP03/py/pbenc_aes_gcm_hmac.py @@ -0,0 +1,76 @@ +import os +from cryptography.hazmat.primitives.ciphers.aead import AESGCM +import argparse + +def setup(key_file): + key = AESGCM.generate_key(bit_length=128) + with open(key_file, "wb") as f: + f.write(key) + + +def encrypt(input_file, key_file): + with open(input_file, "rb") as f: + plaintext = f.read() + + with open(key_file, "rb") as f: + key = f.read() + + aad = b"authenticated but unencrypted data" + aesgcm = AESGCM(key) + nonce = os.urandom(12) + + ct = aesgcm.encrypt(nonce, plaintext, aad) + + with open(f"{input_file}.enc", "wb") as f: + f.write(nonce) + f.write(ct) + + +def decrypt(input_file, key_file): + with open(input_file, "rb") as f: + nonce = f.read(12) + ct = f.read() + + with open(key_file, "rb") as f: + key = f.read() + + aad = b"authenticated but unencrypted data" + aesgcm = AESGCM(key) + pt = aesgcm.decrypt(nonce, ct, aad) + + with open(f"{input_file}.dec", "wb") as f: + f.write(pt) + + + +def main(): + parser = argparse.ArgumentParser( + description="Program to perform operations using AES-GCM cipher on files", + ) + + subparsers = parser.add_subparsers(dest="operation", help="Operation to perform") + + # Encrypt subcommand + enc_parser = subparsers.add_parser("enc", help="Encrypt a file") + enc_parser.add_argument("fich", help="File to be encrypted") + enc_parser.add_argument("password", help="Pass-phrase to derive the key") + + # Decrypt subcommand + dec_parser = subparsers.add_parser("dec", help="Decrypt a file") + dec_parser.add_argument("fich", help="File to be decrypted") + dec_parser.add_argument("password", help="Pass-phrase to derive the key") + + args = parser.parse_args() + match args.operation: + case "enc": + input_file = args.fich + password = args.password + encrypt(input_file,password) + case "dec": + input_file = args.fich + password = args.password + decrypt(input_file,password) + +if __name__ == "__main__": + main() + From 299708f56c77c4e6f126fa0b9cff3c8c800420e6 Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 5 Mar 2024 12:09:58 +0000 Subject: [PATCH 05/14] Added readme, added exception throw and copied attack program from tp02 --- TPs/TP03/Readme.md | 8 +++++++ TPs/TP03/attack_fail.png | Bin 0 -> 21651 bytes TPs/TP03/py/chacha20_int_attck.py | 30 +++++++++++++++++++++++++ TPs/TP03/py/pbenc_chacha20_poly1305.py | 8 ++++++- 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 TPs/TP03/Readme.md create mode 100644 TPs/TP03/attack_fail.png create mode 100644 TPs/TP03/py/chacha20_int_attck.py diff --git a/TPs/TP03/Readme.md b/TPs/TP03/Readme.md new file mode 100644 index 0000000..a469ec8 --- /dev/null +++ b/TPs/TP03/Readme.md @@ -0,0 +1,8 @@ +# Questao 1 + +Ao utilizar o programa 'chacha20_int_attck.py' sobre um criptograma produzido por 'pbenc_chacha20_poly1305', the decrpyt function will raise the execption : +- 'cryptography.exceptions.InvalidTag' – If the authentication tag doesn’t validate this exception will be raised. This will occur when the ciphertext has been changed, but will also occur when the key, nonce, or associated data are wrong. + +We can try this by encrypting a message and then changing the ciphertext with the attack program: + +[Failed Attack](https://github.com/uminho-mei-es/2324-G05/tree/main/TPs/TP03/images/failed_attack.png) \ No newline at end of file diff --git a/TPs/TP03/attack_fail.png b/TPs/TP03/attack_fail.png new file mode 100644 index 0000000000000000000000000000000000000000..f489c7af9193aa7beb2714a320856e426c40cf85 GIT binary patch literal 21651 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 M7Ix+pX85@O0A3K_4gdfE literal 0 HcmV?d00001 diff --git a/TPs/TP03/py/chacha20_int_attck.py b/TPs/TP03/py/chacha20_int_attck.py new file mode 100644 index 0000000..60ad33c --- /dev/null +++ b/TPs/TP03/py/chacha20_int_attck.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import sys + +def attack(fctxt, pos, plainAtPos, newPlainAtPos): + f = open(fctxt,"rb") + ciphertext = f.read() + f.close() + + plainAtPos = plainAtPos.encode() + newPlainAtPos = newPlainAtPos.encode() + txt_len = len(plainAtPos) + diff = bytes([a ^ b for (a,b) in zip(plainAtPos,newPlainAtPos)]) + cipher_diff = bytes([a ^ b for (a,b) in zip(diff,ciphertext[pos:pos+txt_len])]) + + new_ciphertext = ciphertext[:pos] + cipher_diff + ciphertext[pos+txt_len:] + + with open(fctxt+".attck","wb") as f: + f.write(new_ciphertext) + +def main(): + argv = sys.argv[1:] + argc = len(argv) + if argc < 3 or argc > 5: + sys.exit("Needs 4 arguments ") + + attack(argv[0],int(argv[1]),argv[2],argv[3]) + +if __name__ == "__main__": + main() diff --git a/TPs/TP03/py/pbenc_chacha20_poly1305.py b/TPs/TP03/py/pbenc_chacha20_poly1305.py index ff1ea73..714793c 100644 --- a/TPs/TP03/py/pbenc_chacha20_poly1305.py +++ b/TPs/TP03/py/pbenc_chacha20_poly1305.py @@ -40,7 +40,13 @@ def decrypt(input_file, key_file): cipher = ChaCha20Poly1305(key) - plaintext = cipher.decrypt(nonce, ciphertext, aad) + try: + plaintext = cipher.decrypt(nonce, ciphertext, aad) + except Exception as e: + print(f"Could not validate the authentication: {e}") + return + + with open(f"{input_file}.dec", "wb") as f: f.write(plaintext) From 5e8d0cfd535a05dbbbb378b6b135c80a7c35293a Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 5 Mar 2024 12:11:08 +0000 Subject: [PATCH 06/14] fixed readme --- TPs/TP03/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TPs/TP03/Readme.md b/TPs/TP03/Readme.md index a469ec8..45c94ca 100644 --- a/TPs/TP03/Readme.md +++ b/TPs/TP03/Readme.md @@ -5,4 +5,4 @@ Ao utilizar o programa 'chacha20_int_attck.py' sobre um criptograma produzido po We can try this by encrypting a message and then changing the ciphertext with the attack program: -[Failed Attack](https://github.com/uminho-mei-es/2324-G05/tree/main/TPs/TP03/images/failed_attack.png) \ No newline at end of file +![Failed Attack](https://github.com/uminho-mei-es/2324-G05/blob/main/TPs/TP03/attack_fail.png) \ No newline at end of file From b726a165a4851641bf8ae27753fad2f0bc7c334f Mon Sep 17 00:00:00 2001 From: tsousa111 Date: Sat, 16 Mar 2024 17:11:11 +0000 Subject: [PATCH 07/14] TP04 finished and testes --- TPs/TP04/cfich_nike.py | 116 ++++++++++++++++++++++++----------------- TPs/TP04/input | 8 +++ 2 files changed, 77 insertions(+), 47 deletions(-) create mode 100644 TPs/TP04/input diff --git a/TPs/TP04/cfich_nike.py b/TPs/TP04/cfich_nike.py index beeafb9..d04e296 100644 --- a/TPs/TP04/cfich_nike.py +++ b/TPs/TP04/cfich_nike.py @@ -1,11 +1,11 @@ import argparse import os +import cryptography.hazmat.primitives.serialization as serialization from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import dh from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 from cryptography.hazmat.primitives.kdf.hkdf import HKDF -import cryptography.hazmat.primitives.serialization as serialization from cryptography.hazmat.primitives.serialization import ( Encoding, NoEncryption, @@ -13,106 +13,125 @@ from cryptography.hazmat.primitives.serialization import ( PublicFormat, ) +p = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF +g = 2 +params = dh.DHParameterNumbers(p, g).parameters() + def setup(user): - parameters = dh.generate_parameters(generator=2, key_size=512) - private_key = parameters.generate_private_key() + private_key = params.generate_private_key() public_key = private_key.public_key() - skey = open(f"{user}.sk", 'wb') - pkey = open(f"{user}.pk", 'wb') - skey.write(private_key.private_bytes(encoding=Encoding.PEM, format=PrivateFormat.PKCS8, encryption_algorithm=NoEncryption())) - pkey.write(public_key.public_bytes(encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo)) + skey = open(f"{user}.sk", "wb") + pkey = open(f"{user}.pk", "wb") + skey.write( + private_key.private_bytes( + encoding=Encoding.PEM, + format=PrivateFormat.PKCS8, + encryption_algorithm=NoEncryption(), + ) + ) + pkey.write( + public_key.public_bytes( + encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo + ) + ) skey.close() pkey.close() -def encrypt(user,filename): - peer_pkey_file = open(f"{user}.pk", 'rb') +def encrypt(user, filename): + peer_pkey_file = open(f"{user}.pk", "rb") if peer_pkey_file is None: print(f"No public key found for {user}") return - file_r = open(filename, 'rb') + file_r = open(filename, "rb") if file_r is None: print(f"File {filename} not found") return - # FIX: Add try - parameters = dh.generate_parameters(generator=2, key_size=512) - skey = parameters.generate_private_key() - peer_pkey= serialization.load_pem_public_key(peer_pkey_file.read()) - derived_key = None - if isinstance(peer_pkey, dh.DHPublicKey): - shared_key = skey.exchange(peer_pkey) - derived_key = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=b'handshake data').derive(shared_key) - else: + + skey = params.generate_private_key() + peer_pkey = serialization.load_pem_public_key(peer_pkey_file.read()) + if not isinstance(peer_pkey, dh.DHPublicKey): print("Error: Invalid key type") return + shared_key = skey.exchange(peer_pkey) + derived_key = HKDF( + algorithm=hashes.SHA256(), length=32, salt=None, info=None + ).derive(shared_key) + message = file_r.read() chacha = ChaCha20Poly1305(derived_key) nonce = os.urandom(12) ciphertext = chacha.encrypt(nonce, message, None) - file_w = open(f"{filename}.enc", 'wb') - nonce_ciphertext = mkpair(nonce, ciphertext) - to_send = mkpair(peer_pkey.public_bytes(Encoding.PEM, PublicFormat.SubjectPublicKeyInfo), nonce_ciphertext) + file_w = open(f"{filename}.enc", "wb") + nonce_ciphertext = nonce + ciphertext + pkey_bytes = skey.public_key().public_bytes( + Encoding.DER, PublicFormat.SubjectPublicKeyInfo + ) + to_send = mkpair(pkey_bytes, nonce_ciphertext) file_w.write(to_send) file_r.close() file_w.close() - skey_file.close() peer_pkey_file.close() -def decrypt(user,filename): - skey_file = open(f"{user}.sk", 'rb') +def decrypt(user, filename): + skey_file = open(f"{user}.sk", "rb") if skey_file is None: print(f"No private key found for {user}") return - file_r = open(filename, 'rb') + file_r = open(filename, "rb") if file_r is None: print(f"File {filename} not found") return message_bytes = file_r.read() peer_pkey_bytes, ciphertext = unpair(message_bytes) - # FIX: Add try - skey = serialization.load_pem_private_key(skey_file.read(), None) - peer_pkey = serialization.load_pem_public_key(peer_pkey_bytes) - derived_key = None - if isinstance(skey, dh.DHPrivateKey) and isinstance(peer_pkey, dh.DHPublicKey): - shared_key = skey.exchange(peer_pkey) - derived_key = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=b'handshake data').derive(shared_key) - else: + + skey = serialization.load_pem_private_key(skey_file.read(), None) + peer_pkey = serialization.load_der_public_key(peer_pkey_bytes) + if not isinstance(skey, dh.DHPrivateKey) or not isinstance( + peer_pkey, dh.DHPublicKey + ): print("Error: Invalid key type") return - nonce, encrypted_message = unpair(ciphertext) + shared_key = skey.exchange(peer_pkey) + derived_key = HKDF( + algorithm=hashes.SHA256(), length=32, salt=None, info=None + ).derive(shared_key) + + nonce = ciphertext[:12] + encrypted_message = ciphertext[12:] chacha = ChaCha20Poly1305(derived_key) message = chacha.decrypt(nonce, encrypted_message, None) - file_w = open(f"{filename}.decrypt", 'wb') + file_w = open(f"{filename}.dec", "wb") file_w.write(message) file_r.close() file_w.close() skey_file.close() - - def mkpair(x, y): - """ produz uma byte-string contendo o tuplo '(x,y)' ('x' e 'y' são byte-strings) """ + """produz uma byte-string contendo o tuplo '(x,y)' ('x' e 'y' são byte-strings)""" len_x = len(x) - len_x_bytes = len_x.to_bytes(2, 'little') + len_x_bytes = len_x.to_bytes(2, "little") return len_x_bytes + x + y + def unpair(xy): - """ extrai componentes de um par codificado com 'mkpair' """ - len_x = int.from_bytes(xy[:2], 'little') - x = xy[2:len_x+2] - y = xy[len_x+2:] + """extrai componentes de um par codificado com 'mkpair'""" + len_x = int.from_bytes(xy[:2], "little") + x = xy[2 : len_x + 2] + y = xy[len_x + 2 :] return x, y + def main(): parser = argparse.ArgumentParser( description="Program to perform operations using ChaCha20 cipher on files", @@ -121,7 +140,9 @@ def main(): subparsers = parser.add_subparsers(dest="operation", help="Operation to perform") # Setup subcommand - setup_parser = subparsers.add_parser("setup", help="Setup diffie helman key pair for user") + setup_parser = subparsers.add_parser( + "setup", help="Setup diffie helman key pair for user" + ) setup_parser.add_argument("user", help="User for which to setup the key pair") # Encrypt subcommand @@ -142,11 +163,12 @@ def main(): case "enc": user = args.user file = args.file - encrypt(user,file) + encrypt(user, file) case "dec": user = args.user file = args.file - decrypt(user,file) + decrypt(user, file) + if __name__ == "__main__": main() diff --git a/TPs/TP04/input b/TPs/TP04/input new file mode 100644 index 0000000..badaeeb --- /dev/null +++ b/TPs/TP04/input @@ -0,0 +1,8 @@ +As armas e os barões assinalados, +Que da ocidental praia Lusitana, +Por mares nunca de antes navegados, +Passaram ainda além da Taprobana, +Em perigos e guerras esforçados, +Mais do que prometia a força humana, +E entre gente remota edificaram +Novo Reino, que tanto sublimaram; From cac7356abb55ead2a84217ede8c6880cc877fad5 Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 19 Mar 2024 19:17:59 +0000 Subject: [PATCH 08/14] imported certificates --- TPs/TP05/ALICE.crt | 23 +++++++++++++++++++++++ TPs/TP05/ALICE.key | 30 ++++++++++++++++++++++++++++++ TPs/TP05/BOB.crt | 23 +++++++++++++++++++++++ TPs/TP05/BOB.key | 30 ++++++++++++++++++++++++++++++ TPs/TP05/EC.crt | 23 +++++++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 TPs/TP05/ALICE.crt create mode 100644 TPs/TP05/ALICE.key create mode 100644 TPs/TP05/BOB.crt create mode 100644 TPs/TP05/BOB.key create mode 100644 TPs/TP05/EC.crt diff --git a/TPs/TP05/ALICE.crt b/TPs/TP05/ALICE.crt new file mode 100644 index 0000000..985abe4 --- /dev/null +++ b/TPs/TP05/ALICE.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyzCCArOgAwIBAgIUCPhaX8nmoqG8snFrfNe+saiJ8CswDQYJKoZIhvcNAQEL +BQAwgYoxCzAJBgNVBAYTAlBUMQ4wDAYDVQQIDAVNaW5obzEOMAwGA1UEBwwFQnJh +Z2ExHjAcBgNVBAoMFVVuaXZlcnNpZGFkZSBkbyBNaW5obzENMAsGA1UECwwETVNH +UzEfMB0GA1UEAwwWRW50aWRhZGUgQ2VydGlmaWNhZG9yYTELMAkGA1UEQQwCRUMw +HhcNMjQwMzA4MjEzOTM4WhcNMjQwNjE2MjEzOTM4WjB9MQswCQYDVQQGEwJQVDEO +MAwGA1UECAwFTWluaG8xDjAMBgNVBAcMBUJyYWdhMR4wHAYDVQQKDBVVbml2ZXJz +aWRhZGUgZG8gTWluaG8xDTALBgNVBAsMBE1TR1MxDjAMBgNVBAMMBUFMSUNFMQ8w +DQYDVQRBDAZDTElFTlQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6 +dLkrGhqif05lmhTWKbRbWRtMpAqTlPs1uNTg4h0eXhvGGpWQBYiQ2lekreTtXB4U +vJ0EjDxcTQ68SodEvoLYlotPtnDlLwP5yAeoRy96lyFwbgWMjWQY/ILCY7CtLYmo +9ZA2ySL/6K1agDTE5Y+eRqO2WKu1kYL1O66zUs3dA+EsbWWGg6/sRvUWE+SuZV7O +OMXKtEszeqbeD0E10O7b+wBx5CvomZb4GYDQMiZkhcP7Gg4pLakgQ4EWvM6Jqmun +4DdMiutKxD5L2Q+MNhkYh8+1CsVg9z/MAd6OheSYyMKQD4M0MLm2EY35g+dHijL0 +S+XhRGikr0xI9jSDmFMnAgMBAAGjNTAzMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/ +BAQDAgbAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQA8 +MHI0Ss76IPWq3fEODzLdfAQ86khHNZZ+KQEnOOb8h5UEVSciwiilISxTHltPmNPX +7YRvBvY3LFfURPQwV0UPL7FErORXMny8epd3W4/D/sL6HOL8n/5uq442jW8rPnaA +wFUcoLXBRxX+sTFXQisqGewpEzUpyf2MGJoneOcB3xQteQv7K0Sp3rop0LmlEV74 +/ZP6cMjW4MjxLn71J6y3tJ5FP4rTpbUmefnD1F8YVsuNNb0kj1CUsx5YMIFp4PjQ +sruJXrAGTlqa8YuUwwjX7v6wvMv8Di95TIMgTm7bwonsjO7lmQsO261zGySfa0hF +jMUsOA7r+H44aIyWAeNb +-----END CERTIFICATE----- diff --git a/TPs/TP05/ALICE.key b/TPs/TP05/ALICE.key new file mode 100644 index 0000000..3a609e7 --- /dev/null +++ b/TPs/TP05/ALICE.key @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,5614AC7BE85EAABC3789637A31321B7F + +HxiSg2g4b4agu05VuCQdKdiAvh7fQaBsPVYvvuGvGa3szsol9RBwdEviaOE9hIWz +vKIJghMVEz6C6fWwHoTv6qegTT0uMK6+Z7XN6Ma7GVABE9JDCc7AvAP8or1T0+NN +xh3iztDQvPu+EfLD0jaZDP2pmz5ymq/ibeHIf8hutrdF9dkeNuwtRhKJ9vLv+S5c +mJ4etKwDK1un2lt3wQpWSYQoqSKBz1B4tJT+NL6Nz0ZVW3nEcjNpUdLhBK+yBusM +s7LwiEoqG/1VxDx8gPweOVHDIeURjaOR91NOSdjwwpwOuYOWdhSkfEa/fGSVol9u +QMLEtNN1SRAWvakAmwhNrPNlSRRcFjn2nvO4AS1dRxZuwZEkYuiWeGONGFD6S4lK +rG1rvwYlI28p9+VKVDi7XsW+HUFJ1tG2qYC5BgAOav3S9HIFhjhvYn3sOoM/0vxt +cSr7r94v88UFhvKJZUSLHZn/yCiSX069yYEdY0grt8ZJRhRpN5G7o2T5ejQzGj8l +U8fyDr89DlPYEQn/2eMgxIPcSghxAQqYF5MHvnZ6/CjNMKgQFc8ymGiq/HXveTE9 +91WtuH4NQZYsXanN6ZtUQm3a2h8lJD8x/H8LDQPFtwMfHMQP1WK8FlaiKiT7242Q +Gu98ZwEyRBY1qO9rVYX0nbsXMxLAMefdtZlAgKovl1S5xj5r6LcIvFDsVqN5K98h +IK2aoOG023wYJ4eNkjL4dBJiwZ5+RUg3sj4wkNzidcd0cucioj7mbTl4SWJilMI+ +fSXzvJADEI4qyjZbPb3KNGqeX0tvF7bkRHwZk91b1ihvvWsK1Lc6j++aDzOraqxS +yVT5IuBy/kd/L+qps3UipneWuUA9NmqUgtIvp20W5R8G9aAfZFFaK0uVPbOYSLum +WNIfBZDZN0SnuiiVoLCaMkFRzK/5GL7UTKKr5JQxS4KW+1VDrdUc8NqzMBhmFwmX +fcGZNOj7bNkckooFIIEtUVL1r2/wX8t3hRY9M4S+MYuOR6Vr2yuajEJPodFD1Hom +BMQDrkicVUJ9yP6QL/UO7a+QNZ2wdaIjfG6zOZkf0RQ/JxJtCN5jaziV6LNE/SfX +UPeh/EdxVqU9hcdcZw6UsLCrVBpRJCwe5UhVHzrsShFW5DqdNBB0Blfxy/9X3IP4 +tyOeLqRj7jgHrVgd11rccOiB7vyydUL8J+ilmMbFDlk8lfJYvDked7OaQ5ca3/q9 +djkJfVBzGX4s7leJKg8286FBhceKgWhlyqrmXWe9WuBZNj8M94RvoZOCzrlw7WgF +SFf2kSNmh0yXFtsYlNO5skmJo0pgZc5qDQnkHlfXq+Hf89a62L+igsgiy5F1cShx +lCiFa/fkLUe3/+7kJg9XR35XqbLdFS0OLTMmLyghsL+p1Iab28xvajc2jyb7ftGe +CBDD0KT3FvEYSFiE8o0JVYgiWav5NJOML7kW0fq6/ZUm1j9oXxWBpZx8rlVs1jTK +16vkatrUENs9xaWmDsYvuvBmOnSFFzaCFcZ/mE6ixUUim7qKZWfGGwcTs6e1UmlW +twsdWhQEVdZF9mF3NdXqUGqWOHV5RJCHyx3sGzps+pb3DiIgp1Xu6Y8R1057sGKY +-----END RSA PRIVATE KEY----- diff --git a/TPs/TP05/BOB.crt b/TPs/TP05/BOB.crt new file mode 100644 index 0000000..497d736 --- /dev/null +++ b/TPs/TP05/BOB.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyTCCArGgAwIBAgIUX4OZN6EvuWMWUD7EWgYwomRa2JswDQYJKoZIhvcNAQEL +BQAwgYoxCzAJBgNVBAYTAlBUMQ4wDAYDVQQIDAVNaW5obzEOMAwGA1UEBwwFQnJh +Z2ExHjAcBgNVBAoMFVVuaXZlcnNpZGFkZSBkbyBNaW5obzENMAsGA1UECwwETVNH +UzEfMB0GA1UEAwwWRW50aWRhZGUgQ2VydGlmaWNhZG9yYTELMAkGA1UEQQwCRUMw +HhcNMjQwMzA4MjEzOTM3WhcNMjQwNjE2MjEzOTM3WjB7MQswCQYDVQQGEwJQVDEO +MAwGA1UECAwFTWluaG8xDjAMBgNVBAcMBUJyYWdhMR4wHAYDVQQKDBVVbml2ZXJz +aWRhZGUgZG8gTWluaG8xDTALBgNVBAsMBE1TR1MxDDAKBgNVBAMMA0JPQjEPMA0G +A1UEQQwGU0VSVkVSMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAljc+ +6jnrgaXhkNqTTCfi4i55Poxmj2AM3xVxlZwron1oAFFx7Uw1RoqE+bKLk3chZPTu +I6Va4Ch9UF1lHl3YKf7+Z0I68JC/Z4mnZGnTYOZ2b9V5WqIyDWFcQlGhKfEQlPZg +BJYZNlrnmePTJjUkniG3+t3u9rSvm/5copv+/Bp5jb9lXZAHVoYNulVY9Th5aRQZ +8PB2bu+k3bsz/rGtF3TRpuMPu1oGoBUq6OVVWWZ6279DlKwycq+Yxl+0dd9dZD80 +X+yTyzTd8pkWwRTEtQ3cy4z+V5NsBlw7JBVOPVNz0FtRrUctZmgvW/S87yrUDOQ5 +eBXVsZwrZm6tmtHhVQIDAQABozUwMzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQE +AwIGwDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAQEAay7j +May5ZrUh0O/XC/n/+NpxrxtUOWy+9ioGa/EJcuPRQJbyHTBkF7jhdY5WwgEMe2e/ +qJvM9sDfx0EL6fc6S3Dku6LINvsFKGOp3ljYt5JZZGXFiNshCEXjJ5l061jWWenn +bAo2ef8OiO0LnfNqAZLqpRD0nI+AdEdqU/O5e792IMzPVNqDVxccYGvHron63WzB +/32gqBBby5gU0USTXffwCLlauv51wKAXCwkp7uGvU0adKp2vL9rHo5OY67N4FzaA +2a3/SMX5YMy0fvMB5Ao8mR2Y+jmQ8Lwb1xIMBx43NOc8exZtfPoHWH6WMKNyYx4i +ydtkrMURnOOdXcBpAQ== +-----END CERTIFICATE----- diff --git a/TPs/TP05/BOB.key b/TPs/TP05/BOB.key new file mode 100644 index 0000000..3df7657 --- /dev/null +++ b/TPs/TP05/BOB.key @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,003D12E5CDCB087CCE0B3C7E89D2D651 + +lQirD96D/XjbbJOlZUzBQDqSmKeKICwrawMHddX6t34N414dcGuLaFPVDdvW5Aml +W6gI43ovOLJQzF+thtHRflANehPE7ObHM+oRJn7+yyzHOv7zvFlm+8GBqRSb6H8m +iVoupPPlFjcUfiy/6DNdRWU3iL2iIGFSwhbboZANrXMTBT+p7GGoaRTxdtwTd3hd +kj2U73ehg9TeGSH/ftXr0dOGKIBZLXeQlIpiPTy86yn93fZ28E3EmjgOCWJXblTa +Plv6xuLY/Y8vZUjjhoJto9IzeA5to4aI30gW90JkxaTnedk9ZL1skjMUKHCrl2Mi +loKU0AI7wJrVlEl7ea3xZ52U+5Qe/KmkZL8GLo5MsB9Fc0jbpRhbsLrrocRW8qgy +KYROLFb5l0s3N2WUN3zBmEO8vjm47mbZblGpPbHGpnVEvuqppNwBoWtUCiq9iptU +0BWWcQ68QUdl0YDp+Mutl3/28ONJo9UYtBFo55PLTNG8tp9qz0Bh/i2hqoCIFoqD +k0rVkGVaXU54IqQLZdF6yhWsKlUyehX8hy1SgukLzgpzwfHkW9DqlztKrmlcXPYl +bHCAaQhimwufRrqSD7nq2Pn0Mq2qtdp6rn+jS9n6Spls1OPNZx4ev5zxga3v1NfA +nIdXeevmP5VZlkIlZmkcoeMMPBKl1f4hzDL14kdA5kTBRbjasJQce4K6bqrueOxP +qpsTGE9KF64NcD/8a2MQhnnpv7TTIFKy1eLrdrojhHUPnDWlVGJ0ihGpvn2AjmJ9 +YIFkxXhnegwbUYzabWFXk5fuX8Z2rXPXzpaKGfDTrEvpw0katlMZ/k9cfRJa0obb +W0cwUwkgv7kH8DDRpnU2arNLtkQMviZKhNkVudWh7dD9wQwFLu46yyrocz9qbCHF +vRA0IU5wwrHs0VxETEGm9qnfGJLHbSYaj57nybX2SI2tpwyqvdWEzCIuEvJ155Yc +8u4HijBHI2ysEnoUycDJhZSfW/nl+R892Ppf5t29YVIgdM0yUV2nVA2D+e/buDnR +B6ZKACBmNQIQIx9RsF3Q+EQipxUE82at48wWbTVl5iWbWJUbWK+Yoj9M1NDQZZjO +7ytGzg9WkmuG/6HxuKJJl+0/zdn3+9BvgBGBqjEXNHTaG7OSMrIiwOCFmWzFKguh +YLkh26+JuedrRmx1KoubR1q+gc+VDBD8owQaFz00O8virrqFC00zrC0Q0NtiEvCs +24qkFHsvlvEwOwVAS0xL/rORmZ2GoW7hTVYKth6iOfLjJo9Df/UxNrdqFmmjtI3J +G67ao4w93wiJnRwmgPyuvo0i5UKJqxkcwVkEzVuvYlLhgXj9IXp55atFNQ0h8NLr +aoaHPGX/B/Fj7qisIa3925yXHeLBRDtUFsp8koY/GmY2BPuIrc+utwuJykb02puW ++Z+FcWNeCJFxvGJgH1mVUGpcbbO4VwpuT2PoxBIeTca5ujfwJyPEBiXVgB8rfKxV +OjzrHdGIlz3aaLX1zGmiffyEQdWI1RHTk9VwF2K6Yxl+/ARiFqju89vzHXRX7B6s +1CqApD0x5dHmuyqywAX3KE7qyvgQKabL4K33OcLyr1G5i6V0dLKfbseQWzVImpK9 +-----END RSA PRIVATE KEY----- diff --git a/TPs/TP05/EC.crt b/TPs/TP05/EC.crt new file mode 100644 index 0000000..90406d6 --- /dev/null +++ b/TPs/TP05/EC.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID3DCCAsSgAwIBAgIUTH2fOhbGuLcGi6Dy3NlUYspUr/IwDQYJKoZIhvcNAQEL +BQAwgYoxCzAJBgNVBAYTAlBUMQ4wDAYDVQQIDAVNaW5obzEOMAwGA1UEBwwFQnJh +Z2ExHjAcBgNVBAoMFVVuaXZlcnNpZGFkZSBkbyBNaW5obzENMAsGA1UECwwETVNH +UzEfMB0GA1UEAwwWRW50aWRhZGUgQ2VydGlmaWNhZG9yYTELMAkGA1UEQQwCRUMw +HhcNMjQwMzA4MjEzOTMxWhcNMjQwNjE2MjEzOTMxWjCBijELMAkGA1UEBhMCUFQx +DjAMBgNVBAgMBU1pbmhvMQ4wDAYDVQQHDAVCcmFnYTEeMBwGA1UECgwVVW5pdmVy +c2lkYWRlIGRvIE1pbmhvMQ0wCwYDVQQLDARNU0dTMR8wHQYDVQQDDBZFbnRpZGFk +ZSBDZXJ0aWZpY2Fkb3JhMQswCQYDVQRBDAJFQzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKL4muNmXblWtpkGx7/Yfd9MnF++dwVlw835qnzCftMpVtAd +QvyTryrGGNElGQmUNhihnz9zAHQPMFaUt4M3Xx8Wfilts1jzjEpqA3dikWQNkwC8 +ao8JA6v3n8rX0mWFA4Ggee6LpoiAu9YksAr8VYqSxH/cXg5SYybraxwW/GaFkfp9 +brMM7X1rGNeTsWpPpHNUTuMDqdBsaTRw9LAfAg8bDB3JKaIuX78MxH2C2UrCuf0s +WyoEl6mJrDHXqxJ+mFntTLizHzEN3M8AZ/vrz/14avfcuih4i4LxFw/MlvTbWlLm ++gmgOBKmsx7JJ/O9VHg3AsBvG2XtmVc13XA3h4cCAwEAAaM4MDYwDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJ +KoZIhvcNAQELBQADggEBAJCvNfm9zA8Dnk+j5qfzrMTbSbKyNSUR4Ic02Ji+Ew1h +BsydcPMS62+yRH01I+AVLO1QX1dSJUoifQtHDbIOC2HkVaYq7mOyKPWVYkqRQT5u +cwON88wpXqKq50ngT+0+yQMGNdT5+ON2DsL/I70O9WJ/ZE8bNPs+uYkZISvui+FW +n0+iuuXIvB7wtdlVAB1RGvrkvi71UfXUPQXDX92rQj63oyrXuTtEDvsjWidMzPoN +7H5VkAY4t9LTWJhosuNvKZbeHKNiZdUUiz53zTACc6WTN8k7nUyW/m1SgsYwAt1m +AgfXmmTQqOeGFTkt5K3ElmCs3XD2ZMUnRf7w4jwb+ms= +-----END CERTIFICATE----- From b8b32fe189d5dcf0b22d27f9258a376bbb17d1bb Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 19 Mar 2024 19:18:27 +0000 Subject: [PATCH 09/14] Imported certificate loading --- TPs/TP05/sig_fich.py | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 TPs/TP05/sig_fich.py diff --git a/TPs/TP05/sig_fich.py b/TPs/TP05/sig_fich.py new file mode 100644 index 0000000..2d1f256 --- /dev/null +++ b/TPs/TP05/sig_fich.py @@ -0,0 +1,50 @@ +from cryptography import x509 +import datetime + +def cert_load(fname): + """ lê certificado de ficheiro """ + with open(fname, "rb") as fcert: + cert = x509.load_pem_x509_certificate(fcert.read()) + return cert + +def cert_validtime(cert, now=None): + """ valida que 'now' se encontra no período + de validade do certificado. """ + if now is None: + now = datetime.datetime.now(tz=datetime.timezone.utc) + if now < cert.not_valid_before_utc or now > cert.not_valid_after_utc: + raise x509.verification.VerificationError("Certificate is not valid at this time") + +def cert_validsubject(cert, attrs=[]): + """ verifica atributos do campo 'subject'. 'attrs' + é uma lista de pares '(attr,value)' que condiciona + os valores de 'attr' a 'value'. """ + print(cert.subject) + for attr in attrs: + if cert.subject.get_attributes_for_oid(attr[0])[0].value != attr[1]: + raise x509.verification.VerificationError("Certificate subject does not match expected value") + +def cert_validexts(cert, policy=[]): + """ valida extensões do certificado. 'policy' é uma lista de pares '(ext,pred)' onde 'ext' é o OID de uma extensão e 'pred' + o predicado responsável por verificar o conteúdo dessa extensão. """ + for check in policy: + ext = cert.extensions.get_extension_for_oid(check[0]).value + if not check[1](ext): + raise x509.verification.VerificationError("Certificate extensions does not match expected value") + +def valida_certALICE(ca_cert): + try: + cert = cert_load("ALICE.crt") + # obs: pressupõe que a cadeia de certifica só contém 2 níveis + cert.verify_directly_issued_by(ca_cert) + # verificar período de validade... + cert_validtime(cert) + # verificar identidade... (e.g.) + cert_validsubject(cert, [(x509.NameOID.COMMON_NAME, "ALICE")]) + # verificar aplicabilidade... (e.g.) + #cert_validexts(cert, [(x509.ExtensionOID.EXTENDED_KEY_USAGE, lambda e: x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH in e)]) + #print("Certificate is valid!") + return True + except: + #print("Certificate is invalid!") + return False \ No newline at end of file From b7918a2e3061618ab8000b14d0a0c93cc3b39491 Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 19 Mar 2024 21:11:31 +0000 Subject: [PATCH 10/14] Finalized sig_fich implementation --- TPs/TP05/sig_fich.py | 157 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 135 insertions(+), 22 deletions(-) diff --git a/TPs/TP05/sig_fich.py b/TPs/TP05/sig_fich.py index 2d1f256..694b82a 100644 --- a/TPs/TP05/sig_fich.py +++ b/TPs/TP05/sig_fich.py @@ -1,6 +1,28 @@ +import os +import sys +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.backends import default_backend from cryptography import x509 +from cryptography.x509.oid import NameOID +from cryptography.exceptions import InvalidSignature +import argparse import datetime +def mkpair(x, y): + """ produz uma byte-string contendo o tuplo '(x,y)' ('x' e 'y' são byte-strings) """ + len_x = len(x) + len_x_bytes = len_x.to_bytes(2, 'little') + return len_x_bytes + x + y + +def unpair(xy): + """ extrai componentes de um par codificado com 'mkpair' """ + len_x = int.from_bytes(xy[:2], 'little') + x = xy[2:len_x+2] + y = xy[len_x+2:] + return x, y + def cert_load(fname): """ lê certificado de ficheiro """ with open(fname, "rb") as fcert: @@ -8,43 +30,134 @@ def cert_load(fname): return cert def cert_validtime(cert, now=None): - """ valida que 'now' se encontra no período - de validade do certificado. """ + """ valida que 'now' se encontra no período + de validade do certificado. """ if now is None: now = datetime.datetime.now(tz=datetime.timezone.utc) if now < cert.not_valid_before_utc or now > cert.not_valid_after_utc: raise x509.verification.VerificationError("Certificate is not valid at this time") def cert_validsubject(cert, attrs=[]): - """ verifica atributos do campo 'subject'. 'attrs' - é uma lista de pares '(attr,value)' que condiciona - os valores de 'attr' a 'value'. """ + """ verifica atributos do campo 'subject'. 'attrs' + é uma lista de pares '(attr,value)' que condiciona + os valores de 'attr' a 'value'. """ print(cert.subject) for attr in attrs: if cert.subject.get_attributes_for_oid(attr[0])[0].value != attr[1]: raise x509.verification.VerificationError("Certificate subject does not match expected value") def cert_validexts(cert, policy=[]): - """ valida extensões do certificado. 'policy' é uma lista de pares '(ext,pred)' onde 'ext' é o OID de uma extensão e 'pred' - o predicado responsável por verificar o conteúdo dessa extensão. """ + """ valida extensões do certificado. 'policy' é uma lista de pares '(ext,pred)' onde 'ext' é o OID de uma extensão e 'pred' + o predicado responsável por verificar o conteúdo dessa extensão. """ for check in policy: ext = cert.extensions.get_extension_for_oid(check[0]).value if not check[1](ext): raise x509.verification.VerificationError("Certificate extensions does not match expected value") -def valida_certALICE(ca_cert): +def valida_cert(cert, ca_cert, user): try: - cert = cert_load("ALICE.crt") - # obs: pressupõe que a cadeia de certifica só contém 2 níveis - cert.verify_directly_issued_by(ca_cert) - # verificar período de validade... - cert_validtime(cert) - # verificar identidade... (e.g.) - cert_validsubject(cert, [(x509.NameOID.COMMON_NAME, "ALICE")]) - # verificar aplicabilidade... (e.g.) - #cert_validexts(cert, [(x509.ExtensionOID.EXTENDED_KEY_USAGE, lambda e: x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH in e)]) - #print("Certificate is valid!") - return True - except: - #print("Certificate is invalid!") - return False \ No newline at end of file + ca_cert.public_key().verify( + cert.signature, + cert.tbs_certificate_bytes, + padding.PKCS1v15(), + cert.signature_hash_algorithm + ) + except InvalidSignature: + raise x509.verification.VerificationError("Certificate signature is invalid") + + cert_validtime(cert) + + cert_validsubject(cert, [(NameOID.COMMON_NAME, user)]) + + + +""" +sign -- em que assina o conteúdo de usando a chave privada armazenada em .key. +Deve produzir o ficheiro .sig contendo o par composto pela assinatura e certificado do assinante; +""" +def sign(user, filename): + + with open(user + ".key", "rb") as key_file: + private_key = serialization.load_pem_private_key(key_file.read(), password=b'1234', backend=default_backend()) + + user_cert = cert_load(user + ".crt") + + with open(filename, "rb") as file: + data_to_sign = file.read() + + + + signature = private_key.sign(data_to_sign, + padding.PSS(mgf=padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.MAX_LENGTH), + hashes.SHA256()) + + + signature_and_cert = mkpair(signature, user_cert.public_bytes(serialization.Encoding.PEM)) + + with open(filename + ".sig", "wb") as sig_file: + sig_file.write(signature_and_cert) + + + +""" +verify -- verifica a assinatura contida em .sig usando a +informação do signatário contida no certificado (também incluído em .sig). +Deve apresentar o status de validade da assinatura (Válida/Inválida) e, +no caso de ser válida, ainda os dados do signatário. +""" +def verify(filename, user): + + with open(filename + ".sig", "rb") as sig_file: + signature_and_cert = sig_file.read() + + signature, cert_bytes = unpair(signature_and_cert) + + cert = x509.load_pem_x509_certificate(cert_bytes, default_backend()) + + ca_cert = cert_load("EC.crt") + + try: + valida_cert(cert, ca_cert, user) + + with open(filename, "rb") as file: + data_to_verify = file.read() + + cert.public_key().verify(signature, data_to_verify, + padding.PSS(mgf=padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.MAX_LENGTH), + hashes.SHA256()) + + print("Valid signature") + print(cert.subject) + + except x509.verification.VerificationError as e: + print("Invalid signature: " + str(e)) + return + +def main(): + parser = argparse.ArgumentParser(description="Sign or verify files using X.509 certificates.") + parser.add_argument("command", choices=["sign", "verify"], help="Command to execute: 'sign' or 'verify'") + parser.add_argument("user", help="Username") + parser.add_argument("filename", help="File name") + + args = parser.parse_args() + + if args.command == "sign": + if os.path.exists(args.user + ".crt") and os.path.exists(args.user + ".key"): + sign(args.user, args.filename) + print("File signed successfully.") + else: + print("User certificate or private key not found.") + elif args.command == "verify": + if os.path.exists(args.filename + ".sig"): + verify(args.filename, args.user) + else: + print("Signature file not found.") + else: + parser.print_help() + sys.exit(1) + +if __name__ == "__main__": + main() + From 745c926d76e9cb4ff65cf1e12e8785e035868bb2 Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 19 Mar 2024 21:58:27 +0000 Subject: [PATCH 11/14] Refactored elifs into match case --- TPs/TP05/sig_fich.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/TPs/TP05/sig_fich.py b/TPs/TP05/sig_fich.py index 694b82a..ee23477 100644 --- a/TPs/TP05/sig_fich.py +++ b/TPs/TP05/sig_fich.py @@ -140,23 +140,25 @@ def main(): parser.add_argument("command", choices=["sign", "verify"], help="Command to execute: 'sign' or 'verify'") parser.add_argument("user", help="Username") parser.add_argument("filename", help="File name") + parser.add_argument("--test", action="store_true", help="Perform testing (simulate errors)") args = parser.parse_args() - if args.command == "sign": - if os.path.exists(args.user + ".crt") and os.path.exists(args.user + ".key"): + match args.command: + case "sign" if os.path.exists(args.user + ".crt") and os.path.exists(args.user + ".key"): sign(args.user, args.filename) print("File signed successfully.") - else: + case "sign": print("User certificate or private key not found.") - elif args.command == "verify": - if os.path.exists(args.filename + ".sig"): + case "verify" if os.path.exists(args.filename + ".sig"): verify(args.filename, args.user) - else: + case "verify": print("Signature file not found.") - else: - parser.print_help() - sys.exit(1) + case _: + parser.print_help() + sys.exit(1) + + if __name__ == "__main__": main() From c56b2790a3a3d022acbf216052e29c432dd765a4 Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 19 Mar 2024 21:58:36 +0000 Subject: [PATCH 12/14] Questoes do TP5 --- TPs/TP05/Images/Q1.png | Bin 0 -> 22373 bytes TPs/TP05/Readme.md | 56 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 TPs/TP05/Images/Q1.png create mode 100644 TPs/TP05/Readme.md diff --git a/TPs/TP05/Images/Q1.png b/TPs/TP05/Images/Q1.png new file mode 100644 index 0000000000000000000000000000000000000000..f0eb8969f3b99fff1c236034eae26b3b8ea18456 GIT binary patch literal 22373 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 J5_9*+{{kRF?r#79 literal 0 HcmV?d00001 diff --git a/TPs/TP05/Readme.md b/TPs/TP05/Readme.md new file mode 100644 index 0000000..7731a19 --- /dev/null +++ b/TPs/TP05/Readme.md @@ -0,0 +1,56 @@ +# Respostas das Questões +## Q1 + +Para verificar que as chaves fornecidas constituem um par RSA valido, podemos extrair a chave publica do certificado e da chave privada (separadamente) e verificar se a chave publica é igual à chave publica extraída da chave privada. + +[Verificação da chave publica]() + +## Q2 +Utilizando o comando `openssl x509 -text -noout -in xxx.cert` podemos visualizar o conteúdo do certificado. Correndo o comando para o certificado `ALICE.crt` obtemos o seguinte resultado: + +```bash + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 08:f8:5a:5f:c9:e6:a2:a1:bc:b2:71:6b:7c:d7:be:b1:a8:89:f0:2b + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = PT, ST = Minho, L = Braga, O = Universidade do Minho, OU = MSGS, CN = Entidade Certificadora, pseudonym = EC + Validity + Not Before: Mar 8 21:39:38 2024 GMT + Not After : Jun 16 21:39:38 2024 GMT + Subject: C = PT, ST = Minho, L = Braga, O = Universidade do Minho, OU = MSGS, CN = ALICE, pseudonym = CLIENT + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + ... + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Key Usage: critical + Digital Signature, Non Repudiation + X509v3 Extended Key Usage: + TLS Web Client Authentication + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + ... +``` +Neste certificado, os campos importantes incluem: +- **Serial Number**: Identificador único do certificado. +- **Validity**: Indica o período durante o qual o certificado é válido. +- **Subject**: Informações sobre a entidade a quem o certificado é emitido. +- **Subject Public Key Info**: Detalhes sobre a chave pública, incluindo o algoritmo e o tamanho. +- **X509v3 extensions**: Contém informações adicionais, como restrições básicas, uso de chaves e uso de chaves estendido. +- **Signature Algorithm**: Algoritmo usado para assinar o certificado. +- **Signature Value**: O valor de assinatura real que garante a integridade do certificado. + + +## Q3 + +Para provocar erros do tipo de validação do certificado, podemos alterar o certificado de várias maneiras, como: +- Alterar a data de validade para uma data anterior à data atual. +- Alterar o nome do emissor ou do sujeito. +- Alterar a chave pública ou privada. + +Para provocar erros na validação da assinatura, podemos alterar a assinatura do certificado, o que invalidará a assinatura e resultará em um erro de validação. From 00abb58fa6597072773fc18b3a75e8665e3506f8 Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 19 Mar 2024 22:01:19 +0000 Subject: [PATCH 13/14] Updated Relatorio with image --- TPs/TP05/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TPs/TP05/Readme.md b/TPs/TP05/Readme.md index 7731a19..c5400c4 100644 --- a/TPs/TP05/Readme.md +++ b/TPs/TP05/Readme.md @@ -3,7 +3,7 @@ Para verificar que as chaves fornecidas constituem um par RSA valido, podemos extrair a chave publica do certificado e da chave privada (separadamente) e verificar se a chave publica é igual à chave publica extraída da chave privada. -[Verificação da chave publica]() +[Verificação da chave publica](https://github.com/uminho-mei-es/2324-G05/blob/main/TPs/TP05/Images/Q1.png) ## Q2 Utilizando o comando `openssl x509 -text -noout -in xxx.cert` podemos visualizar o conteúdo do certificado. Correndo o comando para o certificado `ALICE.crt` obtemos o seguinte resultado: From 78723fe55f0f6c49cc7bdacfc94fba2f6264cb2c Mon Sep 17 00:00:00 2001 From: LucasVerdelho Date: Tue, 19 Mar 2024 22:02:15 +0000 Subject: [PATCH 14/14] fixed missing syntax issue in relatorio --- TPs/TP05/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TPs/TP05/Readme.md b/TPs/TP05/Readme.md index c5400c4..bc0e4f5 100644 --- a/TPs/TP05/Readme.md +++ b/TPs/TP05/Readme.md @@ -3,7 +3,7 @@ Para verificar que as chaves fornecidas constituem um par RSA valido, podemos extrair a chave publica do certificado e da chave privada (separadamente) e verificar se a chave publica é igual à chave publica extraída da chave privada. -[Verificação da chave publica](https://github.com/uminho-mei-es/2324-G05/blob/main/TPs/TP05/Images/Q1.png) +![Verificação da chave publica](https://github.com/uminho-mei-es/2324-G05/blob/main/TPs/TP05/Images/Q1.png) ## Q2 Utilizando o comando `openssl x509 -text -noout -in xxx.cert` podemos visualizar o conteúdo do certificado. Correndo o comando para o certificado `ALICE.crt` obtemos o seguinte resultado: