0% found this document useful (0 votes)
34 views20 pages

Muhd Faizun Nazim Bin MD Fauzan - NWS21070675

Uploaded by

Faizun Nazim
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)
34 views20 pages

Muhd Faizun Nazim Bin MD Fauzan - NWS21070675

Uploaded by

Faizun Nazim
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/ 20

GMI German-Malaysian Institute

DIPLOMA PROGRAMME

LAB WORKS 20%


Academic Period: July 2023

Program : NETWORK SECURITY


Course : CRYPTOGRAPHY
Code : CBS 2373
Duration : 3 HOURS FOR EACH LAB WORK
Total Marks :

GENERAL INSTRUCTIONS:

1. Write down clearly (with capital letters) your name, trade, group and the date
of examination at the bottom of this page.
2. Do not open this question booklet until you are told to do so by the invigilator.
3. Read the specific instructions and questions carefully before answering.

Student’s Name : MUHAMMAD FAIZUN NAZIM BIN MD FAUZAN


Student’s I/D No. : NWS21070675
Semester/Trade/Group : DNWS2 SEM5
Date : 10/11/2023
CBS 2373 CRYPTOGRAPHY

Level
CL Full
No Assessment Criteria PO of Score Marks Comment
O Marks
Diff
1. Lab work #1 0 0
Install Python
2 Lab work #2 2 4 P3 15
Create a Python program to apply
substitution technique.
3. Lab work #3 2 4 P3 15
Create a Python program to apply
transposition technique.
4. Lab work #4 2 4 P3 15
Create a Python program to apply
Hash algorithm technique.
Lab work #5
Create a Python program to apply 2 4
5 P3 15
Public Key encryption algorithm
technique.
Lab work #6
6 Create a Python program to apply 2 4 P3 15
cryptographic protocol.
Total 75
Total Marks /75
Total PO 4 /75

Signature

Page 2 of 20
Copyright of German-Malaysian Institute. All rights reserved.
SCHEME – each lab work given

APPROACHES MEETS
NO. CRITERIA EXCELLENT [3] MARKS MARKS MARKS MARKS MARKS MARKS
EXPECTATIONS [1] EXPECTATIONS [2]
LAB 1 LAB 2 LAB 3 LAB 4 LAB 5 LAB 6

LAB WORKS

Functional
Able to setup the functional
program: Able to setup the
1 Unable to setup the programming without major
Able to construct the functional programming
functional programming. assistance.
python language with little assistance.
toward cryptography

Discover encryption
technique: Able to discover the
Unable to discover the
2 Able to discover the Able to discover the cryptography techniques,
cryptography techniques,
classical and modern cryptography techniques analyse the strength of
and analyze the strength
encryption technique with little assistance. encryption without major
of encryption technique.
assistance.

Demonstrate:
Able to demonstrate Able to demonstrate the
Unable to demonstrate the Able to demonstrate the various
the various encryption various cipher algorithm
3 various cipher algorithm in algorithm without major
techniques. in difference scenarios
difference scenarios. assistance.
with little assistance.

Interpretation:
Unable to interpret most of Able to interpret all the findings
4 Able to Interpret Able to interpret most of
the findings and result. and result clearly and
findings. the findings and result.
comprehensively.

Only restatement of the


instruction without
Knowledge:
commenting on the
Able to apply Shows a little
5 expected key point. Shows a full understanding of
knowledge toward understanding of what
Incorrect what the practical was about.
cryptography the practical was about.
judgment/arguments are
used.

TOTAL
ANSWER, OUTPUT AND ELABORATE THE FINDINGS

You are required to follow the step given:

Step 1: Take the photo your laptop at every time to start creating a Python program

Step 2: Screen capture the OUTPUT PROGRAM and result at every lab works given.

Step 3: Submit the lab sheet in PDF format and rename the file with your FULL NAME and
STUDENT ID.

Lab work #1
Install Python

Software installation:
https://www.python.org/downloads/

STEPS SCREEN SHOT THE PHOTO


