Thanks to visit codestin.com
Credit goes to www.scribd.com

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

CNS I

Lab manual of cryptography and network security

Uploaded by

Rushil Beladiya
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)
31 views30 pages

CNS I

Lab manual of cryptography and network security

Uploaded by

Rushil Beladiya
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

Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 1
AIM : Write a program to Implement Caesar cipher encryption-decryption.

Code:
def caesar_encrypt(plaintext, shift):
"""Encrypt the plaintext using Caesar cipher with the given shift."""
encrypted_text = ""
for char in plaintext:
# Encrypt only alphabetic characters
if char.isalpha():
# Shift the character within its case (upper or lower)
start = ord('A') if char.isupper() else ord('a')
encrypted_char = chr((ord(char) - start + shift) % 26 + start)
encrypted_text += encrypted_char
else:
# Non-alphabetic characters remain unchanged
encrypted_text += char
return encrypted_text

def caesar_decrypt(ciphertext, shift):


"""Decrypt the ciphertext using Caesar cipher with the given shift."""
decrypted_text = ""
for char in ciphertext:
# Decrypt only alphabetic characters
if char.isalpha():
# Shift the character within its case (upper or lower)
start = ord('A') if char.isupper() else ord('a')
decrypted_char = chr((ord(char) - start - shift) % 26 + start)
decrypted_text += decrypted_char
else:
# Non-alphabetic characters remain unchanged
decrypted_text += char
return decrypted_text

# Main function to demonstrate encryption and decryption


if __name__ == "__main__":
# Get user input for plaintext and shift value
text = input("Enter the text: ")
shift = int(input("Enter the shift value: "))

BAIT,SURAT Page 1
Cryptography and Network Security [1010207711] [2107020701005]

# Perform encryption
encrypted_text = caesar_encrypt(text, shift)
print(f"Encrypted Text: {encrypted_text}")

# Perform decryption
decrypted_text = caesar_decrypt(encrypted_text, shift)
print(f"Decrypted Text: {decrypted_text}")

Output:

BAIT,SURAT Page 2
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 2
AIM : Write a program to Implement Monoalphabetic cipher encryption-
decryption.

Code :
import string

# Function to create a cipher key based on a fixed substitution


def create_cipher_key():
"""Creates a fixed monoalphabetic cipher key (a shuffled alphabet)"""
alphabet = string.ascii_uppercase # The alphabet to be used
key = "QAZWSXEDCRFVTGBYHNUJMIKOLP" # Example fixed key (you can change
this)
return key

# Function to encrypt the plaintext using the cipher key


def monoalphabetic_encrypt(plaintext, key):
alphabet = string.ascii_uppercase # The original alphabet

# Create a mapping of the original alphabet to the key


char_map = {alphabet[i]: key[i] for i in range(len(alphabet))}

encrypted_text = ""
for char in plaintext:
# Encrypt only alphabetic characters (case-insensitive)
if char.isalpha():
# Convert to uppercase and substitute with the cipher key
char = char.upper()
encrypted_text += char_map[char]
else:
# Non-alphabetic characters remain unchanged
encrypted_text += char

return encrypted_text

# Function to decrypt the ciphertext using the cipher key


def monoalphabetic_decrypt(ciphertext, key):
alphabet = string.ascii_uppercase # The original alphabet

# Create a mapping from the key to the original alphabet


char_map = {key[i]: alphabet[i] for i in range(len(alphabet))}

BAIT,SURAT Page 3
Cryptography and Network Security [1010207711] [2107020701005]

decrypted_text = ""
for char in ciphertext:
# Decrypt only alphabetic characters (case-insensitive)
if char.isalpha():
# Convert to uppercase and substitute with the original alphabet
char = char.upper()
decrypted_text += char_map[char]
else:
# Non-alphabetic characters remain unchanged
decrypted_text += char

return decrypted_text

# Main function to demonstrate encryption and decryption


if __name__ == "__main__":
# Get user input for plaintext
text = input("Enter the text: ")

# Define the cipher key (fixed for demonstration)


