0% found this document useful (0 votes)
5 views18 pages

Cryptography Algorithms Overview

The document outlines various encryption algorithms including Caesar cipher, Vigenere cipher, transposition cipher, One Time Pad (OTP), RC4, A5/1, DES, and AES. Each algorithm is accompanied by Python code demonstrating its encryption and decryption processes. The document is structured by weeks, with each week focusing on a different cipher and its implementation.

Uploaded by

mahermostafa564
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)
5 views18 pages

Cryptography Algorithms Overview

The document outlines various encryption algorithms including Caesar cipher, Vigenere cipher, transposition cipher, One Time Pad (OTP), RC4, A5/1, DES, and AES. Each algorithm is accompanied by Python code demonstrating its encryption and decryption processes. The document is structured by weeks, with each week focusing on a different cipher and its implementation.

Uploaded by

mahermostafa564
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

Week 1:

Ceaser cipher:
def caeser_encrypt_decrypt(text,shift):
result=""
for ch in text:
if [Link]():
base=ord('A') if [Link]() else ord('a')
result+=chr(base+((ord(ch)-base+shift+26)%26))
else:
result+=ch
return result

shift=3
text="Ramy"
ciphertext=caeser_encrypt_decrypt(text,shift)
print("ciphertext:",ciphertext)
plaintext=caeser_encrypt_decrypt(ciphertext,shift)

print("plaintext:",plaintext)

vigenere cipher:
def vig_encrypt(plain_text,key):
cipher_text=""
for i,ch in enumerate(plain_text):
if [Link]():
key_ind=(i%len(key))
baseK=ord('A') if key[key_ind].isupper() else ord('a')
shift_val=ord(key[key_ind])-baseK
base=ord('A') if [Link]() else ord('a')
cipher_text+=chr(base+((ord(ch)-base+shift_val+26)%26))
else:
cipher_text+=ch
return cipher_text

def vig_decrypt(cipher_text,key):
plain_text=""
for i,ch in enumerate(cipher_text):
if [Link]():
key_ind=(i%len(key))
baseK=ord('A') if key[key_ind].isupper() else ord('a')
shift_val=ord(key[key_ind])-baseK
base=ord('A') if [Link]() else ord('a')
plain_text+=chr(base+((ord(ch)-base-shift_val+26)%26))
else:
plain_text+=ch
return plain_text

key="key"
text="Ramy & ,"
ciphertext=vig_encrypt(text,key)
print("ciphertext:",ciphertext)
plaintext=vig_decrypt(ciphertext,key)
print("plaintext:",plaintext)
Week 2:

Transposition cipher:

def douple_trans_encrypt(plaintext,rows,cols,perR,perC):
ciphertext=[]
for i in range(rows):
[Link]([])
for j in range(cols):
ciphertext[i].append('.')
for i in range(rows):
for j in range(cols):
ciphertext[i][j]=plaintext[perR[i]-1][perC[j]-1]

return ciphertext
def double_trans_decrypt(ciphertext,rows,cols,perR,perC):
plaintext=[]
for i in range(rows):
[Link]([])
for j in range(cols):
plaintext[i].append('.')
for i in range(rows):
for j in range(cols):
plaintext[perR[i]-1][perC[j]-1]=ciphertext[i][j]
return plaintext
rows,cols
perR=[3,2,1]
perC=[4,2,1,3]
plaintext=[['a','t','t','a'],['c','k','a','t'],['d','a','w','n']]
rows=len(plaintext)
cols=len(plaintext[0])
cipher=douple_trans_encrypt(plaintext,rows,cols,perR,perC)
print("cipher: ",cipher)
text=double_trans_decrypt(cipher,rows,cols,perR,perC)
print("text: ",text)
# text="attack at dawn"
# text=[Link](' ','')
def to_mat(text):
while len(text)!=rows*cols:
text+=' '
plaintext=[]
for i in range (rows):
[Link]([i for i in text[i*cols:(i+1)*cols]])
return plaintext
quiz.
Week 3:

One Time Pad(OTP) cipher:

import os
def generate_key(length):
return [Link](length)
def OTP_encrypt(plaintext):
text_pytes=[Link]('utf-8')
key=generate_key(len(text_pytes))
ciphertext=[p^k for p,k in zip(text_pytes,key)]
return ciphertext,key
def OTP_decrypt(ciphertext,key):
plaintext=[p^k for p,k in zip(ciphertext,key)]
return bytes(plaintext).decode()
plaintext="hello everyone"
ciphertext,key=OTP_encrypt(plaintext)
print(ciphertext)
print(OTP_decrypt(ciphertext,key))
RC4 cipher:

