0% found this document useful (0 votes)
15 views30 pages

Complex Variables and Linear Algebra Submission 1

The document provides implementations of various encryption algorithms including Caesar Cipher, Hill Cipher, Vigenère Cipher, Playfair Cipher, RSA, Diffie-Hellman, ElGamal, and SHA/MD5 hashing. Each algorithm is explained with Python code snippets demonstrating how to encrypt and decrypt messages. Additionally, it includes examples of key generation and message handling for these cryptographic techniques.

Uploaded by

jaiswalrahul818
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views30 pages

Complex Variables and Linear Algebra Submission 1

The document provides implementations of various encryption algorithms including Caesar Cipher, Hill Cipher, Vigenère Cipher, Playfair Cipher, RSA, Diffie-Hellman, ElGamal, and SHA/MD5 hashing. Each algorithm is explained with Python code snippets demonstrating how to encrypt and decrypt messages. Additionally, it includes examples of key generation and message handling for these cryptographic techniques.

Uploaded by

jaiswalrahul818
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 30

Ceaser Cipher

plaintext = input("Enter the plaintext: ")

k = int(input("Enter the key value: "))

cipher = {}

initial_ascii_cap = 65

initial_ascii_low = 97

# Create mapping for uppercase letters

for i in range(26):

char = chr(initial_ascii_cap + i)

cipher[char] = i

# Create mapping for lowercase letters

for i in range(26):

char = chr(initial_ascii_low + i)

cipher[char] = i

cip = ''

for j in plaintext:

if j.isalpha():

updatedval = cipher[j] + k

updatedval %= 26

if j.islower():

c = chr(updatedval + initial_ascii_low)

else:
c = chr(updatedval + initial_ascii_cap)

cip += c

else:

cip += j # Non-alphabetic characters remain unchanged

print(cip)

hill cipher

import numpy as np

def mod_inverse(a, m):

for x in range(1, m):

if (a * x) % m == 1:

return x

return None

def ttn(text): # text to numbers

return [ord(char) - ord('A') for char in text.upper() if char.isalpha()]

def ntt(numbers): # numbers to text

return ''.join(chr(num + ord('A')) for num in numbers)

def pad_text(text, size):

padding_length = (size - len(text) % size) % size


return text + 'X' * padding_length

def encryption(pt, key):

n = len(key)

pt = pad_text(pt, n)

pt_n = ttn(pt)

cipher = []

for i in range(0, len(pt_n), n):

block = pt_n[i:i+n]

enc_block = np.dot(key, block) % 26

cipher.extend(enc_block)

return ntt(cipher)

def decryption(c, key):

n = len(key)

det = int(round(np.linalg.det(key)))

det_inv = mod_inverse(det % 26, 26)

if det_inv is None:

raise ValueError("Modular inverse doesn't exist; invalid key matrix.")

key_inverse = (

det_inv * np.round(det * np.linalg.inv(key)).astype(int) % 26

) % 26

cipher = ttn(c)

pt_n = []
for i in range(0, len(cipher), n):

block = cipher[i:i+n]

dec_block = np.dot(key_inverse, block) % 26

pt_n.extend(dec_block)

return ntt(pt_n).rstrip('X')

# Example usage

key_m = np.array([[6, 24, 1], [13, 16, 10], [20, 17, 15]])

pt = "HELLO"

enc = encryption(pt, key_m)

print(f"Encrypted = {enc}")

dec = decryption(enc, key_m)

print(f"Decrypted = {dec}")

Vignete cipher

plaintext = input("Enter the plaintext: ")

key = input("Enter the key value: ")

cipher = {}

initial_ascii_cap = 65

initial_ascii_low = 97

# Create alphabet to index mappings

for i in range(26):

cipher[chr(initial_ascii_cap + i)] = i

cipher[chr(initial_ascii_low + i)] = i
cip = ''

vals = []

vals2 = []

# Convert plaintext to values

for j in plaintext:

if j.isalpha():

val = cipher[j]

vals.append(val)

else:

vals.append(j) # Store non-alphabetic characters as-is