key = create_cipher_key()
print(f"Cipher Key: {key}")

# Perform encryption
encrypted_text = monoalphabetic_encrypt(text, key)
print(f"Encrypted Text: {encrypted_text}")

# Perform decryption
decrypted_text = monoalphabetic_decrypt(encrypted_text, key)
print(f"Decrypted Text: {decrypted_text}")

Output :

BAIT,SURAT Page 4
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 3
AIM : Write a program to Implement Playfair cipher encryption-
decryption.

Code:
import string

# Function to create the Playfair cipher matrix


def create_playfair_matrix(key):
# Create a 5x5 matrix for Playfair cipher
alphabet = string.ascii_uppercase.replace('J', '') # 'J' is omitted
key = ''.join(dict.fromkeys(key.upper())) # Remove duplicates from the key
matrix_string = key + ''.join([char for char in alphabet if char not in key])

# Create the 5x5 matrix


matrix = [matrix_string[i:i+5] for i in range(0, len(matrix_string), 5)]

return matrix

# Function to format the plaintext into digraphs


def format_text(plaintext):
plaintext = plaintext.upper().replace(' ', '').replace('J', 'I')

# Split the text into digraphs


digraphs = []
i=0
while i < len(plaintext):
if i + 1 < len(plaintext) and plaintext[i] != plaintext[i + 1]:
digraphs.append(plaintext[i] + plaintext[i + 1])
i += 2
else:
digraphs.append(plaintext[i] + 'X') # Padding with 'X' if letters are the same
i += 1
return digraphs

# Function to locate the position of a character in the Playfair matrix


def get_position(matrix, char):
for row in range(5):
if char in matrix[row]:
return row, matrix[row].index(char)
return None

BAIT,SURAT Page 5
Cryptography and Network Security [1010207711] [2107020701005]

# Function to encrypt a digraph using the Playfair cipher


def playfair_encrypt(plaintext, key):
matrix = create_playfair_matrix(key)
digraphs = format_text(plaintext)
encrypted_text = ''

for digraph in digraphs:


r1, c1 = get_position(matrix, digraph[0])
r2, c2 = get_position(matrix, digraph[1])

if r1 == r2: # Same row: shift columns to the right


encrypted_text += matrix[r1][(c1 + 1) % 5]
encrypted_text += matrix[r2][(c2 + 1) % 5]
elif c1 == c2: # Same column: shift rows down
encrypted_text += matrix[(r1 + 1) % 5][c1]
encrypted_text += matrix[(r2 + 1) % 5][c2]
else: # Rectangle: swap columns
encrypted_text += matrix[r1][c2]
encrypted_text += matrix[r2][c1]

return encrypted_text

# Function to decrypt a digraph using the Playfair cipher


def playfair_decrypt(ciphertext, key):
matrix = create_playfair_matrix(key)
digraphs = [ciphertext[i:i+2] for i in range(0, len(ciphertext), 2)]
decrypted_text = ''

for digraph in digraphs:


r1, c1 = get_position(matrix, digraph[0])
r2, c2 = get_position(matrix, digraph[1])

if r1 == r2: # Same row: shift columns to the left


decrypted_text += matrix[r1][(c1 - 1) % 5]
decrypted_text += matrix[r2][(c2 - 1) % 5]
elif c1 == c2: # Same column: shift rows up
decrypted_text += matrix[(r1 - 1) % 5][c1]
decrypted_text += matrix[(r2 - 1) % 5][c2]
else: # Rectangle: swap columns
decrypted_text += matrix[r1][c2]
decrypted_text += matrix[r2][c1]

# Remove trailing 'X' padding


return decrypted_text.rstrip('X')

BAIT,SURAT Page 6
Cryptography and Network Security [1010207711] [2107020701005]

# Main function to demonstrate Playfair cipher encryption and decryption


if __name__ == "__main__":
# Get user input for plaintext and key
text = input("Enter the plaintext: ")
key = input("Enter the key: ")

# Encrypt the plaintext