def RC4(text,key):
#KSA
S=list(range(256))
T=[]
for i in range(256):
[Link](key[i%len(key)])
for i in range(256):
j=(i+S[i]+T[i])%256
S[i],S[j]=S[j],S[i]
#PCGA
keystream=[]
j=i=0
for _ in range(len(text)):
i=(i+1)%256
j=(S[i]+j)%256
S[i],S[j]=S[j],S[i]
[Link]((S[i]+S[j])%256)
result=[i^j for i,j in zip(text,keystream)]
return bytes(result)

text="Ramy Monazaa TA"


key="Asdf"
text_bytes=[Link]()
key_bytes=[Link]()
ciphertext=RC4(text_bytes,key_bytes)
plaintext=RC4(ciphertext,key_bytes)
print("text:",text)
print("ciphertext:",ciphertext)
print("text:",[Link]())
assignment.
Week 4:

A5/1 cipher:

def encrypt(plaintext, key):


"""Encrypt plaintext using A5/1 stream cipher."""
# Convert plaintext to binary list
plaintext_bits = []
for c in plaintext:
bits=f"{ord(c):08b}"
plaintext_bits.extend(int(i) for i in bits)
# Initialize registers (R1: 19 bits, R2: 22 bits, R3: 23 bits)
R1=[int(i) for i in bin(key&0x7FFFF)[2:].zfill(19)]#first 19 bits
R2=[int(i) for i in bin((key>>19)&0x3FFFFF)[2:].zfill(22)]#next 22 bits
R3=[int(i) for i in bin((key>>41)&0x7FFFFF)[2:].zfill(23)]#last 23 bits
# Feedback taps for LFSR shifting
keystream = []

for i in range(len(plaintext_bits)):
# Majority clocking
majority = (R1[8]+R2[10]+R3[10])>=2
if R1[8] == majority:
newbit=R1[13]^R1[16]^R1[17]^R1[18]
R1=[newbit]+R1[:-1]
#x 0 1 2 3 4 5
if R2[10] == majority:
newbit=R2[20]^R2[21]
R2=[newbit]+R2[:-1]
if R3[10] == majority:
newbit=R3[7]^R3[20]^R3[21]^R3[22]
R3=[newbit]+R3[:-1]

# Keystream bit is XOR of last bits of R1, R2, and R3


[Link](R1[18] ^ R2[21] ^ R3[22])

# XOR plaintext with keystream to get ciphertext


# ciphertext = [p ^ k for p, k in zip(plaintext_bits, keystream)]
ciphertext =[]
for i,j in zip(plaintext_bits, keystream):
[Link](i ^ j)
ciphertext_chars = []
print(ciphertext)
for i in range(0, len(ciphertext), 8):
x=map(str,ciphertext[i:i+8])
x_int=int(''.join(x),2)
ciphertext_chars.append(chr(x_int))
return ''.join(ciphertext_chars) # Return as string

def decrypt(ciphertext, key):


"""Decrypt ciphertext using A5/1 (same as encryption)."""
return encrypt(ciphertext, key) # XORing twice cancels out encryption

import random
# Example Usage
key = [Link](64) # 64-bit key
plaintext = "HELLO"
ciphertext = encrypt(plaintext, key)
decrypted_text = decrypt(ciphertext, key)

print("Plaintext: ", plaintext)


print("Ciphertext:", ciphertext)
print("Decrypted: ", decrypted_text)
quiz.
Week 5:

DES cipher:

# Permutation tables (1-based indices)


IP = []

IP_INV = []

E = []

P = []

PC1 = []

PC2 = []

S_BOX = []
def bytes_to_bits(byte_data):
text_bits = []
for c in byte_data:
bits=f"{c:08b}"
text_bits.extend(int(i) for i in bits)
return text_bits