Visual Studio Code Software installation: https://code.visualstudio.com/download
Software

Python Extension
inside VS Code

Select Python
language
CBS 2373 CRYPTOGRAPHY

Lab work #2
Create a Python program to apply substitution technique.

Laptop photo including python program:

Page 5 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

ENCRYPTION TECHNIQUE NAME PYTHON PROGRAM OUTPUT PROGRAM / ELABORATE THE


FINDINGS
import tkinter as tk
Caesar Cipher
def caesar_cipher(text, shift):
result = ""
for char in text:
if char.isalpha():
shift_amount = shift % 26
if char.islower():
result += chr(((ord(char) -
ord('a') + shift_amount) % 26) +
ord('a'))
else:
result += chr(((ord(char) -
ord('A') + shift_amount) % 26) +
ord('A'))
else:
result += char 1. Import tkinter Library: The program
return result imports the tkinter library, which is
used to create the GUI.
def encrypt():
text = entry_text.get() 2. Caesar Cipher Function
shift = int(entry_shift.get()) (caesar_cipher):
encrypted_text =
caesar_cipher(text, shift) This function takes a text and a shift
result_label.config(text="Encrypted value as input.
Text: " + encrypted_text) It shifts the letters in the text forward
or backward in the alphabet based on
def decrypt(): the shift value.
text = entry_text.get()
shift = int(entry_shift.get()) 3. Encrypt and Decrypt Functions
decrypted_text = (encrypt and decrypt):
caesar_cipher(text, -shift)
result_label.config(text="Decrypted These functions are called when you
Text: " + decrypted_text) click the "Encrypt" and "Decrypt"
buttons in the GUI.
# Create the main window They get the text from the input field
window = tk.Tk() and the shift value entered by the user.
window.title("Caesar Cipher")
The result is displayed in the GUI.
# Create and configure widgets
text_label = tk.Label(window, 4. Create the Main Window:
text="Enter Text:")
entry_text = tk.Entry(window) It initializes the main GUI window and
sets its title to "Caesar Cipher."
shift_label = tk.Label(window,
text="Enter Shift:") 5. Create and Configure Widgets:
entry_shift = tk.Entry(window)
Labels, input fields, buttons, and a
encrypt_button = tk.Button(window, result label are created and configured
text="Encrypt", command=encrypt) for the GUI.
decrypt_button = tk.Button(window,
text="Decrypt", command=decrypt) 6. Arrange Widgets on the Window:

result_label = tk.Label(window, The widgets are placed in a specific


text="Result:") order on the GUI window using the
pack method.
# Arrange widgets on the window
text_label.pack() 7. Start the GUI Main Loop:
entry_text.pack()
shift_label.pack() It enters the main event loop, allowing
entry_shift.pack() the user to interact with the GUI.
encrypt_button.pack()
decrypt_button.pack()
result_label.pack()

# Start the GUI main loop


window.mainloop()

Page 6 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

import tkinter as tk
Vigenere Cipher
def vigenere_cipher(text, key, mode):
result = ""
key_len = len(key)

for i, char in enumerate(text):


if char.isalpha():
key_char = key[i % key_len]
ascii_offset = ord('A') if
char.isupper() else ord('a')
key_offset = ord('A') if
key_char.isupper() else ord('a')
shift = ord(key_char) -
key_offset
When you run this program, you'll see
if mode == "encrypt": a GUI where you can enter the text
shifted_char = you want to encrypt or decrypt, and
chr((ord(char) - ascii_offset + shift) % the Vigenère key. Clicking the
26 + ascii_offset) "Encrypt" button will encrypt the text,
else: # Decryption and clicking the "Decrypt" button will
shifted_char = decrypt it. The result is displayed in
chr((ord(char) - ascii_offset - shift) % the result label below the buttons. The
26 + ascii_offset) program ensures that the Vigenère
result += shifted_char Cipher is applied correctly based on
else: the provided key and the selected
result += char mode (encryption or decryption).
return result

def encrypt():
plaintext = entry_text.get()
key = entry_key.get()
ciphertext =
vigenere_cipher(plaintext, key,
"encrypt")
result_label.config(text="Encrypted
Text: " + ciphertext)

def decrypt():
ciphertext = entry_text.get()
key = entry_key.get()
plaintext =
vigenere_cipher(ciphertext, key,
"decrypt")
result_label.config(text="Decrypted
Text: " + plaintext)

# Create the main window


window = tk.Tk()
window.title("Vigenère Cipher")

# Create and configure widgets


text_label = tk.Label(window,
text="Enter Text:")
entry_text = tk.Entry(window)

key_label = tk.Label(window,
text="Enter Key:")
entry_key = tk.Entry(window)

encrypt_button = tk.Button(window,
text="Encrypt", command=encrypt)
decrypt_button = tk.Button(window,
text="Decrypt", command=decrypt)

result_label = tk.Label(window,
text="Result:")

# Arrange widgets on the window


text_label.pack()
entry_text.pack()

Page 7 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

key_label.pack()
entry_key.pack()
encrypt_button.pack()
decrypt_button.pack()
result_label.pack()

# Start the GUI main loop


window.mainloop()

Page 8 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

Lab work #3
Create a Python program to apply transposition technique.

Laptop photo including python program:

Page 9 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

ENCRYPTION TECHNIQUE NAME PYTHON PROGRAM OUTPUT PROGRAM / ELABORATE THE


FINDINGS
import tkinter as tk
Rail Fence
def encrypt_rail_fence(plain_text,
rails):
fence = [[' ' for _ in
range(len(plain_text))] for _ in
range(rails)]
direction = -1
row, col = 0, 0

for char in plain_text:


fence[row][col] = char Here's a simplified explanation of how
if row == 0 or row == rails - 1: it works:
direction *= -1
row += direction Library Import: The program starts by
col += 1 importing the tkinter library for
creating the graphical user interface
cipher_text = '' (GUI). It also defines two functions for
for row in fence: encryption and decryption.
for char in row:
if char != ' ': Encryption Function: The
cipher_text += char encrypt_rail_fence function takes the
input plaintext and the number of rails
return cipher_text as parameters. It creates a "fence" of
empty spaces where it arranges the
def decrypt_rail_fence(cipher_text, characters in a zigzag pattern. This
rails): arrangement forms the ciphertext.
fence = [[' ' for _ in
range(len(cipher_text))] for _ in Decryption Function: The
range(rails)] decrypt_rail_fence function is
direction = -1 responsible for reversing the
row, col = 0, 0 encryption process. It takes the
ciphertext and the number of rails as
for _ in range(len(cipher_text)): input, then constructs the "fence" with
fence[row][col] = '*' asterisks (*) as placeholders. The
if row == 0 or row == rails - 1: characters are placed in the fence to
direction *= -1 reveal the original plaintext.
row += direction
col += 1 GUI Creation: The program creates a
graphical user interface (GUI) using
idx = 0 tkinter. It includes labels, text entry
for i in range(rails): fields, buttons for encryption and
for j in range(len(cipher_text)): decryption, and a label to display the
if fence[i][j] == '*' and idx < result.
len(cipher_text):
fence[i][j] = Encryption and Decryption Buttons:
cipher_text[idx] Users can interact with the GUI by
idx += 1 entering text into the input field and
specifying the number of rails (rows).
direction = -1 Clicking the "Encrypt" button triggers
row, col = 0, 0 the encryption function, while clicking
plain_text = '' the "Decrypt" button triggers the
decryption function. The result of the
for _ in range(len(cipher_text)): operation is displayed in the GUI.
plain_text += fence[row][col]
if row == 0 or row == rails - 1: The program provides a user-friendly
direction *= -1 way to encrypt and decrypt messages
row += direction using the Rail Fence Transposition
col += 1 Cipher by simply entering the text and
the number of rails, and then clicking
return plain_text the appropriate button.

def encrypt():
plain_text = entry_text.get()
rails = int(entry_rails.get())
cipher_text =
encrypt_rail_fence(plain_text, rails)

Page 10 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

result_label.config(text="Encrypted
Text: " + cipher_text)

def decrypt():
cipher_text = entry_text.get()
rails = int(entry_rails.get())
plain_text =
decrypt_rail_fence(cipher_text, rails)
result_label.config(text="Decrypted
Text: " + plain_text)

# Create the main window


window = tk.Tk()
window.title("Rail Fence Transposition
Cipher")

# Create and configure widgets


text_label = tk.Label(window,
text="Enter Text:")
entry_text = tk.Entry(window)

rails_label = tk.Label(window,
text="Number of Rails:")
entry_rails = tk.Entry(window)

encrypt_button = tk.Button(window,
text="Encrypt", command=encrypt)
decrypt_button = tk.Button(window,
text="Decrypt", command=decrypt)

result_label = tk.Label(window,
text="Result:")

# Arrange widgets on the window


text_label.pack()
entry_text.pack()
rails_label.pack()
entry_rails.pack()
encrypt_button.pack()
decrypt_button.pack()
result_label.pack()

# Start the GUI main loop


window.mainloop()

Page 11 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

Lab work #4
Create a Python program to apply Hash algorithm technique.

Laptop photo including python program:

Page 12 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

ENCRYPTION TECHNIQUE NAME PYTHON PROGRAM OUTPUT PROGRAM / ELABORATE THE


FINDINGS
import tkinter as tk
MD5 Techniques import hashlib

def calculate_md5():
input_text = entry_text.get()
md5_hash = 1. Imports:
hashlib.md5(input_text.encode()).hexd
igest() tkinter library is imported to create the
result_label.config(text="MD5 Hash: graphical user interface (GUI).
" + md5_hash)
2. Function calculate_md5:
# Create the main window
window = tk.Tk() This function is invoked when the
window.title("MD5 Hash Generator") "Calculate MD5" button is pressed.
It retrieves the text entered in the
# Create and configure widgets input field.
text_label = tk.Label(window, It generates the MD5 hash of the input
text="Enter Text:") text using hashlib.md5 and encodes
entry_text = tk.Entry(window) the text before hashing using
.encode().
calculate_button = tk.Button(window,
text="Calculate MD5", 3. Main Window Creation:
command=calculate_md5)
A window is created using tkinter.Tk().
result_label = tk.Label(window, The window's title is set to "MD5 Hash
text="MD5 Hash:") Generator".

# Arrange widgets on the window 4. Widgets:


text_label.pack()
entry_text.pack() Labels (text_label and result_label)
calculate_button.pack() display text.
result_label.pack() entry_text is an input field where the
user can type the text they want to
# Start the GUI main loop hash.
window.mainloop() calculate_button triggers the
calculate_md5 function when pressed.

5. Widget Placement:

pack() is used to place the widgets


within the window, arranging them in a
vertical layout.

6. GUI Main Loop:

window.mainloop() starts the GUI,


allowing user interaction.

Page 13 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

Lab work #5
Create a Python program to apply Public Key encryption algorithm technique.

Laptop photo including python program:

Page 14 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

ENCRYPTION TECHNIQUE NAME PYTHON PROGRAM OUTPUT PROGRAM / ELABORATE THE


FINDINGS
import random
RSA (Rivest-Shamir-Adleman) import math

# A set will be the collection of prime


numbers,
# where we can select random primes
p and q
prime = set()
The provided Python code implements
public_key = None the RSA (Rivest-Shamir-Adleman)
private_key = None encryption and decryption process:
n = None
1. Prime Number Generation: The code
# We will run the function only once to starts by generating a set of prime
fill the set of numbers using the Sieve of
# prime numbers Eratosthenes. These primes will be
def primefiller(): used to create the RSA key pairs.
# Method used to fill the primes set
is Sieve of 2. Key Pair Generation: Two prime
# Eratosthenes (a method to collect numbers, p and q, are selected
prime numbers) randomly from the generated prime
seive = [True] * 250 set. The code then calculates the
seive[0] = False modulus n = p * q and Euler's totient
seive[1] = False function ϕ(n) for these primes.
for i in range(2, 250):
for j in range(i * 2, 250, i): 3. Public and Private Keys: The code
seive[j] = False then determines a public key (e) and
private key (d) pair. e is chosen as the
# Filling the prime numbers smallest positive integer that is
for i in range(len(seive)): coprime to ϕ(n), and d is calculated as
if seive[i]: the modular multiplicative inverse of e
prime.add(i) with respect to ϕ(n).

# Picking a random prime number and 4. Encryption: To encrypt a message,


erasing that prime each character in the input message is
# number from list because p!=q converted to its ASCII value. The
def pickrandomprime(): encryption function is applied to each
global prime character, which results in a list of
k = random.randint(0, len(prime) - encrypted numbers.
1)
it = iter(prime) 5. Decryption: The decryption function
for _ in range(k): reverses the encryption process. It
next(it) applies the private key to each
encrypted number to recover the
ret = next(it) original ASCII values.
prime.remove(ret)
return ret 6. Final Output: The code showcases
the entire process by encrypting and
def setkeys(): decrypting a sample message and
global public_key, private_key, n displaying the original message, the
prime1 = pickrandomprime() # First encrypted message (numbers), and
prime number the decrypted message.
prime2 = pickrandomprime() #
Second prime number

n = prime1 * prime2
fi = (prime1 - 1) * (prime2 - 1)

e=2
while True:
if math.gcd(e, fi) == 1:
break
e += 1

# d = (k*Φ(n) + 1) / e for some


integer k
public_key = e

Page 15 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

d=2
while True:
if (d * e) % fi == 1:
break
d += 1

private_key = d

# To encrypt the given number


def encrypt(message):
global public_key, n
e = public_key
encrypted_text = 1
while e > 0:
encrypted_text *= message
encrypted_text %= n
e -= 1
return encrypted_text

# To decrypt the given number


def decrypt(encrypted_text):
global private_key, n
d = private_key
decrypted = 1
while d > 0:
decrypted *= encrypted_text
decrypted %= n
d -= 1
return decrypted

# First converting each character to its


ASCII value and
# then encoding it then decoding the
number to get the
# ASCII and converting it to character
def encoder(message):
encoded = []
# Calling the encrypting function in
the encoding function
for letter in message:

encoded.append(encrypt(ord(letter)))
return encoded

def decoder(encoded):
s = ''
# Calling the decrypting function in
the decoding function
for num in encoded:
s += chr(decrypt(num))
return s

if __name__ == '__main__':
primefiller()
setkeys()
message = "Test Message"
# Uncomment below for manual
input
# message = input("Enter the
message\n")
# Calling the encoding function
coded = encoder(message)

print("Initial message:")
print(message)
print("\n\nThe encoded
message(encrypted by public key)\n")
print(''.join(str(p) for p in coded))
print("\n\nThe decoded
message(decrypted by public key)\n")

Page 16 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

print(''.join(str(p) for p in
decoder(coded)))

import tkinter as tk
DSA (Digital Signature Algorithm) import hashlib
import random

def generate_dsa_keys():
global p, q, g, x, y
p = 809
q = 13
g=6

x = random.randint(1, q - 1)
y = (g ** x) % p
public_key_text.delete(1.0, tk.END)
public_key_text.insert(tk.END, f"p:
{p}\nq: {q}\ng: {g}\ny: {y}")

def sign_message():
global r, s
message = message_text.get(1.0,
tk.END).strip()
k = random.randint(1, q - 1)
r = (g ** k % p) % q Here's an example based on the
h= provided code:
int(hashlib.sha1(message.encode()).he
xdigest(), 16) Click "Generate DSA Keys" to generate
s = (k ** -1 * (h + x * r)) % q DSA keys. The "Public Key" text field
signature_text.delete(1.0, tk.END) shows the values of p, q, g, and y.
signature_text.insert(tk.END, f"r:
{r}\ns: {s}") In the "Message" text field, enter a
message (e.g., "Hello, world!").
def verify_signature():
message = message_text.get(1.0, Click "Sign Message." The "Signature"
tk.END).strip() text field shows the calculated r and s
h= values.
int(hashlib.sha1(message.encode()).he
xdigest(), 16) Click "Verify Signature." If the
w = s ** -1 % q signature is valid, the "Verification
u1 = (h * w) % q Result" label will display "Signature is
u2 = (r * w) % q valid."
v = ((g ** u1 * y ** u2) % p) % q
The validity of the signature depends
if v == r: on the correctness of the key pair
generation, message signing, and
verification_result.config(text="Signatu verification processes. In practice,
re is valid.") these processes are much more
else: complex and involve secure key
management. This code is a simplified
verification_result.config(text="Signatu demonstration and should not be used
re is not valid.") for real cryptographic security.

window = tk.Tk()
window.title("DSA Signature
Generation and Verification")

generate_keys_button =
tk.Button(window, text="Generate DSA
Keys", command=generate_dsa_keys)
generate_keys_button.pack()

public_key_text = tk.Text(window,
height=6, width=40)
public_key_text.pack()

message_text = tk.Text(window,
height=6, width=40)
message_text.pack()

Page 17 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

sign_button = tk.Button(window,
text="Sign Message",
command=sign_message)
sign_button.pack()

signature_text = tk.Text(window,
height=6, width=40)
signature_text.pack()

verify_button = tk.Button(window,
text="Verify Signature",
command=verify_signature)
verify_button.pack()

verification_result = tk.Label(window,
text="")
verification_result.pack()

window.mainloop()

Page 18 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

Lab work #6
Create a Python program to apply cryptographic protocol.

Laptop photo including python program:

Page 19 of 20
Copyright of German-Malaysian Institute. All rights reserved.
CBS 2373 CRYPTOGRAPHY

ENCRYPTION TECHNIQUE NAME PYTHON PROGRAM OUTPUT PROGRAM / ELABORATE THE


FINDINGS
from cryptography.fernet import Fernet Output:

AES Algorithm # Generate a key and create a cipher Encrypted message:


object b'gAAAAABlT3daIB7b6rXvIaZljh9NgGY
key = Fernet.generate_key() A39HrqPq81AhmAsNeXBI4Ng9cs4CIIc
cipher_suite = Fernet(key) GqRmOftfvlhZ6ZbOXz2ufzMHOQSmg93
-5sCw=='
# Encrypt a message
message = b"Hello, World!" Decrypted message: b'Hello, World!'
encrypted_message =
cipher_suite.encrypt(message)
print(f"Encrypted message: Elaborate:
{encrypted_message}")
1. Import Fernet from
# Decrypt the message cryptography.fernet:
decrypted_message =
cipher_suite.decrypt(encrypted_messa The code imports a tool called Fernet
ge) from the cryptography library. Fernet is
print(f"Decrypted message: a technique for encrypting and
{decrypted_message}") decrypting messages using a secret
key.

2. Generate a Key:

It creates a random secret key that will


be used for both encrypting and
decrypting messages. The key is
stored in a variable named key.

3. Create a Cipher Suite:

A "cipher suite" is like a set of tools for


encrypting and decrypting messages.
It is created using the secret key,
making it possible to lock and unlock
messages with that key.

3. Encrypt a Message:

The code defines a message (in this


case, "Hello, World!"). It uses the
secret key and the cipher suite to turn
the message into a secret code. This
secret code is called the "encrypted
message."

4. Print the Encrypted Message:

It shows the secret code, which is the


encrypted message, so you can see
what it looks like.

5. Decrypt the Message.

Page 20 of 20
Copyright of German-Malaysian Institute. All rights reserved.

You might also like