0% found this document useful (0 votes)
28 views34 pages

Priyanshu Practical File

Uploaded by

priyanshuarya091
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)
28 views34 pages

Priyanshu Practical File

Uploaded by

priyanshuarya091
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/ 34

Data Privacy

Practical Submission

Name : Priyanshu Arya

Roll no. : 16061

Course : B.Sc(Hons.) Computer Science

Section : B
Question Mentioned in Practical List :
1. Write a program to perform encryption and decryption using Caesar cipher

(substitutional cipher).

2. Write a program to perform encryption and decryption using Rail Fence

Cipher (transpositional cipher)

3. Write a Python program that defines a function and takes a password string

as input and returns its SHA-256 hashed representation as a hexadecimal

string.

4. Write a Python program that reads a file containing a list of usernames and

passwords, one pair per line (separated by a comma). It checks each

password to see if it has been leaked in a data breach. You can use the "Have

I Been Pwned" API (https://haveibeenpwned.com/API/v3) to check if a

password has been leaked.

5. Write a Python program that generates a password using a random

combination of words from a dictionary file.

6. Write a Python program that simulates a brute-force attack on a password by

trying out all possible character combinations.

7. Demonstrate the usage/sending of a digitally signed document.


Q. 1. Write a program to perform encryption and decryption using

Caesar cipher (substitutional cipher)

def caesar_cipher(text, shift, mode):

result = ''

if mode == 'decrypt':

shift = -shift

for char in text:

if char.isalpha():

start = ord('a') if char.islower() else ord('A')

shifted_char = chr(((ord(char) - start + shift)

% 26 )+ start)

else:

shifted_char = char

if mode == 'decrypt':

result = result + shifted_char

else:

result += shifted_char
return result

def menu():

while True:

print("Caeser Cipher Menu")

print("1. Encrypt")

print("2. Decrypt")

print("3. Exit")

choice = input("Enter your choice: ")

if choice == '1':

text = input("Enter the text to encrypt: ")

shift = int(input("Enter the shift value: "))

encrypted_text = caesar_cipher(text, shift,

'encrypt')

print("Encrypted:", encrypted_text)

elif choice == '2':

text = input("Enter the text to decrypt: ")

shift = int(input("Enter the shift value: "))


decrypted_text = caesar_cipher(text, shift,

'decrypt')

print("Decrypted:", decrypted_text)

elif choice == '3':

print("Exiting the program.")

break

else:

print("Invalid choice. Please try again.")

if __name__ == "__main__":

menu()
How the Caesar Cipher Works

The Caesar Cipher is a substitution cipher that shifts each letter


in the plaintext by a fixed number of positions in the alphabet.
For example, with a shift of 3:
● A becomes D
● B becomes E, and so on.
When the end of the alphabet is reached, it wraps around to the
beginning.

Applications and Limitations

Applications:

● Used in basic cryptography to understand substitution


ciphers.
● Can serve as a teaching tool for learning encryption
techniques.

Limitations:

● It is not secure for modern use since the shift key can be
brute-forced (only 25 possible shifts).
Q. 2. Write a program to perform encryption and decryption using Rail

Fence Cipher (transpositional cipher)

def encrypt_rail_fence(text, depth):

rail = [['\n' for i in range(len(text))] for j in

range(depth)]

dir_down = False

row, col = 0, 0

for i in range(len(text)):

if (row == 0) or (row == depth - 1):

dir_down = not dir_down

rail[row][col] = text[i]

col += 1

if dir_down:

row += 1

else:

row -= 1
result = []

for i in range(depth):

for j in range(len(text)):

if rail[i][j] != '\n':

result.append(rail[i][j])

return "".join(result)

def decrypt_rail_fence(cipher, depth):

rail = [['\n' for i in range(len(cipher))] for j

in range(depth)]

dir_down = None

row, col = 0, 0

for i in range(len(cipher)):

if row == 0:

dir_down = True

if row == depth - 1:

dir_down = False

rail[row][col] = '*'
col += 1

if dir_down:

row += 1

else:

row -= 1

index = 0

for i in range(depth):

for j in range(len(cipher)):

if rail[i][j] == '*' and index <

len(cipher):

rail[i][j] = cipher[index]

index += 1

result = []

row, col = 0, 0

for i in range(len(cipher)):

if row == 0:

dir_down = True
if row == depth-1:

dir_down = False

if rail[row][col] != '*':

result.append(rail[row][col])

col += 1

if dir_down:

row += 1

else:

row -= 1

return "".join(result)

if __name__ == "__main__":

while True:

print("\nMenu:")

print("1. Encrypt a message")

print("2. Decrypt a message")

