Initial commit

Completed DH-AES part yesterday
This commit is contained in:
Kaushik Narayan R 2023-10-29 16:18:39 -07:00
commit c6ecfa305b
6 changed files with 136 additions and 0 deletions

BIN
DH-AES/DH-AES-Project.pdf Normal file

Binary file not shown.

33
DH-AES/README.md Normal file
View File

@ -0,0 +1,33 @@
# Diffie-Hellman and AES encryption
## Setup and requirements
- Recommended Python version: 3.10.5 or later
- Install packages from requirements.txt
## Run program
The specified example's inputs:
```shell
python3 dh_aes.py "A2 2D 93 61 7F DC 0D 8E C6 3E A7 74 51 1B 24 B2" 251 465 255 1311 2101864342 8995936589171851885163650660432521853327227178155593274584417851704581358902 "F2 2C 95 FC 6B 98 BE 40 AE AD 9C 07 20 3B B3 9F F8 2F 6D 2D 69 D6 5D 40 0A 75 45 80 45 F2 DE C8 6E C0 FF 33 A4 97 8A AF 4A CD 6E 50 86 AA 3E DF" AfYw7Z6RzU9ZaGUloPhH3QpfA1AXWxnCGAXAwk3f6MoTx
```
This gives the attached outputs:
![Output for above command](dh_aes_output.png "Output for above command")
For a more verbose output, include the `--verbose` flag:
```shell
python3 dh_aes.py "A2 2D 93 61 7F DC 0D 8E C6 3E A7 74 51 1B 24 B2" 251 465 255 1311 2101864342 8995936589171851885163650660432521853327227178155593274584417851704581358902 "F2 2C 95 FC 6B 98 BE 40 AE AD 9C 07 20 3B B3 9F F8 2F 6D 2D 69 D6 5D 40 0A 75 45 80 45 F2 DE C8 6E C0 FF 33 A4 97 8A AF 4A CD 6E 50 86 AA 3E DF" AfYw7Z6RzU9ZaGUloPhH3QpfA1AXWxnCGAXAwk3f6MoTx --verbose
```
![More verbose output](dh_aes_verbose_output.png "Verbose output")
### Notes and inferences
- Recent versions (2.2+) of Python automatically handle large numbers
- Little-endian vs big-endian: given inputs are little-endian byte arrays, so when converting keys from integers to bytes, we convert to little-endian byte order
- `cryptography` package is used here for AES - `pip install cryptography`
- Used AES-256 algorithm - CBC mode of operation, using provided initialization vector (IV is commonly prepended to ciphertext in practice)
- [Library reference for implementation](https://cryptography.io/en/latest/hazmat/primitives/symmetric-encryption/#cryptography.hazmat.primitives.ciphers.Cipher)

102
DH-AES/dh_aes.py Normal file
View File

@ -0,0 +1,102 @@
import os
import argparse
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
def prettyBytes(bytestr: bytes) -> str:
"""Prints byte strings like `\\x3d\\xe9\\xb7` as `3D E9 B7`"""
return " ".join([bytestr[i : i + 1].hex().upper() for i in range(0, len(bytestr))])
def buildExpNum(exponent: int, constant: int, base: int = 2) -> int:
return pow(base, exponent) - constant
def calculateSharedKey(
g_e: int, g_c: int, N_e: int, N_c: int, x: int, gy_modN: int
) -> int:
"""Diffie-Hellman shared key computation (single-party)"""
# g = build_exp_num(g_e, g_c) # not needed since gy_modN is given
N = buildExpNum(N_e, N_c)
return pow(gy_modN, x, N)
def encrypt(plaintext: bytes, key: int, iv: bytearray) -> bytes:
"""Encryption using AES-256 in CBC mode"""
key_byte_length = 32
cipher = Cipher(
algorithms.AES(key.to_bytes(key_byte_length, byteorder="little")), modes.CBC(iv)
)
padder = padding.PKCS7(algorithms.AES.block_size).padder()
padded_plaintext = padder.update(plaintext) + padder.finalize()
encryptor = cipher.encryptor()
return encryptor.update(padded_plaintext) + encryptor.finalize()
def decrypt(ciphertext: bytes, key: int, iv: bytearray) -> bytes:
"""Decryption using AES-256 in CBC mode"""
key_byte_length = 32
cipher = Cipher(
algorithms.AES(key.to_bytes(key_byte_length, byteorder="little")), modes.CBC(iv)
)
decryptor = cipher.decryptor()
return decryptor.update(ciphertext) + decryptor.finalize()
def main(args: argparse.Namespace) -> None:
# pre-processing inputs
iv = bytearray.fromhex(args.initialization_vector)
g_e = int(args.g_e)
g_c = int(args.g_c)
N_e = int(args.N_e)
N_c = int(args.N_c)
x = int(args.x)
gy_modN = int(args.gy_modN)
ciphertext = bytearray.fromhex(args.ciphertext)
plaintext = str.encode(args.plaintext, "utf-8")
verbose = args.verbose
shared_key = calculateSharedKey(g_e, g_c, N_e, N_c, x, gy_modN)
if verbose:
print(("-" * os.get_terminal_size().columns) + "\n")
print("Shared key\t\t", shared_key)
print(("-" * os.get_terminal_size().columns) + "\n")
new_pt = decrypt(ciphertext, shared_key, iv)
if verbose:
print("Given ciphertext\t", prettyBytes(ciphertext))
print("Calculated plaintext\t", new_pt.decode("utf-8"))
print(("-" * os.get_terminal_size().columns) + "\n")
new_ct = encrypt(plaintext, shared_key, iv)
if verbose:
print("Given plaintext\t\t", args.plaintext)
print("Calculated ciphertext\t", prettyBytes(new_ct))
print(("-" * os.get_terminal_size().columns) + "\n")
if not verbose:
print(f"{new_pt.decode('utf-8')}, {prettyBytes(new_ct)}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="DHKE keygen and AES encryption/decryption"
)
parser.add_argument("initialization_vector", help="")
parser.add_argument("g_e", help="Exponent (base 2), for g")
parser.add_argument("g_c", help="Constant to be subtracted, for g")
parser.add_argument("N_e", help="Exponent (base 2), for N")
parser.add_argument("N_c", help="Constant to be subtracted, for N")
parser.add_argument("x", help="Alice's private key value")
parser.add_argument("gy_modN", help="g^y modulo N, computed by Bob")
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)

BIN
DH-AES/dh_aes_output.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

1
DH-AES/requirements.txt Normal file
View File

@ -0,0 +1 @@
cryptography==41.0.5