CNS PYTHON
CNS PYTHON
AIM: Write a C program that contains a string (char pointer) with a value “Hello world”. The
program should XOR each character in this string with 0 and displays the result.
DESCRIPTION:
The operaCon "XOR each character in this string with 0" means applying the XOR (exclusive
OR) bitwise operaCon to each character of the string using the value `0`. Since XOR with `0`
leaves the bits unchanged, each character will remain the same.
In other words, XORing any character with 0 does not alter the original string.
CODE:
#include <stdio.h>
int main() {
char str[] = "Hello world";
for (int i = 0; str[i] != '\0'; i++) {
str[i] = str[i] ^ 0;
}
prinZ("Result a[er XOR with 0: %s\n", str);
return 0;
}
OUTPUT:
1
EXPERIMENT-2
AIM: Write a C program that contains a string (char pointer) with a value “Hello world”. The
program should AND or and XOR each character in this string with 127 and display the
result.
DESCRIPTION:
AND each character with 127:
o The AND operaCon compares each bit of the character’s ASCII value with the
number 127 (01111111 in binary). Since 127 has its highest bit set to 0, this
effecCvely clears the most significant bit of each character, leaving the other
bits unchanged. Characters with an ASCII value above 127 will be reduced to a
value below 127.
XOR each character with 127:
o The XOR operaCon flips the bits wherever the corresponding bit of the
number 127 (01111111) is 1. This will invert the lower 7 bits of each
character, drasCcally changing its ASCII value. For example, if a character is
lowercase, it might turn into uppercase or a different symbol depending on its
original ASCII value.
Both operaCons result in modified strings, but in different ways based on how bitwise AND
or XOR affects the character’s ASCII values.
CODE:
#include <stdio.h>
int main() {
char *str = "Hello world";
int i;
prinZ("Original string: %s\n", str);
prinZ("AND with 127: ");
for (i = 0; str[i] != '\0'; i++) {
prinZ("%c", str[i] & 127);
}
prinZ("\n");
prinZ("OR with 127: ");
for (i = 0; str[i] != '\0'; i++) {
prinZ("%c", str[i] | 127);
2
}
prinZ("\n");
prinZ("XOR with 127: ");
for (i = 0; str[i] != '\0'; i++) {
prinZ("%c", str[i] ^ 127);
}
prinZ("\n");
return 0;
}
OUTPUT:
3
EXPERIMENT-3
AIM: Write a Java program to perform encrypCon and decrypCon using the following
algorithms
a. Ceaser cipher
DESCRIPTION:
A Caesar cipher is one of the simplest encrypCon techniques. It works by shi[ing each leoer
of the plaintext by a fixed number of posiCons in the alphabet. For example, with a shi[ of 3:
• A becomes D
• B becomes E
• C becomes F
This shi[ing conCnues for all leoers in the message. When the end of the alphabet is reached,
it wraps around (so Z would shi[ to C with a shi[ of 3). Non-leoer characters remain
unchanged.
CODE:
class CaesarCipher:
@staCcmethod
def encrypt(plaintext, key):
encrypted_text = []
for c in plaintext:
shi[ed_char = chr(ord(c) + key)
encrypted_text.append(shi[ed_char)
return ''.join(encrypted_text)
@staCcmethod
def decrypt(encrypted_text, key):
decrypted_text = []
for c in encrypted_text:
shi[ed_char = chr(ord(c) - key)
decrypted_text.append(shi[ed_char)
return ''.join(decrypted_text)
4
if __name__ == "__main__":
plaintext = "ABC"
key = 3
encrypted_text = CaesarCipher.encrypt(plaintext, key)
print("Encrypted Text:", encrypted_text)
decrypted_text = CaesarCipher.decrypt(encrypted_text, key)
print("Decrypted Text:", decrypted_text)
OUTPUT:
5
b. Subs/tu/on Cipher
DESCRIPTION:
A SubsCtuCon cipher is a type of encrypCon where each leoer in the plaintext is replaced with
another leoer according to a fixed system. Unlike the Caesar cipher, where leoers are shi[ed
uniformly, a subsCtuCon cipher uses a more complex mapping.
For example:
• Plaintext: HELLO
• Ciphertext (using a random subsCtuCon): XNZZT
CODE:
class SubCipher:
@staCcmethod
def encrypt(plaintext, key):
encrypted_text = []
for i in range(len(plaintext)):
shi[ed_char = chr(ord(plaintext[i]) + key[i])
encrypted_text.append(shi[ed_char)
return ''.join(encrypted_text)
@staCcmethod
def decrypt(encrypted_text, key):
decrypted_text = []
for i in range(len(encrypted_text)):
shi[ed_char = chr(ord(encrypted_text[i]) - key[i])
decrypted_text.append(shi[ed_char)
return ''.join(decrypted_text)
if __name__ == "__main__":
plaintext = "ABC"
key = [1, 3, 5]
6
encrypted_text = SubCipher.encrypt(plaintext, key)
print("Encrypted Text:", encrypted_text)
decrypted_text = SubCipher.decrypt(encrypted_text, key)
print("Decrypted Text:", decrypted_text)
OUTPUT:
7
c. Hill Cipher
DESCRIPTION:
The Hill cipher is a polygraphic subsCtuCon cipher that uses linear algebra, specifically matrix
mulCplicaCon, to encrypt text. It encrypts blocks of leoers, treaCng them as vectors and
mulCplying them by an encrypCon matrix.
Here’s how it works:
1. Key Matrix: A square matrix (e.g., 2x2 or 3x3) acts as the encrypCon key.
2. Plaintext Blocks: The plaintext is divided into equally sized blocks of leoers.
3. Matrix MulCplicaCon: Each block is converted to a vector (using numerical values for
leoers), then mulCplied by the key matrix.
4. Modulo OperaCon: The resulCng vector is reduced modulo 26 (for the 26 leoers of
the alphabet) to get the ciphertext.
To decrypt, the inverse of the key matrix is used. It requires modular arithmeCc and the matrix
determinant to compute the inverse.
CODE:
class HillCipher:
@staCcmethod
def determinant(matrix):
return (matrix[0][0] * (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1]) -
matrix[0][1] * (matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0]) +
matrix[0][2] * (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0])) % 26
@staCcmethod
def mod_inverse(d, mod):
d = d % mod
for x in range(1, mod):
if (d * x) % mod == 1:
return x
return 1 # Fallback
@staCcmethod
8
def adjoint(matrix):
adj = [[0] * 3 for _ in range(3)]
adj[0][0] = (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1]) % 26
adj[0][1] = (matrix[0][2] * matrix[2][1] - matrix[0][1] * matrix[2][2]) % 26
adj[0][2] = (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1]) % 26
adj[1][0] = (matrix[1][2] * matrix[2][0] - matrix[1][0] * matrix[2][2]) % 26
adj[1][1] = (matrix[0][0] * matrix[2][2] - matrix[0][2] * matrix[2][0]) % 26
adj[1][2] = (matrix[0][2] * matrix[1][0] - matrix[0][0] * matrix[1][2]) % 26
adj[2][0] = (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) % 26
adj[2][1] = (matrix[0][1] * matrix[2][0] - matrix[0][0] * matrix[2][1]) % 26
adj[2][2] = (matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]) % 26
@staCcmethod
def mulCply_matrices(matrix1, matrix2):
result = [[0] * 3 for _ in range(3)]
for i in range(3):
for j in range(3):
result[i][j] = sum(matrix1[i][k] * matrix2[k][j] for k in range(3)) % 26
if result[i][j] < 0:
result[i][j] += 26 # Ensure posiCve modulo
return result
9
@staCcmethod
def encrypt(plaintext, key):
plain_matrix = [[ord(plaintext[i * 3 + j]) - ord('A') for j in range(3)] for i in range(3)]
cipher_matrix = HillCipher.mulCply_matrices(key, plain_matrix)
@staCcmethod
def decrypt(ciphertext, key):
adj = HillCipher.adjoint(key)
d = HillCipher.determinant(key)
d_inverse = HillCipher.mod_inverse(d, 26)
if __name__ == "__main__":
key = [
[2, 4, 5],
[9, 2, 1],
[3, 17, 7]
]
plaintext = "ATTACKBBB"
10
ciphertext = HillCipher.encrypt(plaintext, key)
print("Encrypted text:", ciphertext)
decrypted_text = HillCipher.decrypt(ciphertext, key)
print("Decrypted text:", decrypted_text)
OUTPUT:
11
d. Play fair Cipher
DESCRIPTION:
The Playfair Cipher is a digraph subsCtuCon cipher that encrypts pairs of leoers in plaintext.
It uses a 5x5 matrix of leoers, and each leoer pair is encrypted based on its posiCon in this
matrix. The rules for encrypCon are as follows:
1. If both leoers are in the same row, each leoer is replaced by the leoer to its right.
2. If both leoers are in the same column, each leoer is replaced by the leoer below.
3. If the leoers form a rectangle, each is replaced by the leoer on the same row but in
the other pair's column.
CODE:
def remove_duplicate(s):
result = []
for char in s:
if char not in result:
result.append(char)
return ''.join(result)
def make_pair(pt):
s = ''
12
for i in range(len(pt)):
if pt[i] == ' ':
conCnue
else:
s += pt[i]
if i < len(pt) - 1 and pt[i] == pt[i + 1]:
s += 'x'
if len(s) % 2 != 0:
s += 'x'
print(s)
return s
if y[0] == y[2]:
y[1] = (y[1] + 1) % 5
y[3] = (y[3] + 1) % 5
13
elif y[1] == y[3]:
y[0] = (y[0] + 1) % 5
y[2] = (y[2] + 1) % 5
return y
return ''.join(ch)
def main():
pt = "instruments"
key = "monarchy"
key = remove_duplicate(key)
ch = list(key)
st = "abcdefghiklmnopqrstuvwxyz" # Excludes 'j'
st = remove_white_space(ch, st)
c = list(st)
14
matrix = [['' for _ in range(5)] for _ in range(5)]
index_of_st, index_of_key = 0, 0
for i in range(5):
for j in range(5):
if index_of_key < len(key):
matrix[i][j] = ch[index_of_key]
index_of_key += 1
else:
matrix[i][j] = c[index_of_st]
index_of_st += 1
pt = make_pair(pt)
pt = encrypt(pt, matrix)
print("Encrypted text:", pt)
if __name__ == "__main__":
main()
15
OUTPUT:
16
EXPERIMENT-4
AIM: Write a C/JAVA program to implement the DES algorithm logic.
DESCRIPTION:
The DES (Data EncrypCon Standard) is a symmetric-key block cipher used for encrypCng data.
It operates on 64-bit blocks of plaintext and uses a 56-bit key for encrypCon. Here's how it
works:
1. IniCal PermutaCon: The plaintext is permuted using a fixed table to rearrange the bits.
2. 16 Rounds of Feistel Network: Each round involves:
o Spli•ng the block into two 32-bit halves.
o Applying a series of transformaCons (expansion, subsCtuCon, permutaCon)
using a round-specific key derived from the main key.
o XORing one half with the transformed result.
o Swapping the two halves.
3. Final PermutaCon: A[er 16 rounds, the two halves are combined and permuted to
produce the ciphertext.
CODE:
from Crypto.Cipher import DES
from Crypto.Random import get_random_bytes
def pad(text):
while len(text) % 8 != 0:
text += ' '
17
return text
def main():
message = "This is a confidenCal message."
message = pad(message)
my_message = message.encode('uZ-8')
my_des_key = get_random_bytes(8)
my_encrypted_bytes = my_cipher.encrypt(my_message)
my_decrypted_bytes = my_cipher.decrypt(my_encrypted_bytes)
encrypted_data = my_encrypted_bytes
decrypted_data = my_decrypted_bytes.decode('uZ-8').strip()
if __name__ == "__main__":
main()
OUTPUT:
18
EXPERIMENT-5
AIM: Write a C/JAVA program to implement the Blowfish algorithm logic
DESCRIPTION:
Steps in Blowfish Algorithm:
1. Key Expansion: The key provided is expanded into several subkeys that are stored in
two arrays: the P-array and the S-boxes. Blowfish uses 18 entries in the P-array and
four S-boxes containing 256 entries each.
2. Rounds of EncrypCon: Blowfish processes 16 rounds of encrypCon, where each round
consists of:
o XORing half the data with a subkey from the P-array.
o Passing the result through a complex funcCon involving the S-boxes.
o XORing this result with the other half of the data and swapping halves.
3. Final Round: A[er 16 rounds, the two halves are swapped again, and the output is
XORed with two more subkeys to produce the ciphertext.
4. DecrypCon: The decrypCon process is the reverse of encrypCon, using the same key
and subkeys.
CODE:
from Crypto.Cipher import Blowfish
from Crypto.Random import get_random_bytes
import base64
def main():
message = "This is a confidenCal message"
secret_key = get_random_bytes(16)
while len(message) % 8 != 0:
message += ' '
19
encrypted_message = cipher.encrypt(message.encode('uZ-8'))
encrypted_base64 = base64.b64encode(encrypted_message).decode('uZ-8')
print("Encrypted Message:", encrypted_base64)
decrypted_message = cipher.decrypt(base64.b64decode(encrypted_base64)).decode('uZ-
8').strip()
print("Decrypted Message:", decrypted_message)
if __name__ == "__main__":
main()
OUTPUT:
20
EXPERIMENT-6
AIM: Write a C/JAVA program to implement the Rijndael algorithm logic.
DESCRIPTION:
Rijndael is a symmetric key block cipher that was selected as the Advanced EncrypCon
Standard (AES) by the U.S. NaConal InsCtute of Standards and Technology (NIST) in 2001. It
supports key sizes of 128, 192, and 256 bits, and operates on data blocks of 128 bits (16 bytes).
Rijndael is known for its security and efficiency in both so[ware and hardware
implementaCons.
Key Features of Rijndael/AES
• Block Size: Fixed at 128 bits.
• Key Sizes: Supports 128, 192, or 256 bits.
• Structure: Composed of several rounds of processing, including subsCtuCon,
permutaCon, and mixing operaCons.
CODE:
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import base64
def main():
message = "This is a confidenCal message"
while len(message) % 16 != 0:
message += ' '
encrypted_message = cipher.encrypt(message.encode('uZ-8'))
encrypted_base64 = base64.b64encode(encrypted_message).decode('uZ-8')
21
print("Encrypted Message:", encrypted_base64)
decrypted_message = cipher.decrypt(base64.b64decode(encrypted_base64)).decode('uZ-
8').strip()
print("Decrypted Message:", decrypted_message)
if __name__ == "__main__":
main()
OUTPUT:
22
EXPERIMENT-7
AIM: Write the RC4 logic in Java Using Java cryptography.
DESCRIPTION:
RC4 (Rivest Cipher 4) is a symmetric stream cipher designed by Ron Rivest in 1987. It is known
for its simplicity and speed, making it a popular choice for various applicaCons, including
SSL/TLS and WEP. Here’s a brief overview of its key characterisCcs and working principle:
Key CharacterisCcs
• Symmetric Key Cipher: The same key is used for both encrypCon and decrypCon.
• Stream Cipher: Encrypts data one byte at a Cme, producing a keystream that is XORed
with the plaintext to create ciphertext.
• Key Size: Supports variable key lengths, typically ranging from 40 to 2048 bits, but
commonly used with 128-bit keys.
• Simplicity: The algorithm is relaCvely straighZorward, which allows for efficient
implementaCon.
Working Principle
1. Key Scheduling Algorithm (KSA):
o IniCalizes a permutaCon of all 256 possible byte values (0-255) using the
provided key.
o The key is repeated to fill the array of size 256, and the array is then scrambled
based on the key values.
2. Pseudo-Random GeneraCon Algorithm (PRGA):
o Generates a keystream from the permuted array.
o This keystream is XORed with the plaintext to produce ciphertext during
encrypCon and with ciphertext to recover plaintext during decrypCon.
CODE:
def encrypCon():
global S, key_list, pt, key_stream, cipher_text
print("Plain text : ", plain_text)
print("Key : ", key)
print("n : ", n)
23
print("S : ", S)
key_list = convert_to_decimal(key)
pt = convert_to_decimal(plain_text)
print("Plain text (in array form): ", pt)
KSA()
PRGA()
XOR()
def decrypCon():
global S, key_list, pt, key_stream, original_text
S, key_list, pt, key_stream = [], [], [], []
KSA()
24
PRGA()
do_XOR()
def KSA():
global S
j=0
N = len(S)
for i in range(N):
j = (j + S[i] + key_list[i]) % N
S[i], S[j] = S[j], S[i]
print(i, S)
def PRGA():
global S, key_stream
N = len(S)
i, j = 0, 0
for k in range(len(pt)):
i = (i + 1) % N
j = (j + S[i]) % N
S[i], S[j] = S[j], S[i]
print(k, S)
t = (S[i] + S[j]) % N
key_stream.append(S[t])
25
print("Key stream : ", key_stream)
def XOR():
global cipher_text
for i in range(len(pt)):
c = key_stream[i] ^ pt[i]
cipher_text.append(c)
def do_XOR():
global original_text
for i in range(len(cipher_text)):
p = key_stream[i] ^ cipher_text[i]
original_text.append(p)
def convert_to_decimal(input_str):
decimal_list = [int(input_str[i:i+n], 2) for i in range(0, len(input_str), n)]
return decimal_list
26
if __name__ == "__main__":
n=3
plain_text = "001010010010"
key = "101001000001"
S, key_list, pt, key_stream, cipher_text, original_text = [], [], [], [], [], []
encrypCon()
print("---------------------------------------------------------")
decrypCon()
OUTPUT:
Plain text : 001010010010
Key : 101001000001
n:3
S : [0, 1, 2, 3, 4, 5, 6, 7]
Plain text ( in array form ): [1, 2, 2, 2]
Key list : [5, 1, 0, 1, 5, 1, 0, 1]
0 [5, 1, 2, 3, 4, 0, 6, 7]
1 [5, 7, 2, 3, 4, 0, 6, 1]
2 [5, 2, 7, 3, 4, 0, 6, 1]
3 [5, 2, 7, 0, 4, 3, 6, 1]
4 [5, 2, 7, 0, 6, 3, 4, 1]
5 [5, 2, 3, 0, 6, 7, 4, 1]
6 [5, 2, 3, 0, 6, 7, 4, 1]
7 [1, 2, 3, 0, 6, 7, 4, 5]
The iniCal permutaCon array is : [1, 2, 3, 0, 6, 7, 4, 5]
0 [1, 3, 2, 0, 6, 7, 4, 5]
1 [1, 3, 6, 0, 2, 7, 4, 5]
2 [1, 3, 6, 2, 0, 7, 4, 5]
3 [1, 3, 6, 2, 0, 7, 4, 5]
27
Key stream : [7, 1, 6, 1]
Cipher text : 110011100011
---------------------------------------------------------
0 [5, 1, 2, 3, 4, 0, 6, 7]
1 [5, 7, 2, 3, 4, 0, 6, 1]
2 [5, 2, 7, 3, 4, 0, 6, 1]
3 [5, 2, 7, 0, 4, 3, 6, 1]
4 [5, 2, 7, 0, 6, 3, 4, 1]
5 [5, 2, 3, 0, 6, 7, 4, 1]
6 [5, 2, 3, 0, 6, 7, 4, 1]
7 [1, 2, 3, 0, 6, 7, 4, 5]
The iniCal permutaCon array is : [1, 2, 3, 0, 6, 7, 4, 5]
0 [1, 3, 2, 0, 6, 7, 4, 5]
1 [1, 3, 6, 0, 2, 7, 4, 5]
2 [1, 3, 6, 2, 0, 7, 4, 5]
3 [1, 3, 6, 2, 0, 7, 4, 5]
Key stream : [7, 1, 6, 1]
Decrypted text : 001010010010
28
EXPERIMENT-8
AIM: Write a Java program to implement RSA algorithm.
DESCRIPTION:
RSA (Rivest-Shamir-Adleman) is a widely used asymmetric encrypCon algorithm that relies on
the mathemaCcal properCes of prime numbers. Here’s a brief descripCon:
1. Key GeneraCon: RSA involves generaCng a pair of keys—a public key (used for
encrypCon) and a private key (used for decrypCon). The process includes:
o SelecCng two disCnct large prime numbers, p and q
o CompuCng n=p×q, which forms part of the public key.
o CalculaCng the toCent,ϕ(n)=(p−1)(q−1).
o Choosing a public exponent e (typically 65537) such that 1<e<ϕ(n) and e is
coprime to ϕ(n).
o CompuCng the private exponent d, which is the modular mulCplicaCve inverse
of emoduloϕ(n).
2. EncrypCon: To encrypt a message MMM:
o Convert the plaintext message to an integer mmm such that 0≤m<n.
o Compute the ciphertext ccc using the public key:
c=m^emodn
3. DecrypCon: To decrypt the ciphertext ccc:
o Use the private key to compute the original message mmm:
m=c^dmodn
o Convert the integer mmm back to plaintext.
CODE:
import math
from sympy import mod_inverse
29
def main():
p=3
q = 11
n=p*q
z = (p - 1) * (q - 1)
print("The value of z =", z)
msg = 12
print("Original message:", msg)
# EncrypCon
c = pow(msg, e, n)
print("Encrypted message is:", c)
30
# DecrypCon
msg_back = pow(c, d, n)
print("Decrypted message is:", msg_back)
if __name__ == "__main__":
main()
OUTPUT:
31