# Extend or repeat the key

extended_key = ''

key_index = 0

for ch in plaintext:

if ch.isalpha():

extended_key += key[key_index % len(key)]

key_index += 1

else:

extended_key += ch

# Convert key to values

for j in extended_key:

if j.isalpha():
val = cipher[j]

vals2.append(val)

else:

vals2.append(j)

# Perform encryption

for i in range(len(vals)):

if isinstance(vals[i], int):

new_val = (vals[i] + vals2[i]) % 26

if plaintext[i].islower():

c = chr(new_val + initial_ascii_low)

else:

c = chr(new_val + initial_ascii_cap)

cip += c

else:

cip += vals[i] # Non-alphabetic characters unchanged

print(cip)

playfair cipher

def generate_playfair_matrix(key):

key = key.upper().replace("J", "I")

matrix = []

seen = set()
for char in key + "ABCDEFGHIKLMNOPQRSTUVWXYZ":

if char not in seen:

seen.add(char)

matrix.append(char)

return [matrix[i:i+5] for i in range(0, 25, 5)]

def find_position(matrix, char):

for i in range(5):

for j in range(5):

if matrix[i][j] == char:

return i, j

return None

def prepare_text(text):

text = text.upper().replace("J", "I")

prepared = ""

i=0

while i < len(text):

char1 = text[i]

char2 = text[i + 1] if i + 1 < len(text) else 'X'

if char1 == char2:

prepared += char1 + 'X'

i += 1

else:

prepared += char1 + char2

i += 2
if len(prepared) % 2 != 0:

prepared += 'X'

return prepared

def playfair_encrypt(text, key):

matrix = generate_playfair_matrix(key)

text = prepare_text(text)

encrypted = ""

for i in range(0, len(text), 2):

row1, col1 = find_position(matrix, text[i])

row2, col2 = find_position(matrix, text[i + 1])

if row1 == row2: # Same row

encrypted += matrix[row1][(col1 + 1) % 5]

encrypted += matrix[row2][(col2 + 1) % 5]

elif col1 == col2: # Same column

encrypted += matrix[(row1 + 1) % 5][col1]

encrypted += matrix[(row2 + 1) % 5][col2]

else: # Rectangle swap

encrypted += matrix[row1][col2]

encrypted += matrix[row2][col1]

return encrypted

def playfair_decrypt(text, key):

matrix = generate_playfair_matrix(key)

decrypted = ""

for i in range(0, len(text), 2):


row1, col1 = find_position(matrix, text[i])

row2, col2 = find_position(matrix, text[i + 1])

if row1 == row2: # Same row

decrypted += matrix[row1][(col1 - 1) % 5]

decrypted += matrix[row2][(col2 - 1) % 5]

elif col1 == col2: # Same column

decrypted += matrix[(row1 - 1) % 5][col1]

decrypted += matrix[(row2 - 1) % 5][col2]

else: # Rectangle swap

decrypted += matrix[row1][col2]

decrypted += matrix[row2][col1]

return decrypted

RSA

import random

def gcd(a, b):

while b != 0:

a, b = b, a % b

return a

def modinv(a, m):

m0, x0, x1 = m, 0, 1

if m == 1:

return 0

while a > 1:
q = a // m

m, a = a % m, m

x0, x1 = x1 - q * x0, x0

if x1 < 0:

x1 += m0

return x1

def is_prime(num):

if num < 2:

return False

for i in range(2, int(num ** 0.5) + 1):

if num % i == 0:

return False

return True

def generate_keypair(p, q):

if not (is_prime(p) and is_prime(q)):

raise ValueError("Both numbers must be prime.")

elif p == q:

raise ValueError("p and q cannot be the same")

n=p*q

phi = (p - 1) * (q - 1)

e = random.randrange(1, phi)

g = gcd(e, phi)
while g != 1:

e = random.randrange(1, phi)

g = gcd(e, phi)

d = modinv(e, phi)

return ((e, n), (d, n))

def encrypt(pk, plaintext):

key, n = pk