encrypted_text = playfair_encrypt(text, key)
print(f"Encrypted Text: {encrypted_text}")

# Decrypt the ciphertext


decrypted_text = playfair_decrypt(encrypted_text, key)
print(f"Decrypted Text: {decrypted_text}")

Output:

BAIT,SURAT Page 7
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 4
AIM : Write a program to Implement Hill cipher encryption-decryption.

Code:
import numpy as np

key_matrix = np.zeros((3, 3), dtype=int)


message_vector = np.zeros((3, 1), dtype=int)
cipher_matrix = np.zeros((3, 1), dtype=int)

def get_key_matrix(key):
k=0
for i in range(3):
for j in range(3):
key_matrix[i][j] = ord(key[k]) % 65
k += 1

def encrypt(message_vector):
for i in range(3):
cipher_matrix[i][0] = 0
for x in range(3):
cipher_matrix[i][0] += (key_matrix[i][x] * message_vector[x][0])
cipher_matrix[i][0] = cipher_matrix[i][0] % 26

def hill_cipher(message, key):


get_key_matrix(key)
for i in range(3):
message_vector[i][0] = ord(message[i]) % 65
encrypt(message_vector)
ciphertext = [chr(cipher_matrix[i][0] + 65) for i in range(3)]
print("The Ciphertext:", "".join(ciphertext))

message = "ACT"
key = "GYBNQKURP"
hill_cipher(message, key)

BAIT,SURAT Page 8
Cryptography and Network Security [1010207711] [2107020701005]

Output:

BAIT,SURAT Page 9
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 5
AIM : Write a program to Implement Euclid algorithm to find GCD.

Code:
# Function to implement the Euclidean Algorithm to find GCD
def euclid_gcd(a, b):
# Loop until b becomes 0
while b != 0:
# Compute remainder
a, b = b, a % b
return a

# Example usage
if __name__ == "__main__":
# Input two numbers
a = int(input("Enter the first number: "))
b = int(input("Enter the second number: "))

# Compute the GCD


gcd = euclid_gcd(a, b)

# Output the result


print(f"The GCD of {a} and {b} is: {gcd}")

Output:

BAIT,SURAT Page 10
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 6
AIM : Write a program to implement Simple DES.

Code:
# S-DES Key Generation, Encryption, and Decryption

# Permutation and substitution tables


P10 = [3, 5, 2, 7, 4, 10, 1, 9, 8, 6]
P8 = [6, 3, 7, 4, 8, 5, 10, 9]
P4 = [2, 4, 3, 1]
IP = [2, 6, 3, 1, 4, 8, 5, 7]
IP_inv = [4, 1, 3, 5, 7, 2, 8, 6]
EP = [4, 1, 2, 3, 2, 3, 4, 1]
S0 = [[1, 0, 3, 2], [3, 2, 1, 0], [0, 2, 1, 3], [3, 1, 3, 2]]
S1 = [[0, 1, 2, 3], [2, 0, 1, 3], [3, 0, 1, 0], [2, 1, 0, 3]]

def permute(bits, table):


return [bits[i - 1] for i in table]

def left_shift(bits, n):


return bits[n:] + bits[:n]

def xor(bits1, bits2):


return [b1 ^ b2 for b1, b2 in zip(bits1, bits2)]

def sbox(input_bits, sbox):


row = (input_bits[0] << 1) + input_bits[3]
col = (input_bits[1] << 1) + input_bits[2]
return [int(x) for x in format(sbox[row][col], '02b')]

def fk(bits, key):


left, right = bits[:4], bits[4:]
expanded_right = permute(right, EP)
xor_result = xor(expanded_right, key)
left_sbox = sbox(xor_result[:4], S0)
right_sbox = sbox(xor_result[4:], S1)
sbox_output = left_sbox + right_sbox
p4_output = permute(sbox_output, P4)
return xor(left, p4_output) + right

def generate_keys(key):
permuted_key = permute(key, P10)

BAIT,SURAT Page 11
Cryptography and Network Security [1010207711] [2107020701005]

left, right = permuted_key[:5], permuted_key[5:]


