diff --git a/DH-AES/README.md b/DH-AES/README.md index 03e4671..da0db1e 100644 --- a/DH-AES/README.md +++ b/DH-AES/README.md @@ -2,7 +2,7 @@ ## Setup and requirements -- Recommended Python version: 3.10.5 or later +- Minimum required Python version: 3.6 - Install packages from requirements.txt ## Run program diff --git a/README.md b/README.md new file mode 100644 index 0000000..01aa89d --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# CSE539_Applied_Cryptography_Midterm + +Programming assignments/midterm for Fall 2023 CSE539 - Applied Cryptography at ASU, check README files in both folders! diff --git a/RSA/README.md b/RSA/README.md new file mode 100644 index 0000000..3464777 --- /dev/null +++ b/RSA/README.md @@ -0,0 +1,30 @@ +# RSA encryption + +## Setup and requirements + +- Minimum required Python version: 3.3 +- No additional dependencies + +## Run program + +The specified example's inputs: + +```shell +python3 rsa.py 254 1223 251 1339 17 65535 66536047120374145538916787981868004206438539248910734713495276883724693574434582104900978079701174539167102706725422582788481727619546235440508214694579 1756026041 +``` + +This gives the attached outputs: +![Output for above command](rsa_output.png "Output for above command") + +For a more verbose output, include the `--verbose` flag: + +```shell +python3 rsa.py 254 1223 251 1339 17 65535 66536047120374145538916787981868004206438539248910734713495276883724693574434582104900978079701174539167102706725422582788481727619546235440508214694579 1756026041 --verbose +``` + +![More verbose output](rsa_verbose_output.png "Verbose output") + +### Notes and inferences + +- Recent versions (2.2+) of Python automatically handle large numbers +- In this implementation, Euler totient function is used, and not Carmichael totient function diff --git a/RSA/RSA-Project.pdf b/RSA/RSA-Project.pdf new file mode 100644 index 0000000..6532e06 Binary files /dev/null and b/RSA/RSA-Project.pdf differ diff --git a/RSA/rsa.py b/RSA/rsa.py new file mode 100644 index 0000000..b241af7 --- /dev/null +++ b/RSA/rsa.py @@ -0,0 +1,101 @@ +import os +import argparse + + +def buildExpNum(exponent: int, constant: int, base: int = 2) -> int: + return pow(base, exponent) - constant + + +def gcdExtendedEuclidean(a: int, b: int) -> (int, int, int): + if a == 0: + return (b, 0, 1) + gcd, x, y = gcdExtendedEuclidean(b % a, a) + return (gcd, y - (b // a) * x, x) + + +def modularInverse(a: int, b: int) -> int: + """Find modular inverse of `a` under modulo `b`""" + g, x, y = gcdExtendedEuclidean(a, b) + if g != 1: + raise ValueError("non-coprime arguments provided") + return x % b + + +def generatePrivateKey(e: int, p: int, q: int) -> (int, int): + n = p * q + lambda_n = (p - 1) * (q - 1) # Euler totient function + d = modularInverse(e, lambda_n) + + # verify + if (e * d) % lambda_n != 1: + raise Exception("error computing d") + return n, d + + +def decrypt(ciphertext: str, key: int, N: int) -> str: + """RSA decryption with private key""" + return str(pow(int(ciphertext), key, N)) + + +def encrypt(plaintext: str, key: int, N: int) -> str: + """RSA encryption with public key""" + return str(pow(int(plaintext), key, N)) + + +def main(args: argparse.Namespace) -> None: + # pre-processing inputs + p_e = int(args.p_e) + p_c = int(args.p_c) + q_e = int(args.q_e) + q_c = int(args.q_c) + e_e = int(args.e_e) + e_c = int(args.e_c) + ciphertext = str(args.ciphertext) + plaintext = int(args.plaintext) + verbose = args.verbose + + p = buildExpNum(p_e, p_c) + q = buildExpNum(q_e, q_c) + pub_key = e = buildExpNum(e_e, e_c) + if verbose: + print(("-" * os.get_terminal_size().columns) + "\n") + print("Given public key (e)\t\t", pub_key) + print(("-" * os.get_terminal_size().columns) + "\n") + + N, priv_key = generatePrivateKey(e, p, q) + if verbose: + print("Calculated private key (d)\t", priv_key) + print(("-" * os.get_terminal_size().columns) + "\n") + + new_pt = decrypt(ciphertext, priv_key, N) + if verbose: + print("Given ciphertext\t\t", ciphertext) + print("Decrypted plaintext\t\t", new_pt) + print(("-" * os.get_terminal_size().columns) + "\n") + + new_ct = encrypt(plaintext, pub_key, N) + if verbose: + print("Given plaintext\t\t\t", plaintext) + print("Encrypted ciphertext\t\t", new_ct) + print(("-" * os.get_terminal_size().columns) + "\n") + + if not verbose: + print(new_pt, new_ct) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Extended Euclidean algorithm and RSA encryption/decryption" + ) + parser.add_argument("p_e", help="Exponent (base 2), for p") + parser.add_argument("p_c", help="Constant to be subtracted, for p") + parser.add_argument("q_e", help="Exponent (base 2), for q") + parser.add_argument("q_c", help="Constant to be subtracted, for q") + parser.add_argument("e_e", help="Exponent (base 2), for e") + parser.add_argument("e_c", help="Constant to be subtracted, for e") + parser.add_argument("ciphertext", help="Ciphertext to be decrypted") + parser.add_argument("plaintext", help="Plaintext to be encrypted") + parser.add_argument("-v", "--verbose", action="store_true") + args = parser.parse_args() + + main(args) diff --git a/RSA/rsa_output.png b/RSA/rsa_output.png new file mode 100644 index 0000000..253dd28 Binary files /dev/null and b/RSA/rsa_output.png differ diff --git a/RSA/rsa_verbose_output.png b/RSA/rsa_verbose_output.png new file mode 100644 index 0000000..69906a5 Binary files /dev/null and b/RSA/rsa_verbose_output.png differ