cipher = [(ord(char) ** key) % n for char in plaintext]

return cipher

def decrypt(pk, ciphertext):

key, n = pk

plain = [chr((char ** key) % n) for char in ciphertext]

return ''.join(plain)

if __name__ == '__main__':

p = 61

q = 53

public, private = generate_keypair(p, q)

print("Public key:", public)

print("Private key:", private)

message = input("Enter the message you want to encrypt: ")


encrypted_msg = encrypt(public, message)

print("Encrypted message:", encrypted_msg)

decrypted_msg = decrypt(private, encrypted_msg)

print("Decrypted message:", decrypted_msg)

dewie hellman

import random

def gen_keys(p, g):

a = random.randint(1, p - 1)

A = pow(g, a, p)

return a, A

def compute_sk(a, B, p):

return pow(B, a, p)

p = 23

g=5

a, A = gen_keys(p, g)

b, B = gen_keys(p, g)

shared_key_a = compute_sk(a, B, p)

shared_key_b = compute_sk(b, A, p)
print(shared_key_a == shared_key_b)

print("Shared key:", shared_key_a)

Elgamal

import random

def gcd(a, b):

while b != 0:

a, b = b, a % b

return a

def mod_exp(base, exp, mod):

result = 1

while exp > 0:

if exp % 2 == 1:

result = (result * base) % mod

base = (base * base) % mod

exp //= 2

return result

def generate_keys(p):

g = random.randint(2, p - 1)

x = random.randint(1, p - 2)

h = mod_exp(g, x, p)
return (p, g, h), x

def encrypt(public_key, plaintext):

p, g, h = public_key

y = random.randint(1, p - 2)

c1 = mod_exp(g, y, p)

c2 = (plaintext * mod_exp(h, y, p)) % p

return c1, c2

def decrypt(private_key, public_key, ciphertext):

p, g, h = public_key

c1, c2 = ciphertext

s = mod_exp(c1, private_key, p)

s_inv = pow(s, -1, p)

plaintext = (c2 * s_inv) % p

return plaintext

p = 467 # A large prime

public_key, private_key = generate_keys(p)

print("Public Key:", public_key)

print("Private Key:", private_key)

plaintext = 123

ciphertext = encrypt(public_key, plaintext)

print("Ciphertext:", ciphertext)
decrypted_message = decrypt(private_key, public_key, ciphertext)

print("Decrypted Message:", decrypted_message)

RSA question

def gcd(a, b):

while b:

a, b = b, a % b

return a

def modinv(e, phi):

d_old, d = 0, 1

r_old, r = phi, e

while r != 0:

q = r_old // r

r_old, r = r, r_old - q * r

d_old, d = d, d_old - q * d

return d_old % phi

def rsa_encrypt_decrypt(p, q, e, M):

n=p*q

phi = (p - 1) * (q - 1)

d = modinv(e, phi)

C = pow(M, e, n)

decrypted = pow(C, d, n)