left, right = left_shift(left, 1), left_shift(right, 1)
key1 = permute(left + right, P8)
left, right = left_shift(left, 2), left_shift(right, 2)
key2 = permute(left + right, P8)
return key1, key2

def encrypt(plaintext, key):


key1, key2 = generate_keys(key)
permuted_text = permute(plaintext, IP)
round1_output = fk(permuted_text, key1)
swapped = round1_output[4:] + round1_output[:4]
round2_output = fk(swapped, key2)
ciphertext = permute(round2_output, IP_inv)
return ciphertext

def decrypt(ciphertext, key):


key1, key2 = generate_keys(key)
permuted_text = permute(ciphertext, IP)
round1_output = fk(permuted_text, key2)
swapped = round1_output[4:] + round1_output[:4]
round2_output = fk(swapped, key1)
plaintext = permute(round2_output, IP_inv)
return plaintext

# Example usage
key = [1, 0, 1, 0, 0, 0, 0, 0, 1, 0]
plaintext = [1, 0, 1, 0, 1, 0, 1, 0]
ciphertext = encrypt(plaintext, key)
decrypted_text = decrypt(ciphertext, key)

print("Plaintext:", plaintext)
print("Ciphertext:", ciphertext)
print("Decrypted text:", decrypted_text)

BAIT,SURAT Page 12
Cryptography and Network Security [1010207711] [2107020701005]

Output:

BAIT,SURAT Page 13
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 7
AIM : Write a program to implement Simple AES.

Code:
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes

def encrypt(plaintext, key):


# Create an AES cipher object with the key and ECB mode
cipher = AES.new(key, AES.MODE_ECB)
# Pad the plaintext to be a multiple of the block size and encrypt it
ciphertext = cipher.encrypt(pad(plaintext.encode(), AES.block_size))
return ciphertext

def decrypt(ciphertext, key):


# Create an AES cipher object with the key and ECB mode
cipher = AES.new(key, AES.MODE_ECB)
# Decrypt the ciphertext and remove the padding
decrypted_data = unpad(cipher.decrypt(ciphertext), AES.block_size)
return decrypted_data.decode()

# Example usage
key = get_random_bytes(16) # AES-128 key
plaintext = "This is a secret message"
ciphertext = encrypt(plaintext, key)
print(f"Ciphertext: {ciphertext}")

decrypted_text = decrypt(ciphertext, key)


print(f"Decrypted text: {decrypted_text}")

Output:

BAIT,SURAT Page 14
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 8
AIM : Write a program to Implement Diffi-Hellmen Key exchange Method

Code:
# Diffie-Hellman Key Exchange Implementation in Python

# Publicly shared variables


shared_prime = 23 # p
shared_base = 5 # g

# Alice's private key


alice_secret = 6 # a

# Bob's private key


bob_secret = 15 # b

# Alice computes her public key


A = (shared_base ** alice_secret) % shared_prime
print("Alice's public key (A):", A)

# Bob computes his public key


B = (shared_base ** bob_secret) % shared_prime
print("Bob's public key (B):", B)

# Alice computes the shared secret


alice_shared_secret = (B ** alice_secret) % shared_prime
print("Alice's shared secret:", alice_shared_secret)

# Bob computes the shared secret


bob_shared_secret = (A ** bob_secret) % shared_prime
print("Bob's shared secret:", bob_shared_secret)

# The shared secrets should be the same


assert alice_shared_secret == bob_shared_secret

BAIT,SURAT Page 15
Cryptography and Network Security [1010207711] [2107020701005]

Output:

BAIT,SURAT Page 16
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 9
AIM : Write a program to Implement RSA encryption-decryption
algorithm.

Code:
import random

# Function to compute the greatest common divisor


def gcd(a, b):
while b != 0:
a, b = b, a % b
return a

# Function to find the modular inverse


def mod_inverse(e, phi):
d=0
x1, x2, y1 = 0, 1, 1
temp_phi = phi

while e > 0:
temp1 = temp_phi // e
temp2 = temp_phi - temp1 * e
temp_phi, e = e, temp2