def bits_to_bytes(bits):
byte_data = bytearray()
for i in range(0, len(bits), 8):
byte = 0
for j in range(8):
byte = (byte << 1) | bits[i + j]
byte_data.append(byte)
return bytes(byte_data)
def permute(bits, table):
return [bits[i - 1] for i in table]
def generate_subkeys(key_bits):
# Apply PC1 permutation to get 56 bits
pc1 = permute(key_bits, PC1)
# Split into C0 and D0
C = pc1[:28]
D = pc1[28:]
subkeys = []
shift_schedule = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
for shift in shift_schedule:
# Left shift C and D
C = C[shift:] + C[:shift]
D = D[shift:] + D[:shift]
# Combine and apply PC2
combined = C + D
subkey = permute(combined, PC2)
[Link](subkey)
return subkeys
def feistel(right, subkey):
# Expand from 32 to 48 bits
expanded = permute(right, E)
# XOR with subkey
xor_result = [e ^ k for e, k in zip(expanded, subkey)]
# Apply S-boxes
sbox_output = []
for i in range(8):
chunk = xor_result[i*6 : (i+1)*6]
row = (chunk[0] << 1) | chunk[5]
col = (chunk[1] << 3) | (chunk[2] << 2) | (chunk[3] << 1) | chunk[4]
val = S_BOX[i][row][col]
sbox_output += [(val >> 3) & 1, (val >> 2) & 1, (val >> 1) & 1, val & 1]
# Permute with P
return permute(sbox_output, P)
def des_encrypt(plaintext, key):
plaintext_bits = bytes_to_bits(plaintext)
key_bits = bytes_to_bits(key)
subkeys = generate_subkeys(key_bits)
# Initial permutation
permuted = permute(plaintext_bits, IP)
left = permuted[:32]
right = permuted[32:]
# 16 rounds
for i in range(16):
new_left = [Link]()
feistel_output = feistel(right, subkeys[i])
new_right = [l ^ f for l, f in zip(left, feistel_output)]
left, right = new_left, new_right
# Combine and apply inverse IP
combined = right + left
ciphertext_bits = permute(combined, IP_INV)
return bits_to_bytes(ciphertext_bits)

def des_decrypt(ciphertext, key):


ciphertext_bits = bytes_to_bits(ciphertext)
key_bits = bytes_to_bits(key)
subkeys = generate_subkeys(key_bits)[::-1] # Reverse subkeys
# Initial permutation
permuted = permute(ciphertext_bits, IP)
left = permuted[:32]
right = permuted[32:]
# 16 rounds
for i in range(16):
new_left = [Link]()
feistel_output = feistel(right, subkeys[i])
new_right = [l ^ f for l, f in zip(left, feistel_output)]
left, right = new_left, new_right
# Combine and apply inverse IP
combined = right + left
plaintext_bits = permute(combined, IP_INV)
return bits_to_bytes(plaintext_bits)
import os
key=[Link](8)
base_text="ramy TA"
plaintext=(base_text.ljust(8,'\x00').encode())
plaintext=bytes(plaintext)
print(len(plaintext))
ciphertext = des_encrypt(plaintext, key)
print(f'Ciphertext: {[Link]().upper()}')

decrypted = des_decrypt(ciphertext, key)


decrypted=[Link]().upper()
original_text = [Link](decrypted).decode().rstrip('\x00')
print(f'Decrypted: {original_text}')
Week 6:

AES cipher:

S_BOX = []

# AES Inverse S-box (16x16 matrix)


INV_S_BOX = []
def key_expansion(key):
keys = [key]
for i in range(10):
new_key = [x ^ (i + 1) for x in keys[-1]] # keys[-1] last generated key
[Link](new_key)
return keys

def add_round_key(text, key):


return [[text[i][j] ^ key[i * 4 + j] for j in range(4)] for i in range(4)]

def sub_bytes(text):
return [[S_BOX[i >> 4][i & 0x0F] for i in row] for row in text]

def inv_sub_bytes(text):
"""Inverse SubBytes using AES inverse S-Box."""
return [[INV_S_BOX[i >> 4][i & 0x0F] for i in row] for row in text]

def shift_rows(text):
new_text = []
new_text.append(text[0])
[new_text.append(text[j][j:] + text[j][:j]) for j in range(1, 4)]
return new_text

def inv_shift_rows(text):
new_text = []
new_text.append(text[0])
[new_text.append(text[j][-j:] + text[j][:-j]) for j in range(1, 4)]
return new_text

def mix_columns(state):
"""AES MixColumns transformation on a 4x4 state matrix."""
return state

def inv_mix_columns(state):
return state

def AES_encrypt(plaintext, key):


expanded_keys = key_expansion(key)
state = list(plaintext)

state = add_round_key(state, expanded_keys[0])

for i in range(9):
state = sub_bytes(state)
state = shift_rows(state)
state = mix_columns(state)
state = add_round_key(state, expanded_keys[(i + 1)])

state = sub_bytes(state)
state = shift_rows(state)
state = add_round_key(state, expanded_keys[10])

return state

def AES_decrypt(ciphertext, key):


expanded_keys = key_expansion(key)
state = list(ciphertext)

state = add_round_key(state, expanded_keys[10])


state = inv_shift_rows(state)
state = inv_sub_bytes(state)

for i in range(9, 0, -1):


state = add_round_key(state, expanded_keys[i])
# state = inv_mix_columns(state)
state = inv_shift_rows(state)
state = inv_sub_bytes(state)

state = add_round_key(state, expanded_keys[0])

return state