return {

"n": n, "phi": phi, "e": e, "d": d,


"Encrypted (C)": C, "Decrypted (M)": decrypted

test_cases = [

(3, 7, 5, 10),

(5, 13, 5, 8),

(7, 17, 11, 11),

(7, 13, 11, 2),

(17, 23, 9, 7)

for i, (p, q, e, M) in enumerate(test_cases, start=1):

result = rsa_encrypt_decrypt(p, q, e, M)

print(f"\nCase {chr(96+i)}) p={p}, q={q}, e={e}, M={M}")

print(f" n = {result['n']}, phi = {result['phi']}, d = {result['d']}")

print(f" Encrypted (C) = {result['Encrypted (C)']}")

print(f" Decrypted (M) = {result['Decrypted (M)']}")

dewie hellman backup

def mod_exp(base, exp, mod):

result = 1

base = base % mod

while exp > 0:

if exp % 2 == 1:

result = (result * base) % mod

base = (base * base) % mod


exp //= 2

return result

# Input

alpha = int(input("Enter alpha (primitive root): "))

q = int(input("Enter prime number q: "))

xa = int(input("Enter private key of Alice (xa): "))

xb = int(input("Enter private key of Bob (xb): "))

# Public keys

ya = mod_exp(alpha, xa, q) # Alice's public key

yb = mod_exp(alpha, xb, q) # Bob's public key

# Secret keys

ka = mod_exp(yb, xa, q) # Secret key calculated by Alice

kb = mod_exp(ya, xb, q) # Secret key calculated by Bob

# Output

print("\n--- Diwie-Hellman Key Exchange ---")

print(f"Alpha = {alpha}")

print(f"q = {q}")

print(f"Private key of Alice = {xa}")

print(f"Public key of Alice = {ya}")

print(f"Private key of Bob = {xb}")

print(f"Public key of Bob = {yb}")

print(f"Secret key computed by Alice = {ka}")


print(f"Secret key computed by Bob = {kb}")

if ka == kb:

print("✅ Both Alice and Bob have the same secret key.")

print("🔐 Key shared securely.")

else:

print("❌ Key is not shared securely.")

SHA

print("Sample Result")

n = int(input("Give the number of bits for the message: "))

multiplier = 1

while multiplier * 1024 < (n + 128):

multiplier += 1

padding_size = (multiplier * 1024) - (n + 128)

print("\nOriginal message length (bits):", n)

print("The size of the padding bits is:", padding_size)

print("The total size of the blocks after including the padding bits is:", padding_size + n +
128)

# Create padding bits string: '1' followed by (padding_size - 1) zeros

paddingBitsString = '1' + '0' * (padding_size - 1)


print("The padding bits are as below, along with the number of bits (excluding the size of the
message {128}):")

print(paddingBitsString)

print("Size of padding bits:", len(paddingBitsString))

print("Total blocks required:", multiplier)

MD5

def itos(n):

return '0' if n == 0 else '1'

def dec_to_binary(n):

res = ""

count = 8

i=n

while i != 0 or count > 0:

if i == 0 and len(res) < 8:

res = res.rjust(8, '0')

return res

res = itos(i % 2) + res

i //= 2

count -= 1

return res

def main():

inp = input("Give the original message to check: ")


n = len(inp)

input_chain = []

padding_chain = []

print("1. Showing the original message in binary:")

for ch in inp:

temp = dec_to_binary(ord(ch))

print(temp, end=" ")

input_chain.append(temp)

total_message_bits = n * 8

print(f"\nThe total message bits size: {total_message_bits}")

i=1

while (512 * i) - 64 - total_message_bits < 0:

i += 1

x = (512 * i) - 64 - total_message_bits

print(f"\n2. The total number of padding bits is: {x}")

message_length = dec_to_binary(total_message_bits)

print("Message length in binary:", message_length)

# Padding: starts with '10000000' (i.e., 0x80) followed by required 0 blocks

padding_chain.append("10000000")

padding_blocks = x // 8

temp = padding_blocks - 1
while temp != 0:

padding_chain.append("00000000")

temp -= 1

print("The number of padding blocks is (without the message size block):",


padding_blocks)

print("3. The padding bits are:")

for b in padding_chain:

print(b, end=" ")

print(f"\nThe Message in bits are below (The size of the message is:
{total_message_bits}):")

for bit_block in input_chain:

print(bit_block, end=" ")

if __name__ == "__main__":

main()

AES KEY EXP

s_box = [

0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7,
0xAB,….

]
rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36]

def rot_word(word):

return word[1:] + word[:1]

def sub_word(word):

return [s_box[b] for b in word]

def key_expansion(key):

key_size = len(key)

assert key_size == 16

expanded = []

for i in range(0, 16, 4):

word = list(key[i:i+4])

expanded.append(word)

for i in range(4, 44):

temp = expanded[i - 1].copy()

if i % 4 == 0:

temp = rot_word(temp)

temp = sub_word(temp)

temp[0] ^= rcon[(i // 4) - 1]

new_word = [temp[j] ^ expanded[i - 4][j] for j in range(4)]

expanded.append(new_word)
return expanded

sample_key = bytes.fromhex("4A1A607DD64C444F6B2750E0975FE72E")

expanded_keys = key_expansion(sample_key)

round4_key = expanded_keys[16:20]

round4_key_bytes = bytes([byte for word in round4_key for byte in word])

print("Round4 Key (hex):", round4_key_bytes.hex().upper())

DES simulation

def permutation(input_block, table):

output = 0

for i, pos in enumerate(table):

bit = (input_block >> (64 - pos)) & 1

output |= bit << (64 - (i + 1))

return output

ip_table = [

58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,…

fp_table = [

40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23,…

input_hex = "0001002000000008".replace(" ", "")


input_block = int(input_hex, 16)

ip_result = permutation(input_block, ip_table)

fp_result = permutation(ip_result, fp_table)

print("Input block: " + format(input_block, '016X'))

print("After Initial Perm.: " + format(ip_result, '016X'))

print("After Final Perm.: " + format(fp_result, '016X'))

SHA da

def print_hex_vector(vec):

for i, val in enumerate(vec):

print(f"W{i} = {val:016X}")

def majority(a, b, c):

return (a & b) ^ (a & c) ^ (b & c)

def condition(e, f, g):

return (e & f) ^ (~e & g)

# === (1) User input message ===

message = input("Enter the plaintext message: ")

msg_bytes = message.encode("utf-8")

original_bit_length = len(msg_bytes) * 8
# === (a) Padding bits calculation ===

padding_bits = (1024 - (original_bit_length + 1 + 128) % 1024) % 1024

print(f"\n(a) Padding bits: {padding_bits}")

# === (b) Generate message schedule (W0 to W17) ===

W = [0] * 80

for i in range(len(msg_bytes)):

W[i // 8] |= msg_bytes[i] << ((7 - (i % 8)) * 8)

# Append 1 bit (0x80)

W[len(msg_bytes) // 8] |= 0x80 << ((7 - (len(msg_bytes) % 8)) * 8)

# Append original length to W[15]

W[15] = original_bit_length

# Extend W[16] to W[17]

for i in range(16, 18):

W[i] = W[i - 16] + W[i - 7]

print("\n(b) First 18 words (W0 - W17) in hex:")

print_hex_vector(W[:18])

# === (c) Majority function ===

A = 0x6a09e667f3bcc908

B = 0xbb67ae8584caa73b

C = 0x3c6ef372fe94f82b
majority_result = majority(A, B, C)

print(f"\n(c) Majority function result: {majority_result:016X}")

# === (d) Condition function ===

E = 0x510e527fade682d1

F = 0x9b05688c2b3e6c1f

G = 0x1f83d9abfb41bd6b

condition_result = condition(E, F, G)

print(f"(d) Condition function result: {condition_result:016X}")

Absolutely! Here's a brief algorithmic description for each of the provided code snippets:

1. Caesar Cipher:

• Input: Plaintext string, shift key (integer).


• Process:
o Iterate through each character of the plaintext.
o If the character is alphabetic:
§ Convert the character to its corresponding numerical value (A=0,
B=1, etc.).
§ Add the shift key to the numerical value.
§ Apply modulo 26 to wrap around the alphabet.
§ Convert the resulting numerical value back to a character.
o If the character is not alphabetic, leave it unchanged.
• Output: Ciphertext string.

2. Hill Cipher:

• Input: Plaintext string, key matrix (numpy array).


• Process:
o Pad the plaintext with 'X' characters to make its length a multiple of the
key matrix size.
o Convert the plaintext to numerical values (A=0, B=1, etc.).
o Divide the numerical plaintext into blocks of size equal to the key matrix
size.
o For each block:
§ Multiply the key matrix by the block (vector multiplication).
§ Apply modulo 26 to the result.
o Convert the resulting numerical values back to characters.
• Output: Ciphertext string.
• Decryption:
o Calculate the inverse of the Key Matrix.
o Perform the encryption steps in reverse.

3. Vigenère Cipher:

• Input: Plaintext string, key string.


• Process:
o Extend the key to match the plaintext length (repeating the key).
o Convert both plaintext and extended key to numerical values (A=0, B=1,
etc.).
o For each character:
§ Add the plaintext numerical value to the corresponding key
numerical value.
§ Apply modulo 26 to the result.
§ Convert the resulting numerical value back to a character.
o Non alphabetic characters are not changed.
• Output: Ciphertext string.

4. Playfair Cipher:

• Input: Plaintext string, key string.


• Process:
o Generate a 5x5 key matrix from the key (replacing 'J' with 'I').
o Prepare the plaintext:
§ Replace 'J' with 'I'.
§ Insert 'X' between repeated letters.
§ Pad with 'X' if the plaintext length is odd.
o Divide the plaintext into pairs of characters.
o For each pair:
§ Find the positions of the characters in the key matrix.
§ Apply the Playfair rules (same row, same column, rectangle) to get
the ciphertext pair.
o Convert the ciphertext pairs back to a string.
• Output: Ciphertext string.
• Decryption:
o Reverse the encryption steps.

5. RSA:

• Input: Two prime numbers (p, q), plaintext message.


• Process:
o Generate public and private keys:
§ n=p*q
§ phi = (p-1) * (q-1)
§ Choose public exponent 'e' (relatively prime to phi).
§ Calculate private exponent 'd' (modular inverse of 'e' mod phi).
o Encryption:
§ Convert plaintext characters to numerical values.
§ Ciphertext = (plaintext ^ e) mod n.
o Decryption:
§ Plaintext = (ciphertext ^ d) mod n.
• Output: Ciphertext (numerical list), decrypted plaintext.

6. Diffie-Hellman:

• Input: Prime number (p), generator (g), private keys (a, b).
• Process:
o Calculate public keys:
§ A = g^a mod p
§ B = g^b mod p
o Calculate shared secret keys:
§ ka = B^a mod p
§ kb = A^b mod p
• Output: Shared secret key.

7. ElGamal:

• Input: Prime number (p), plaintext message.


• Process:
o Key generation:
§ Generate a generator g.
§ Generate a private key x.
§ Generate a public key h = g^x mod p.
o Encryption:
§ Generate a random y.
§ c1 = g^y mod p.
§ c2 = plaintext * h^y mod p.
o Decryption:
§ s = c1^x mod p.
§ plaintext = c2 * s^-1 mod p.
• Output: Ciphertext (c1, c2), decrypted plaintext.

8. RSA Question (Encryption/Decryption Function):

• Input: Two prime numbers (p, q), public exponent (e), message (M).
• Process:
o Calculate n = p * q and phi = (p-1) * (q-1).
oCalculate private exponent d (modular inverse of e mod phi).
oEncryption: C = M^e mod n.
oDecryption: M = C^d mod n.
• Output: n, phi, d, encrypted message (C), decrypted message (M).

9. Diffie-Hellman Backup:

• Input: primitive root alpha, prime number q, private keys xa and xb.
• Process:
o calculate public keys ya and yb.
o calculate shared key ka and kb.
• Output: public keys, and shared secret key.

10. SHA:

• Input: Message (string).


• Process:
o Calculate padding bits needed.
o Append the padding bits to the message.
o Append the original message lenght in bits.
o Show the result.
• Output: padded message information.

11. MD5:

• Input: Message string.


• Process:
o Convert message to binary.
o Calculate the number of padding bits.
o Append the padding bits.
o Append message length in bits.
• Output: padded message information.

12. AES Key Expansion:

• Input: 16-byte key.


• Process:
o Expand the key into a 44-word array.
o Use S-box, Rcon, and rotation operations.
• Output: Expanded key array.

13. DES Simulation:

• Input: 64-bit input block.


• Process:
o Apply initial permutation (IP).
o Apply final permutation (FP).
• Output: Permuted blocks.

14. SHA da:

• Input: Message string.


• Process:
o Calculate padding bits.
o Create message schedule (W array).
o Perform majority and condition operations.
• Output: intermediate hash values.

You might also like