x = x2 - temp1 * x1
y = d - temp1 * y1

x2, x1 = x1, x
d, y1 = y1, y

if temp_phi == 1:
return d + phi

# Function to generate key pairs


def generate_keypair(p, q):
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)

BAIT,SURAT Page 17
Cryptography and Network Security [1010207711] [2107020701005]

g = gcd(e, phi)

d = mod_inverse(e, phi)
return ((e, n), (d, n))

# Function to encrypt the message


def encrypt(pk, plaintext):
key, n = pk
cipher = [(ord(char) ** key) % n for char in plaintext]
return cipher

# Function to decrypt the message


def decrypt(pk, ciphertext):
key, n = pk
plain = [chr((char ** key) % n) for char in ciphertext]
return ''.join(plain)

# Example usage
if __name__ == '__main__':
p = 61
q = 53
public, private = generate_keypair(p, q)
print("Public Key:", public)
print("Private Key:", private)

message = "Hello RSA!"


encrypted_msg = encrypt(public, message)
print("Encrypted Message:", encrypted_msg)

decrypted_msg = decrypt(private, encrypted_msg)


print("Decrypted Message:", decrypted_msg)

Output:

BAIT,SURAT Page 18
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 10
AIM : Write a program to generate SHA-l hash.

Code:
import hashlib

def generate_sha1_hash(input_string):
# Create a new sha1 hash object
sha1_hash = hashlib.sha1()

# Update the hash object with the bytes-like object (input string encoded to bytes)
sha1_hash.update(input_string.encode('utf-8'))

# Return the hexadecimal digest of the hash


return sha1_hash.hexdigest()

# Example usage
input_data = "Hello, World!"
hash_value = generate_sha1_hash(input_data)
print(f"SHA-1 Hash: {hash_value}")

Output:

BAIT,SURAT Page 19
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 11
AIM : Implement a digital signature algorithm.

Code:
from Crypto.PublicKey import DSA
from Crypto.Signature import DSS
from Crypto.Hash import SHA256

# Generate DSA key pair


key = DSA.generate(2048)

# Export the public key


public_key = key.publickey()

# Message to be signed
message = b'This is a secret message'

# Hash the message


hash_obj = SHA256.new(message)

# Sign the message


signer = DSS.new(key, 'fips-186-3')
signature = signer.sign(hash_obj)

print("Signature:", signature)

# Verify the signature


verifier = DSS.new(public_key, 'fips-186-3')
try:
verifier.verify(hash_obj, signature)
print("The signature is valid.")
except ValueError:
print("The signature is not valid.")

Output:

BAIT,SURAT Page 20
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 12
AIM : Study and use the Wireshark for the various network protocols.
Wire-shark is a network packet analyzer. A network packet analyzer presents captured packet
data in as much detail as possible. Wire-shark is an open-source packet analyzer, which is used
for education, analysis, software development, communication protocol development, and
network troubleshooting. It is used to track the packets so that each one is filtered to meet our
specific needs.

Uses of Wire-shark:
Wire-shark can be used in the following ways:

• It is used by network security engineers to examine security problems.

• It allows the users to watch all the traffic being passed over the network.

• It is used by network engineers to troubleshoot network issues.

• It also helps to troubleshoot latency issues and malicious activities on your network.

• It can also analyze dropped packets.

• It helps us to know how all the devices like laptop, mobile phones, desktop, switch, routers,
etc., communicate in a local network or the rest of the world.

Common Protocols to Analyze with Wireshark :

1. Ethernet

• Ethernet is the link-layer protocol used to communicate between devices within a local
network.

• In Wireshark, Ethernet frames are displayed with details such as source and destination
MAC addresses and the type of the protocol encapsulated in the frame (e.g., IP, ARP).

2. ARP (Address Resolution Protocol)

• ARP is used to map an IP address to a MAC address.

• You can filter ARP packets using the display filter arp.

• ARP packets contain mappings for IP addresses to MAC addresses, which can be
helpful for troubleshooting issues like IP conflicts.