# plaintext = [
# [0x32, 0x43, 0xf6, 0xa8],
# [0x88, 0x5a, 0x30, 0x8d],
# [0x31, 0x31, 0x98, 0xa2],
# [0xe0, 0x37, 0x07, 0x34]
# ]
base_text="ramy"
#convert to 4*4 byte list
plaintext=bytes(base_text.ljust(16,'\x00').encode())
#convert to 2D list
plaintext=[[i for i in plaintext[j*4:j*4+4]]for j in range(4)]

key = [
0x2b, 0x7e, 0x15, 0x16,
0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88,
0x09, 0xcf, 0x4f, 0x3c
]
print(key)
# Plaintext
print("plaintext:", plaintext)
# Encrypt
ciphertext = AES_encrypt(plaintext, key)
print("Encrypted:", ciphertext)

# Decrypt
decrypted = AES_decrypt(ciphertext, key)
decrypted_list=[]
for i in decrypted:
for j in i:
decrypted_list.append(j)
original_text = bytes(decrypted_list).decode().rstrip('\x00')
print("Decrypted:", original_text)
assignment.

Week 7:

Revision (fiestel, DES, AES).


Week 8:

RSA cipher:

def gcd(x, y):


while y != 0:
x, y = y, x % y
return x

# Function to find modular inverse of e modulo phi(n)


def mod_inv(e, phi):
for d in range(1, phi):
if (d * e) % phi == 1:
return d
return -1

# RSA Key Generation


def get_key():
p, q = 11, 19
N = p * q
phi = (p - 1) * (q - 1)
e = 1
for i in range(2, phi):
if gcd(phi, i) == 1:
e = i
break

# Compute d such that e * d ≡ 1 (mod phi(n)) ==> (e * d) % 7 ≡ 1


d = mod_inv(e, phi)
return N, e, d

def RSA(base, N, e):


result = 1
while e > 0:
if e % 2 == 1:
result *= base
result %= N
base *= base
base %= N
e = e // 2
return result
N, e, d = get_key()
print(f"Public Key (e, n): ({e}, {N})")
print(f"Private Key (d, n): ({d}, {N})")
M = 123
print(f"Original Message: {M}")
cipher = RSA(M, N, e)
print(f"Encrypted Message: {cipher}")
plain = RSA(cipher, N, d)
print(f"Decrypted Message: {plain}")
Week 9:

MD5 cipher:

import struct
import math

def left_rotate(x, c):


return (x << c | x >> (32 - c)) & 0xFFFFFFFF

# Constants for the algorithm (sine of integers in radians)


T = [int((1 << 32) * abs([Link](i + 1))) & 0xFFFFFFFF for i in range(64)]

# Initial values for A, B, C, D


A0 = 0x67452301
B0 = 0xefcdab89
C0 = 0x98badcfe
D0 = 0x10325476

# Per-round shift amounts


S = [7, 12, 17, 22] * 4 + \
[5, 9, 14, 20] * 4 + \
[4, 11, 16, 23] * 4 + \
[6, 10, 15, 21] * 4

# Functions for each round


def F(x, y, z): return (x & y) | (~x & z)
def G(x, y, z): return (x & z) | (y & ~z)
def H(x, y, z): return x ^ y ^ z
def I(x, y, z): return y ^ (x | ~z)

functions = [F, G, H, I]

def md5(message):
message = bytearray(message, 'utf-8')
original_length = (8 * len(message)) & 0xffffffffffffffff

# Padding
[Link](0x80)
while (len(message) * 8) % 512 != 448:
[Link](0)

message += [Link]('<Q', original_length)

# Process in 512-bit chunks


A, B, C, D = A0, B0, C0, D0

for chunk_index in range(0, len(message), 64):


chunk = message[chunk_index:chunk_index + 64]
M = list([Link]('<16I', chunk))

a, b, c, d = A, B, C, D

for i in range(64):
if i < 16:
f = F(b, c, d)
g = i
elif i < 32:
f = G(b, c, d)
g = (5 * i + 1) % 16
elif i < 48:
f = H(b, c, d)
g = (3 * i + 5) % 16
else:
f = I(b, c, d)
g = (7 * i) % 16

temp = (a + f + T[i] + M[g]) & 0xFFFFFFFF


temp = (b + left_rotate(temp, S[i])) & 0xFFFFFFFF
a, b, c, d = d, temp, b, c

A = (A + a) & 0xFFFFFFFF
B = (B + b) & 0xFFFFFFFF
C = (C + c) & 0xFFFFFFFF
D = (D + d) & 0xFFFFFFFF

# Return the final hash as hexadecimal


return ''.join([format(i, '02x') for i in [Link]('<4I', A, B, C, D)])

# Example usage
text = "hello"
print("MD5 Hash of 'hello':", md5(text))

quiz.

Week 10:

Revision.

You might also like