CSI-ES-2324/TPs/TP04/cfich_nike.py

174 lines
5.5 KiB
Python

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
from cryptography.hazmat.primitives.serialization import (
Encoding,
NoEncryption,
PrivateFormat,
PublicFormat,
)
p = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF
g = 2
params = dh.DHParameterNumbers(p, g).parameters()
def setup(user):
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.close()
pkey.close()
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")
if file_r is None:
print(f"File {filename} not found")
return
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 = 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()
peer_pkey_file.close()
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")
if file_r is None:
print(f"File {filename} not found")
return
message_bytes = file_r.read()
peer_pkey_bytes, ciphertext = unpair(message_bytes)
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
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}.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)"""
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 main():
parser = argparse.ArgumentParser(
description="Program to perform operations using ChaCha20 cipher on files",
)
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.add_argument("user", help="User for which to setup the key pair")
# Encrypt subcommand
enc_parser = subparsers.add_parser("enc", help="Encrypt a file")
enc_parser.add_argument("user", help="User for which to encrypt the file")
enc_parser.add_argument("file", help="File to encrypt")
# Decrypt subcommand
decrypt_parser = subparsers.add_parser("dec", help="Decrypt a file")
decrypt_parser.add_argument("user", help="Target user for the decryption")
decrypt_parser.add_argument("file", help="File to be decrypted")
args = parser.parse_args()
match args.operation:
case "setup":
user = args.user
setup(user)
case "enc":
user = args.user
file = args.file
encrypt(user, file)
case "dec":
user = args.user
file = args.file
decrypt(user, file)
if __name__ == "__main__":
main()