3. IP (Internet Protocol)

• IPv4 and IPv6 are the most common IP protocols. Use the filters ip and ipv6
respectively.

BAIT,SURAT Page 21
Cryptography and Network Security [1010207711] [2107020701005]

• Key fields include source and destination IP addresses, TTL, and packet length.

• You can inspect packet routing, fragmentation, and TTL expiration.

4. TCP (Transmission Control Protocol)

• TCP is a connection-oriented protocol commonly used for reliable data transmission


(e.g., HTTP, FTP, SMTP).

• Key fields in the TCP header include source and destination ports, sequence and
acknowledgment numbers, and flags (SYN, ACK, FIN, etc.).

• Filters for TCP traffic: tcp, tcp.port == 80, tcp.flags.syn == 1.

• TCP Stream: Wireshark allows you to follow a TCP stream, which is useful for
analyzing entire conversations between hosts.

5. UDP (User Datagram Protocol)

• UDP is used for low-latency communication with no error recovery (e.g., DNS, VoIP,
streaming).

• The UDP header includes source and destination ports, and you can filter UDP traffic
with udp.

6. DNS (Domain Name System)

• DNS resolves domain names to IP addresses.

• Wireshark decodes DNS queries and responses.

• Filter DNS traffic using dns.

• Inspect the query name (e.g., www.example.com) and the response (e.g., 192.168.1.1).

7. HTTP (Hypertext Transfer Protocol)

• HTTP is the protocol used for web communication.

• Filter HTTP traffic using http.

• Examine HTTP requests and responses, including methods like GET, POST, and
response codes (e.g., 200 OK, 404 Not Found).

8. FTP (File Transfer Protocol)

• FTP is used for transferring files over the network.

• Filter FTP traffic using ftp or ftp-data for file transfers.

• Inspect FTP commands such as USER, PASS, STOR, RETR, etc.

BAIT,SURAT Page 22
Cryptography and Network Security [1010207711] [2107020701005]

9. SMTP (Simple Mail Transfer Protocol)

• SMTP is used for email transmission.

• You can filter SMTP traffic with smtp.

• Inspect mail headers, sender/receiver addresses, and message content.

10. TLS/SSL (Transport Layer Security / Secure Sockets Layer)

• Wireshark can capture and display encrypted TLS/SSL traffic (commonly used in
HTTPS).

• You can filter SSL/TLS traffic using tls or ssl (for older versions).

BAIT,SURAT Page 23
Cryptography and Network Security [1010207711] [2107020701005]

PRACTICAL – 13
AIM : Perform various encryption-decryption techniques with cryptool.
What is CrypTool?

CrypTool is an open source e-learning tool illustrating cryptographic and cryptanalytic


concepts.

CrypTool implements more than 300 algorithms. Users can adjust these with own parameters.
The graphical interface, online documentation, analytic tools and algorithms of Crypt Tool
introduce users to the field of cryptography.

Classical ciphers are available alongside asymmetric cryptography including RSA, elliptic
curve cryptography, digital signatures, homomorphism encryption, and Diffie– Hellman key
exchange, many of which are visualized by animations.

Steps to perform encryption using CrypTool

Step 1: Start CrypToo

BAIT,SURAT Page 24
Cryptography and Network Security [1010207711] [2107020701005]

Step 2: Create the document on which you want to apply encryption algorithm.

Step 3: Create the document for the key used for encryption-decryption technique.

BAIT,SURAT Page 25
Cryptography and Network Security [1010207711] [2107020701005]

1.Caesar cipher

BAIT,SURAT Page 26
Cryptography and Network Security [1010207711] [2107020701005]

2. Playfair Cipher

BAIT,SURAT Page 27
Cryptography and Network Security [1010207711] [2107020701005]

BAIT,SURAT Page 28
Cryptography and Network Security [1010207711] [2107020701005]

3.Hill Cipher

BAIT,SURAT Page 29
Cryptography and Network Security [1010207711] [2107020701005]

BAIT,SURAT Page 30

You might also like