print("3. Exit")
choice = input("Enter your choice : ")

if choice == '1':

message = input("Enter the message to

encrypt: ")

depth = int(input("Enter the depth (number

of rails): "))

cipher_text = encrypt_rail_fence(message,

depth)

print(f"Encrypted Message: {cipher_text}")

elif choice == '2':

cipher_text = input("Enter the message to

decrypt: ")

depth = int(input("Enter the depth (number

of rails): "))

decrypted_text =

decrypt_rail_fence(cipher_text, depth)

print(f"Decrypted Message:

{decrypted_text}")
elif choice == '3':

print("Exiting...")

break

else:

print("Invalid choice! Please try again.")


How the Rail Fence Cipher Works

The Rail Fence Cipher is a transposition cipher that rearranges the

plaintext characters into a zigzag pattern across multiple rows.

1. Encryption:
o The plaintext is written in a zigzag pattern using the number
of rows specified by the key.
o The characters are then read row by row to form the
encrypted text.

2. Decryption:
o Reconstructs the zigzag pattern by marking the path and
filling in the characters row by row.
o Reads the characters in a zigzag pattern to retrieve the
original plaintext.

Applications and Limitations

Applications:

● Used in simple message scrambling and cryptography teaching.


● Introduces the concept of transposition in cryptography.

Limitations:

● Not secure against modern cryptanalysis as the structure is


predictable.
Q. 3. Write a Python program that defines a function and takes a

password string as input and returns its SHA-256 hashed representation

as a hexadecimal string.

import rsa

def generateHash(input):

msgInBinary = input.encode('utf-8')

return rsa.compute_hash(msgInBinary, 'SHA-256')

def main():

while True:

print("\nMenu:")

print("1. Generate Hash")

print("2. Exit")

choice = input("Enter your choice: ")

if choice == '1':

user_input = input('Enter the Password :

')

output = generateHash(user_input)
print('Generated Hash: ', output)

print('Generated Hash in Hexa: ',

output.hex())

print('Length of Hex :

',len(output.hex()))

elif choice == '2':

print("Exiting the program.")

break

else:

print("Invalid choice. Please try again.")

if __name__ == "__main__":

main()
Applications

1.Password Storage:

o Hashing ensures passwords are securely


stored, and even if the database is
compromised, the original passwords cannot
be retrieved directly.

2.Data Integrity:

o Hashing can validate that input data hasn't


been tampered with.
Why Use RSA's SHA-256?

● The cryptography library implements strong


cryptographic algorithms, making it reliable and
secure for hashing sensitive data.
Q. 4. Write a Python program that reads a file containing a list of

usernames and passwords, one pair per line (separated by a comma). It

checks each password to see if it has been leaked in a data breach. You

can use the "Have I Been Pwned" API

(https://haveibeenpwned.com/API/v3) to check if a password has been

leaked.

import hashlib

import requests

def hash_password(password):
sha1_hash =

hashlib.sha1(password.encode()).hexdigest().upper()

print("SHA1 Hash genarated : ",sha1_hash)

return sha1_hash

def check_password_pwned(hash_prefix):

url =

f'https://api.pwnedpasswords.com/range/{hash_prefix}'

response = requests.get(url)

return response.text

def check_credentials(file_name):

with open(file_name, 'r') as file:

for line in file:

username, password =

line.strip().split(',')

sha1_hash = hash_password(password)

prefix = sha1_hash[:5]

suffix = sha1_hash[5:]

response = check_password_pwned(prefix)
if suffix in response:

print(f'Password for {username} has

been leaked!')

else:

print(f'Password for {username} is

safe.')

check_credentials('credential.txt')

How This Works

1. Using the "Have I Been Pwned" API:


o The API accepts the first 5 characters of the SHA-1 hash of
the password (prefix) and returns a list of hash suffixes and
their breach counts.

2. Password Checking:
o The program calculates the SHA-1 hash of the password and
splits it into:
▪ Prefix: First 5 characters sent to the API.

▪ Suffix: Remaining characters checked against the API


response.

o If the suffix is found, the password has been leaked, and its
breach count is returned.

3. Output:
o The program prints whether each password is safe or has
been leaked, along with the breach count.

Security Note

● The "k-anonymity" approach ensures that only the prefix of the


password's hash is sent to the API, keeping the original password
private.

● Avoid sharing the original file or leaked passwords.

URL for the credential FIle

Q. 5. Write a Python program that generates a password using a random

combination of words from a dictionary file.


import random

with open('dictionary.txt', 'r') as file:

items = file.read().splitlines()

words = [item for item in items if item.isalpha()]

numbers = [item for item in items if item.isdigit()]

special_chars = [item for item in items if not

item.isalnum()]

def generate_password(password_length):

password = ''

password += random.choice(words).capitalize()

password += random.choice(words).lower()

password += random.choice(numbers)

password += random.choice(special_chars)

while len(password) < password_length:

word = random.choice(words)
number = random.choice(numbers)

special_char = random.choice(special_chars)

password += word + number + special_char

if len(password) > password_length:

excess_length = len(password) -

password_length

password = password[:-excess_length]

return password

def menu():

while True:

print("\nMenu:")

print("1. Generate a password")

print("2. Exit")

choice = input("Enter your choice (1/2): ")

if choice == '1':

while True:
try:

password_length = int(input("Enter

the desired password length (8-12): "))

if 8 <= password_length <= 12:

break

else:

print("Please enter a number

between 8 and 12.")

except ValueError:

print("Invalid input! Please enter

a number between 8 and 12.")

password =

generate_password(password_length)

print(f"Generated Password: {password}")

another = input("Would you like to

generate another password? (yes/no): ").lower()

if another != 'yes':

break
elif choice == '2':

print("Exiting...")

break

else:

print("Invalid choice! Please try again.")

if __name__ == "__main__":

menu()
Explanation

Why Use a Word-Based Password?

● Secure and Memorable: Word-based passwords are longer, making


them harder to crack through brute force. They’re also easier for
humans to remember compared to random strings of characters.

● Randomness: The randomness in word selection enhances security,


as it prevents predictability.
Customizing the Password

● You can:

o Increase the number of words to make the password more


secure.

o Use different separators

o Add random capitalization or numbers for added complexity.

Security Tip

Ensure the dictionary file has a sufficient number of unique words to

make the password hard to guess. A small dictionary significantly

reduces security.

Q. 6. Write a Python program that simulates a brute-force attack


on a password by trying out all possible character combinations.

import itertools

import string

def bruteforce_attack(password):

chars = string.printable.strip()
attempts = 0

for length in range(1, len(password) + 1):

for guess in itertools.product(chars,

repeat=length):

attempts += 1

guess = ''.join(guess)

if guess == password:

return (attempts, guess)

return (attempts, None)

password = input("Input the password to crack: ")

attempts, guess = bruteforce_attack(password)

if guess:

print(f"Password cracked in {attempts} attempts.

The password is {guess}.")

else:

print(f"Password not cracked after {attempts}

attempts.")
Explanation

1. Password Length:

o Brute-forcing longer passwords is exponentially harder:

▪ A charset of 62 (letters + digits) and a password of


length 6 requires 626=56,800,235,58462^6 =
56,800,235,584626=56,800,235,584 attempts.

2. Why It's Slow:


o Brute-force attacks are inherently inefficient, especially for
strong passwords.

o Adding complexity (e.g., longer lengths, more characters)


drastically increases the time required.

3. Real-World Applications:
o Demonstrating the vulnerability of weak or short passwords.

o Stressing the importance of using strong passwords.

Security Note

● This program is for educational purposes only. Attempting


unauthorized brute-force attacks is illegal and unethical.

● Always use this in controlled environments with your own data.


Q. 7. Demonstrate the usage/sending of a digitally signed

document.

import rsa

def generate_keys():

(public_key, private_key) = rsa.newkeys(2048) #

2048-bit key length

return public_key, private_key

def sign_document(document, private_key):

document_bytes = document.encode('utf-8')

signature = rsa.sign(document_bytes, private_key,

'SHA-256')

return signature

def send_document(document, signature):

return {

'document': document,

'signature': signature
}

def verify_signature(document, signature, public_key):

document_bytes = document.encode('utf-8')

try:

rsa.verify(document_bytes, signature,

public_key)

print("The signature is valid, and the

document is authentic.")

except rsa.VerificationError:

print("The signature is invalid, or the

document has been tampered with.")

def main():

public_key, private_key = generate_keys()

document = "This is a confidential document that

needs to be signed."

signature = sign_document(document, private_key)

sent_data = send_document(document, signature)


print(f"Original Document:

{sent_data['document']}")

verify_signature(sent_data['document'],

sent_data['signature'], public_key)

if __name__ == "__main__":

main()
Applications

1. Document Authenticity:
o Ensure the document was created by the intended sender.

2. Integrity:
o Confirm the document hasn't been tampered with during
transmission.

3. Non-Repudiation:
o Prevent the sender from denying their involvement.

Security Considerations

1. Key Protection:
o Private keys must be kept secure to prevent unauthorized
signing.

2. Key Size:
o Use at least 2048-bit RSA keys for strong security.

3. Certificate Authority:
o In real-world use, public keys are distributed with certificates
issued by trusted authorities.

You might also like