0% found this document useful (0 votes)
9 views38 pages

CyberSecurity Lab Programs

The document outlines three encryption methods: Caesar Cipher, Playfair Cipher, and Hill Cipher, providing both the logic and Java code for each. It details how to encrypt and decrypt messages using these ciphers, including the handling of input text and key matrices. Each cipher has specific rules for processing characters, constructing matrices, and managing input preparation.
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)
9 views38 pages

CyberSecurity Lab Programs

The document outlines three encryption methods: Caesar Cipher, Playfair Cipher, and Hill Cipher, providing both the logic and Java code for each. It details how to encrypt and decrypt messages using these ciphers, including the handling of input text and key matrices. Each cipher has specific rules for processing characters, constructing matrices, and managing input preparation.
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/ 38

CyberSecurity Lab Programs

Part-A
1. Caesar Cipher

Code:

import java.util.*;

class Caesar {

// Encrypts the plain text using Caesar cipher with the given key
public static String encrypt(String pt, int key) {
String ct = ""; // To store the ciphertext
String letters = "abcdefghijklmnopqrstuvwxyz"; // List of all lowercase alphabets

// Loop through each character of the plain text


for (int i = 0; i < pt.length(); i++) {
// Loop through each character in the alphabet to find a match
for (int j = 0; j < letters.length(); j++) {
// If the character matches, shift it by the key and append it to ciphertext
if (pt.charAt(i) == letters.charAt(j)) {
ct += letters.charAt((j + key) % 26); // Shift and wrap around using
modulo 26
break; // Exit the inner loop once a match is found
}
}
}
return ct; // Return the final ciphertext
}

// Decrypts the ciphertext using Caesar cipher with the given key
public static String decrypt(String ct, int key) {
String pt = ""; // To store the decrypted plaintext
String letters = "abcdefghijklmnopqrstuvwxyz"; // List of all lowercase alphabets

// Loop through each character of the ciphertext


for (int i = 0; i < ct.length(); i++) {
// Loop through each character in the alphabet to find a match
for (int j = 0; j < letters.length(); j++) {
// If the character matches, shift it backwards by the key and append to
plaintext
if (ct.charAt(i) == letters.charAt(j)) {
// If shifting goes out of bounds, wrap around using +26 to avoid
negative index
if (j - key < 0) {
pt += letters.charAt(j - key + 26); // Adjust when going below 'a'
} else {
pt += letters.charAt(j - key); // Regular shift
}
break; // Exit the loop once a match is found
}
}
}
return pt; // Return the final plaintext
}

// Main method to take user input and execute encryption or decryption


public static void main(String args[]) {
// Prompt the user for input text
System.out.print("Enter the input text: ");
Scanner scan = new Scanner(System.in);
String input = scan.nextLine(); // Read the input text

// Prompt the user for the key


System.out.print("Enter the key: ");
int key = scan.nextInt(); // Read the key

// Prompt the user to choose between encryption or decryption


System.out.print("\nEnter the operation: \n1. Encrypt\n2. Decrypt\nChoice: ");
int choice = scan.nextInt(); // Read the user's choice

String result; // To store the result (ciphertext or plaintext)

// Perform the chosen operation


switch (choice) {
case 1:
result = encrypt(input, key); // Call encrypt function if the choice is 1
System.out.print("\nCipher text: ");
System.out.println(result); // Output the encrypted text
break;
case 2:
result = decrypt(input, key); // Call decrypt function if the choice is 2
System.out.print("\nPlain text: ");
System.out.println(result); // Output the decrypted text
break;
default:
System.out.println("Enter valid choice!!"); // If the choice is invalid
}
}
}
2. Playfair Cipher

Logic:

Matrix Creation: A 5x5 matrix is constructed using the given key. The key is
inserted first, followed by the remaining letters of the alphabet (skipping 'J' since it's
treated as 'I').

Ignore 'J': The input is preprocessed to replace all occurrences of 'J' with 'I', as
the Playfair cipher does not distinguish between 'I' and 'J'.

Input Preparation: The input is processed to ensure it's in even length, inserting
'x' between repeated letters and appending 'x' if the length is odd.

Encryption/Decryption:
 Same Row: If the letters are in the same row, they are replaced by the letters
immediately to their right.

 Same Column: If the letters are in the same column, they are replaced by the
letters immediately below them.

 Rectangle: Otherwise, the letters are replaced by the letters on the same row but
in the column of the other letter.

Functions Used:

ignoreJ(String input):

 Purpose: This function replaces all occurrences of the letter 'J' in the input string
with 'I'. This is because the Playfair cipher treats 'I' and 'J' as the same letter in
the 5x5 matrix.

 Logic: It loops through each character of the input and checks if it is 'J'. If so, it
adds 'I' to the result string, otherwise, it adds the character itself.

createMatrix(String key):

 Purpose: This function creates a 5x5 matrix based on the provided key. The
matrix is filled with the letters from the key first, then the remaining letters of the
alphabet (skipping 'J').

 Logic: It first fills the matrix with characters from the key. Afterward, it checks for
duplicate characters in the key, and if a character is not present, it adds it to the
matrix. The matrix size is restricted to 5x5, so characters are skipped accordingly.
inputBuilder(String input):
 Purpose: This function prepares the input string for encryption by ensuring that
it's of even length. If two consecutive letters in the input are the same, it inserts 'x'
between them. If the input length is odd, it appends an 'x' at the end.

 Logic: It iterates through the input in pairs of characters. If a pair of characters


are identical, it inserts an 'x' between them. If the total length of the string is odd,
an 'x' is appended to make the length even.

encrypt(String input):
 Purpose: This function encrypts the input string using the Playfair cipher rules.

 Logic: The function processes the input in pairs of characters. For each pair, it
finds their positions in the matrix:

o If the characters are in the same row, it replaces them with the characters
to their right.
o If the characters are in the same column, it replaces them with the
characters below them.
o If the characters form a rectangle, it swaps the corners to generate the
cipher text.
decrypt(String input):

 Purpose: This function decrypts the ciphered string using the Playfair cipher
rules.
 Logic: It is similar to the encrypt function, but the characters are shifted in the
opposite direction:
o If the characters are in the same row, they are replaced with the
characters to their left.
o If the characters are in the same column, they are replaced with the
characters above them.

o If the characters form a rectangle, the corners are swapped in the


opposite direction to recover the original text.

Code:
import java.util.*;

class PlayFair {
// Define the alphabet (excluding 'j' as it is treated as 'i')
static String letters = "abcdefghijklmnopqrstuvwxyz";

// 5x5 matrix to store the Playfair cipher key


static char[][] matrix = new char[5][5];

// Method to ignore 'J' and treat it as 'I' in the input string


public static String ignoreJ(String input) {
String finalInput = "";

// Loop through each character in the input string


for (int i = 0; i < input.length(); i++) {
// If the character is 'j', replace it with 'i'
if (input.charAt(i) == 'j')
finalInput += 'i';
else
finalInput += input.charAt(i);
}
return finalInput;
}

// Method to create the Playfair cipher key matrix from the key
public static void createMatrix(String key) {
int counter = 0, letterCounter = 0;
boolean isPresent = false;

// Fill the matrix with the characters from the key


for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (counter < key.length()) {
matrix[i][j] = key.charAt(counter);
counter++;
} else {
// Check if a character from the alphabet is already in the key
isPresent = false;
if (letters.charAt(letterCounter) == 'j')
isPresent = true;
for (int k = 0; k < key.length(); k++) {
if (letters.charAt(letterCounter) == key.charAt(k)) {
isPresent = true;
}
}
// If the character is not present in the key, add it to the matrix
if (!isPresent) {
matrix[i][j] = letters.charAt(letterCounter);
} else {
// If the character is already present, stay at the current position
j--;
}
letterCounter++;
}
}
}
}

// Method to process the input string and handle double letters by adding 'x'
between them
public static String inputBuilder(String input) {
String finalString = "";

// Loop through the input string, check if consecutive characters are the same
for (int i = 0; i < input.length() - 1; i += 2) {
if (input.charAt(i) == input.charAt(i + 1))
// If consecutive characters are the same, add 'x' between them
finalString += input.charAt(i) + "x" + input.charAt(i + 1);
else
finalString += input.charAt(i) + "" + input.charAt(i + 1);
}

// If the input length is odd, add the last character with 'x' to make it even length
if (input.length() % 2 != 0)
finalString += input.charAt(input.length() - 1);

// If the resulting string has an odd length, append 'x' to make it even length
if (finalString.length() % 2 != 0)
finalString += "x";

return finalString;
}

// Method to encrypt the input string using the Playfair cipher


public static String encrypt(String input) {
String result = "";
int[] a = new int[2]; // Store coordinates of the first letter
int[] b = new int[2]; // Store coordinates of the second letter

// Process the input string in pairs of letters


for (int k = 0; k < input.length() - 1; k += 2) {
// Find the positions of the two letters in the matrix
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++) {
if (input.charAt(k) == matrix[i][j]) {
a[0] = i;
a[1] = j;
}
if (input.charAt(k + 1) == matrix[i][j]) {
b[0] = i;
b[1] = j;
}
}

// Apply Playfair cipher rules to encrypt the letters


if (a[0] == b[0])
// If both letters are in the same row, shift their positions to the right
result += matrix[a[0]][(a[1] + 1) % 5] + "" + matrix[b[0]][(b[1] + 1) % 5];
else if (a[1] == b[1])
// If both letters are in the same column, shift their positions down
result += matrix[(a[0] + 1) % 5][a[1]] + "" + matrix[(b[0] + 1) % 5][b[1]];
else
// Otherwise, form a rectangle, swapping the corners
result += matrix[a[0]][b[1]] + "" + matrix[b[0]][a[1]];
}

return result;
}

// Method to decrypt the input string using the Playfair cipher


public static String decrypt(String input) {
String result = "";
int[] a = new int[2]; // Store coordinates of the first letter
int[] b = new int[2]; // Store coordinates of the second letter

// Process the input string in pairs of letters


for (int k = 0; k < input.length() - 1; k += 2) {
// Find the positions of the two letters in the matrix
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++) {
if (input.charAt(k) == matrix[i][j]) {
a[0] = i;
a[1] = j;
}
if (input.charAt(k + 1) == matrix[i][j]) {
b[0] = i;
b[1] = j;
}
}

// Apply Playfair cipher rules to decrypt the letters


if (a[0] == b[0]) {
// If both letters are in the same row, shift their positions to the left
if (a[1] - 1 < 0)
result += matrix[a[0]][(a[1] - 1) + 5] + "";
else
result += matrix[a[0]][a[1] - 1] + "";
if (b[1] - 1 < 0)
result += matrix[b[0]][(b[1] - 1) + 5];
else
result += matrix[b[0]][b[1] - 1];
}
else if (a[1] == b[1]) {
// If both letters are in the same column, shift their positions up
if (a[0] - 1 < 0)
result += matrix[(a[0] - 1) + 5][a[1]] + "";
else
result += matrix[a[0] - 1][a[1]] + "";
if (b[0] - 1 < 0)
result += matrix[(b[0] - 1) + 5][b[1]];
else
result += matrix[b[0] - 1][b[1]];
}
else
// Otherwise, form a rectangle, swapping the corners
result += matrix[a[0]][b[1]] + "" + matrix[b[0]][a[1]];
}

return result;
}

// Main method to run the Playfair cipher program


public static void main(String args[]) {
Scanner scan = new Scanner(System.in);

// Prompt user for the key


System.out.print("Enter the key: ");
String key = scan.nextLine();

// Generate the Playfair cipher matrix using the provided key


createMatrix(key);

// Display the generated matrix for verification


for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++)
System.out.print(matrix[i][j] + "\t");
System.out.println("");
}

// Prompt user for the input message


System.out.print("Enter the input: ");
String inputString = scan.nextLine();

// Ignore 'j' and treat it as 'i'


inputString = ignoreJ(inputString);

// Prepare the input string for encryption or decryption


String passingString = inputBuilder(inputString);
System.out.println("Built String: " + passingString);

// Prompt user for the operation (Encrypt or Decrypt)


System.out.print("Enter operation:\n1.Encrypt\n2.Decrypt\nEnter the choice: ");
int choice = scan.nextInt();

String result;
switch (choice) {
case 1:
result = encrypt(passingString);
System.out.println("Cipher text: " + result);
break;
case 2:
result = decrypt(passingString);
System.out.println("Plain text: " + result);
break;
default:
System.out.println("Invalid choice!");
}
}
}
3. Hill Cipher (Akshit’s Alternative code)

Logic:

1. Input Phase
 The user inputs:

o A plaintext message (letters only, spaces removed, uppercase).

o A key matrix size (e.g., 2 or 3 for 2×2 or 3×3).

o The key matrix values (integers).

o A choice between encryption or decryption.

2. Processing the Text

 Padding: The code adds 'X' to the end of the text if its length isn't divisible by the
matrix size (to make full blocks).

 Block Processing:

o The text is broken into blocks (vectors) of size n.


o Each block is converted to numbers: A = 0, B = 1, ..., Z = 25.

3. Encryption Logic

 Multiply each block vector by the key matrix.

 Resulting vector values are taken mod 26, then converted back to letters.

4. Decryption Logic

 The inverse of the key matrix is computed using:

o Determinant of the matrix (det()).


o Modular inverse of the determinant (modInv()).

o Cofactors and adjugate to build the inverse matrix (inv()).

 Multiply ciphertext vectors by the inverse matrix to recover the original


message.

Functions Used:
✅ modInv(int a, int m)
🔍 Purpose:
Finds the modular inverse of a under modulo m.
🧠 Logic:
 Tries values from 1 to m-1.
 Returns x if (a * x) % m == 1, meaning it is the multiplicative inverse.
 If no such x exists, throws an error.

✅ det(int[][] m, int n)
🔍 Purpose:
Computes the determinant of matrix m of size n × n.
🧠 Logic:
 For 2x2 matrix: uses the basic formula:
(m[0][0] * m[1][1] - m[0][1] * m[1][0])
 For larger matrices: uses recursion and cofactor expansion along the first row.
 Always returns result % 26 to stay in the alphabet range.

✅ inv(int[][] k, int n)
🔍 Purpose:
Calculates the inverse of the key matrix under modulo 26.
🧠 Logic:
1. Finds determinant d of the matrix.
2. Finds modular inverse di of that determinant.
3. Uses cofactors and adjugate transpose to build inverse matrix.
4. Scales by di and applies % 26 to all values to complete the inversion.
📌 Key Concepts Used:
 Cofactor = signed minor of a matrix element.
 Adjugate = transpose of cofactor matrix.

✅ subMatrix(int[][] m, int r, int c, int n)


🔍 Purpose:
Returns the minor matrix of size (n-1) x (n-1) by removing row r and column c.
🧠 Logic:
 Used to calculate cofactors for determinant and inverse matrix.
 Skips the row and column specified.

✅ process(String m, int[][] k, int s, boolean enc)


🔍 Purpose:
Handles both encryption and decryption based on the enc flag.
🧠 Logic:
1. Pads message with 'X' to make length divisible by size s.
2. Splits message into blocks of size s.
3. Converts characters to numbers (A=0, ..., Z=25).
4. If enc == true, uses original matrix k;
else uses inverse matrix inv(k, s).
5. Multiplies each block vector by matrix.
6. Applies modulo 26 and converts numbers back to letters.

Code:

import java.util.Scanner;

public class HillCipher {


public static void main(String[] args) {
Scanner s = new Scanner(System.in);

// Take plaintext input, convert to uppercase and remove spaces


System.out.print("Text: ");
String text = s.nextLine().toUpperCase().replaceAll("\\s", "");

// Get size of key matrix (n x n)


System.out.print("Size: ");
int size = s.nextInt();
int key[][] = new int[size][size];

// Get key matrix values from user


System.out.println("Key: ");
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
key[i][j] = s.nextInt();

// Ask for operation choice: 1 = Encrypt, 2 = Decrypt


System.out.print("1. Encrypt 2. Decrypt: ");
int choice = s.nextInt();

// Process and display the result


System.out.println((choice == 1 ? "Encrypted: " : "Decrypted: ") +
process(text, key, size, choice == 1));
}

// Find modular inverse of a number under modulo 26


private static int modInv(int a, int m) {
for (int x = 1; x < m; x++)
if ((a * x) % m == 1)
return x;
throw new ArithmeticException("Modular inverse does not exist");
}

// Calculate determinant of matrix modulo 26 (works recursively for any n)


private static int det(int[][] m, int n) {
if (n == 2) // Base case for 2x2 matrix
return (m[0][0] * m[1][1] - m[0][1] * m[1][0]) % 26;
int d = 0;
for (int x = 0; x < n; x++)
d = (d + (x % 2 == 0 ? 1 : -1) * m[0][x] * det(subMatrix(m, 0, x, n), n - 1)) % 26;
return (d + 26) % 26; // Ensure positive determinant
}

// Compute inverse of a key matrix modulo 26


private static int[][] inv(int[][] k, int n) {
int d = det(k, n); // Determinant of key matrix
int di = modInv(d, 26); // Modular inverse of determinant
int[][] inv = new int[n][n]; // Inverse matrix to be filled

// Cofactor matrix, transpose (adjugate), multiply by modular inverse of determinant


for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
inv[j][i] = ((det(subMatrix(k, i, j, n), n - 1) *
(1 - 2 * ((i + j) % 2)) * di) % 26 + 26) % 26;
return inv;
}

// Get submatrix by removing row r and column c from an n x n matrix


private static int[][] subMatrix(int[][] m, int r, int c, int n) {
int[][] sub = new int[n - 1][n - 1];
for (int i = 0, si = 0; i < n; i++) {
if (i == r) continue;
for (int j = 0, sj = 0; j < n; j++) {
if (j != c)
sub[si][sj++] = m[i][j];
}
si++;
}
return sub;
}

// Core encryption/decryption function


private static String process(String m, int[][] k, int s, boolean enc) {
// Pad message with 'X' to make its length divisible by matrix size
while (m.length() % s != 0) m += 'X';
StringBuilder r = new StringBuilder();
int[][] keyMatrix = enc ? k : inv(k, s); // Use original or inverse key based on mode

// Process each block of size 's' (like vector multiplication)


for (int i = 0; i < m.length(); i += s) {
int[] v = new int[s]; // Character block as vector

// Convert block to numbers (A=0, B=1, ..., Z=25)


for (int j = 0; j < s; j++)
v[j] = m.charAt(i + j) - 'A';

// Matrix multiplication
for (int j = 0; j < s; j++) {
int sum = 0;
for (int l = 0; l < s; l++)
sum += v[l] * keyMatrix[l][j];

// Convert back to character and append


r.append((char) ((sum % 26 + 26) % 26 + 'A'));
}
}

return r.toString();
}
}
4. Vigenere Cipher

Logic:

1. Encryption Method: encrypt()


Convert to uppercase: Both text and key are converted to uppercase so that
encryption works only with capital letters (A–Z).
Loop through each character of text:
 For letters:
o Get the corresponding key letter using j % key.length().
o Convert key letter to a shift value: 'B' - 'A' = 1, 'C' - 'A' = 2, etc.
o Apply Caesar shift: (plaintext_char + shift) % 26.
o Append encrypted character.
o Increment j (key index) only if a letter is processed.
 For non-letter characters (punctuation, space, digits):
o Append them unchanged.

2. Decryption Method: decrypt()


 Same loop and key logic as encryption.
 But the shift is subtracted:
decryptedChar = (c - shift + 26) % 26
// +26 is used to avoid negative values.

Code:
import java.util.Scanner;
public class VigenereCipher {
public static String encrypt(String text, String key) {
StringBuilder result = new StringBuilder();
char c, encryptedChar;
int shift;
text = text.toUpperCase();
key = key.toUpperCase();

for (int i = 0, j = 0; i < text.length(); i++) {


c = text.charAt(i);
if (Character.isLetter(c)) {
shift = key.charAt(j % key.length()) - 'A';
encryptedChar = (char) ('A' + (c - 'A' + shift) % 26);
result.append(encryptedChar);
j++; // Only increment key index if we process a letter
} else {
result.append(c); // Keep non-letter characters unchanged
}
}
return result.toString();
}

public static String decrypt(String text, String key) {


StringBuilder result = new StringBuilder();
char c, decryptedChar;
int shift;
text = text.toUpperCase();
key = key.toUpperCase();

for (int i = 0, j = 0; i < text.length(); i++) {


c = text.charAt(i);
if (Character.isLetter(c)) {
shift = key.charAt(j % key.length()) - 'A';
decryptedChar = (char) ('A' + (c - 'A' - shift + 26) % 26);
result.append(decryptedChar);
j++; // Only increment key index if we process a letter
} else {
result.append(c); // Keep non-letter characters unchanged
}
}
return result.toString();
}

public static void main(String[] args) {


Scanner scanner = new Scanner(System.in);

System.out.print("Enter plaintext: ");


String plaintext = scanner.nextLine();
System.out.print("Enter key: ");
String key = scanner.nextLine();

String encryptedText = encrypt(plaintext, key);


System.out.println("Encrypted Text: " + encryptedText);
String decryptedText = decrypt(encryptedText, key);
System.out.println("Decrypted Text: " + decryptedText);

scanner.close();
}
}
5. Simplified DES

Logic:

🔑 1. Key Generation

Using a 10-bit key input:

1. P10 Permutation: Rearranges the 10 bits using P10.


2. Split into two 5-bit halves → left and right.

3. Left Shift 1 both halves.

4. P8 Permutation on the combined halves → gives k1 (first subkey).

5. Further Left Shift by 2 on both halves.

6. Apply P8 again → gives k2 (second subkey).


🔄 2. Encryption Process (Feistel Cipher Style)

Encryption uses two rounds with the process() method.


Step-by-step:

1. Initial Permutation (IP) on plaintext (8 bits).

2. Split into two halves: left and right (4 bits each).

3. Apply functionF() with k1:


o Expand right (4 → 8 bits) using EP.

o XOR with k1.

o Run through S-boxes S1 and S2 to substitute (8 → 4 bits).

o Permute with P4.


o XOR with left.

o Concatenate result with original right.

4. Swap halves, apply functionF() again with k2.

5. Apply Inverse IP (IP_INV) to get final 8-bit ciphertext.


Functions Used:

🧠 permute(String input, int[] permutation)

 Rearranges bits of input as per given array permutation.

🔄 leftShift(String input, int shifts)

 Circularly shifts a binary string to the left.

🔐 sBoxSubstitution(String input)

 Uses SBOX1 and SBOX2:

o Splits 8-bit input into two 4-bit halves.


o Converts to row/column index.
o Gets S-box value and returns a 4-bit output.

🔁 xor(String a, String b)

 Performs bitwise XOR of two binary strings.

🧠 functionF(left, right, key)

 Core logic of each round: expands, substitutes, permutes, and XORs.

Code:

import java.util.*;

public class SimpleDES {


private static final int[] P10 = {3, 5, 2, 7, 4, 10, 1, 9, 8, 6}; //{1,0,0,1,0,1} --> {0,}
private static final int[] P8 = {6, 3, 7, 4, 8, 5, 10, 9};
private static final int[] P4 = {2, 4, 3, 1};
private static final int[] IP = {2, 6, 3, 1, 4, 8, 5, 7};
private static final int[] IP_INV = {4, 1, 3, 5, 7, 2, 8, 6};
private static final int[] EP = {4, 1, 2, 3, 2, 3, 4, 1};

private static final int[][] SBOX1 = {{1, 0, 3, 2}, {3, 2, 1, 0}, {0, 2, 1, 3}, {3, 1, 0, 2}};
private static final int[][] SBOX2 = {{0, 1, 2, 3}, {2, 0, 1, 3}, {3, 0, 1, 0}, {2, 1, 0, 3}};

private static String key;


private static String k1, k2;

public static String sBoxSubstitution(String input) {


String leftPart = input.substring(0, 4); //1001 ---? row 11=3, col 00=0
String rightPart = input.substring(4, 8); //0101 ---? row 01=1, col 01=1

//parseInt(String s, int radix) returns the integer value of the string


representation of the second argument in the specified radix (base of the number in
the specified as the string).
int row = Integer.parseInt("" + leftPart.charAt(0) + leftPart.charAt(3), 2); //'1' +
'0' = "10" row = 2
int col = Integer.parseInt("" + leftPart.charAt(1) + leftPart.charAt(2), 2);
int sbox1Value = SBOX1[row][col];

row = Integer.parseInt("" + rightPart.charAt(0) + rightPart.charAt(3), 2);


col = Integer.parseInt("" + rightPart.charAt(1) + rightPart.charAt(2), 2);
int sbox2Value = SBOX2[row][col];

//format(String format, Object... args) returns a formatted string using the


specified format string and arguments.
//%2s: 2 characters wide, right-justified, space-padded i.e. " 1" or "10" or "11"
//replace() replaces all occurrences of the specified character with another
character.
String leftOutput = String.format("%2s",
Integer.toBinaryString(sbox1Value)).replace(' ', '0'); //1 --> "01" --> "01"
String rightOutput = String.format("%2s",
Integer.toBinaryString(sbox2Value)).replace(' ', '0');

return leftOutput + rightOutput;


}

public static String xor(String a, String b) {


StringBuilder result = new StringBuilder();
for (int i = 0; i < a.length(); i++) {
result.append(a.charAt(i) == b.charAt(i) ? '0' : '1'); //result += a.charAt(i) ==
b.charAt(i) ? '0' : '1';
}
return result.toString();
}

public static String functionF(String left, String right, String key) {


String expandedRight = permute(right, EP);
String xorResult = xor(expandedRight, key);
String sboxOutput = sBoxSubstitution(xorResult);
String p4Result = permute(sboxOutput, P4);
return xor(left, p4Result) + right;
}
public static String process(String text, String key1, String key2) {
String permIP = permute(text, IP);
String left = permIP.substring(0, 4);
String right = permIP.substring(4, 8);
String result = functionF(left, right, key1);
left = result.substring(0, 4);
right = result.substring(4, 8);
result = functionF(right, left, key2);
return permute(result, IP_INV);
}

public static String encrypt(String plaintext) {


return process(plaintext, k1, k2);
}

public static String leftShift(String input, int shifts) {


return input.substring(shifts) + input.substring(0, shifts); //"unhappy" -->
"nhappyu"
}

public static String permute(String input, int[] permutation) {


StringBuilder output = new StringBuilder();
for (int i = 0; i < permutation.length; i++) {
output.append(input.charAt(permutation[i] - 1)); //output +=
input.charAt(permutation[i] - 1);
}
return output.toString();
}

public static void generateKeys() {


String perm10 = permute(key, P10);
String left = perm10.substring(0, 5);
String right = perm10.substring(5, 10);
left = leftShift(left, 1);
right = leftShift(right, 1);
k1 = permute(left + right, P8);
left = leftShift(left, 2);
right = leftShift(right, 2);
k2 = permute(left + right, P8);
}

public static void main(String[] args) {


Scanner scanner = new Scanner(System.in);
System.out.print("Enter 10-bit key: ");
key = scanner.next();
generateKeys();

System.out.print("Enter 8-bit plaintext: ");


String plaintext = scanner.next();

String encrypted = encrypt(plaintext);


System.out.println("Encrypted: " + encrypted);

scanner.close();
}
}
Part-B

6. RSA

Logic:

1. Input Primes

 You input two prime numbers:


p and q.

2. Calculate n and phi


 n = p * q:
This is used as the modulus for both the public and private keys.

 phi = (p - 1) * (q - 1):
Euler's Totient Function — it gives the count of numbers less than n that are
coprime with n. It is used to calculate the keys.

3. Find Public Key e

 The code finds the smallest integer e such that:

o 1 < e < phi

o gcd(e, phi) == 1 (i.e. e is coprime to phi)


 This e is part of the public key:
Public Key = {e, n}

4. Find Private Key d

 The code tries every number from 1 to phi, and finds the first d such that:

o (d * e) % phi == 1

 This means d is the modular inverse of e modulo phi.

 This d is your private key:


Private Key = {d, n}
5. Encryption

 The user enters a message M (as a number).

 It is encrypted using the formula:


C = M^e mod n

6. Decryption
 The ciphertext C is decrypted using the private key with:
M = C^d mod n

Code:

import java.util.*;

public class RSA {

// GCD using Euclidean algorithm


public static long gcd(long a, long b) {
if (b == 0) return a;
return gcd(b, a % b);
}

// find modular inverse


public static long modInverse(long e, long phi) {
for (long x = 1; x < phi; x++) {
if ((x * e) % phi == 1) {
return x;
}
}
return -1; // No modular inverse found
}

// Simple modular exponentiation


private static long modExp(long base, long exp, long mod) {
long result = 1;

for (long i = 1; i < exp; i++) {


result = (result*base) % mod;
}
return result;
}

static void main(String args[]){


Scanner scan = new Scanner(System.in);
// Step 1: Choose small primes
System.out.print("Enter two prime numbers: ");
long p = scan.nextLong();
long q = scan.nextLong();
long n = p * q;
long phi = (p - 1) * (q - 1);

// Step 2: Choose e such that 1 < e < phi and gcd(e, phi) == 1
System.out.print("Enter value of e: ");
long e = scan.nextLong();

while (gcd(e, phi) != 1) {


System.out.println("e and phi are not coprime!");
System.out.print("Enter value of e coprime to "+phi+" : ");
e = scan.nextLong();
}

// Step 3: Calculate d (modular inverse of e mod phi)


long d = modInverse(e, phi);
if (d == -1) {
System.out.println("Modular inverse not found!");
return;
}

// Step 4: Message encryption and decryption


System.out.print("Enter the message (as a number): ");
long M = scan.nextLong();
long C = modExp(M, e, n);
long decrypted = modExp(C, d, n);

System.out.println("Cipher Text: " + C);


System.out.println("Decrypted Message: " + decrypted);

scan.close();
}
}
7. Diffie-Hellman Key Exchange

Logic:

1. Public Parameters (p and g)

 Input p: A large prime number.


 Input g: A primitive root modulo p (called the base).

 These two values are publicly shared and known to both Alice and Bob.

2. Private Keys

 Alice enters a private key a (called privateKeyA).

 Bob enters a private key b (called privateKeyB).

 These are kept secret and never shared.

3. Public Keys (to share over network)

Each party computes a public key using the formula:


Public Key = (g ^ privateKey) % p

 Alice computes A = (ga mod p) → shares A

 Bob computes B = (gb mod p) → shares B

These public keys can be safely shared even over insecure channels.

4. Shared Secret Key

Each party uses the other’s public key and their own private key to compute the same
shared secret:

 Alice computes:
K = (Ba mod p)
= (gb)a mod p
= gab mod p

 Bob computes:
K = (Ab mod p)
= (ga)b mod p
= gab mod p
So both get the same shared key without directly sending it.

5. Final Check

 If both parties compute the same shared key, the key exchange is successful.

Code:

import java.util.Scanner;

public class DiffieHellman {


public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);

// Step 1: Publicly Shared Prime (p) and Base (g)


System.out.print("Enter a prime number (p): ");
long p = scanner.nextLong();

System.out.print("Enter a base (g): ");


long g = scanner.nextLong();

// Step 2: Each User Inputs a Private Key


System.out.print("Enter private key for Alice: ");
long privateKeyA = scanner.nextLong();

System.out.print("Enter private key for Bob: ");


long privateKeyB = scanner.nextLong();

// Step 3: Compute Public Keys


long publicKeyA = modExp(g, privateKeyA, p);
long publicKeyB = modExp(g, privateKeyB, p);

System.out.println("Public Key of Alice: " + publicKeyA);


System.out.println("Public Key of Bob: " + publicKeyB);

// Step 4: Compute Shared Secret Key


long sharedSecretA = modExp(publicKeyB, privateKeyA, p);
long sharedSecretB = modExp(publicKeyA, privateKeyB, p);

System.out.println("Shared Secret Key computed by Alice: " + sharedSecretA);


System.out.println("Shared Secret Key computed by Bob: " + sharedSecretB);

// Both should be the same


if (sharedSecretA ==sharedSecretB) {
System.out.println("Key Exchange Successful! Shared Secret Key: " +
sharedSecretA);
} else {
System.out.println("Key Exchange Failed!");
}

scanner.close();
}

private static long modExp(long base, long exp, long mod) {


//In long to initialize a value to 1, we use long.ONE. Likewise for 0, we use
long.ZERO
long result = 1;

for (long i = 1; i < exp; i++) {


result = (result*base) % mod;
}
return result;
}
}
8. Elgamal Encryption

Logic:

1. Input a prime number q.

2. Input a number p that is relatively prime to q (they must not have common
factors other than 1).

3. Alice chooses her private key Xa, and her public key Ya = (pXa) % q is
generated.

4. A message M is encrypted into (C1, C2) using a randomly chosen number k and
the recipient’s public key Ya.

5. The message is decrypted using the private key and the modular inverse of a
calculated value.

Functions Used:

a. User defined:

Function Purpose

checkPrime(long) Checks if a number is prime

Calculates GCD (used to check if two numbers


gcd(long, long) are relatively prime)

genPubKey(long, long, Calculates the public key using (pXa) % q


long)
Encrypts a message and sets global values C1
Encryption(...) and C2

Decrypts the message using private key and


Decryption(...) modular inverse

modExp(long, long, Efficient (baseexp) % mod using binary


long) exponentiation
Code:

import java.util.*;

public class Elgamal {


static long C1 = 1;
static long C2 = 1;

public static void main(String args[]) {


Scanner scan = new Scanner(System.in);

// Step 1: Input a prime number q


System.out.println("Enter the prime value for q");
long q = scan.nextLong();
while (!checkPrime(q)) {
System.out.println("Enter the prime value for q");
q = scan.nextLong();
}

// Step 2: Input p which is relatively prime to q


System.out.println("Enter a value for p which is relatively prime to " + q);
long p = scan.nextLong();
while (gcd(p, q) != 1) {
System.out.println("Enter a value for p which is relatively prime to " + q);
p = scan.nextLong();
}

// Step 3: Input private key and calculate public key


System.out.println("Enter the private key of Alice");
long Xa = scan.nextLong();
long Ya = genPubKey(Xa, p, q);
System.out.println("Alice's private key is: " + Xa + " and public key is: " + Ya);

// Step 4: Input message to encrypt


System.out.println("Enter the message M which is less than " + (q - 1));
long M = scan.nextLong();

// Step 5: Encrypt and decrypt the message


Encryption(M, Ya, q, p);
Decryption(q, C1, C2, Xa);

scan.close();
}

// Function to check if a number is prime


public static boolean checkPrime(long num) {
for (long i = 2; i <= num / 2; i++) {
if (num % i == 0)
return false;
}
return true;
}

// Function to calculate GCD


public static long gcd(long a, long b) {
while (a != 0) {
long temp = b % a;
b = a;
a = temp;
}
return b;
}

// Function to generate public key (Y = px % q)


public static long genPubKey(long x, long p, long q) {
long Y = 1;
for (long i = 0; i < x; i++) {
Y = (Y * p) % q;
}
return Y;
}

// Function to encrypt a message


public static void Encryption(long M, long Y, long q, long p) {
Random r = new Random();
long k = r.nextInt((int)(q - 2)) + 1; // k in range [1, q-2]

System.out.println("Random value k is: " + k);

// K = (Y^k) % q
long K = modExp(Y, k, q);
System.out.println("Shared key K = " + K);

// C1 = (p^k) % q
C1 = modExp(p, k, q);

// C2 = (K * M) % q
C2 = (K * M) % q;

System.out.println("Encrypted values are C1 = " + C1 + ", C2 = " + C2);


}

// Function to decrypt the message


public static void Decryption(long q, long C1, long C2, long Xa) {
// K = (C1^Xa) % q
long K = 1;
for (long i = 0; i < Xa; i++) {
K = (K * C1) % q;
}

// Finding modular inverse of K using brute force


long kinverse = 1;
while ((K * kinverse) % q != 1) {
kinverse++;
}

// M = (C2 * K_inverse) % q
long M = (C2 * kinverse) % q;

System.out.println("Decrypted message is: " + M);


}

private static long modExp(long base, long exp, long mod) {


//In long to initialize a value to 1, we use long.ONE. Likewise for 0, we use
long.ZERO
long result = 1;

for (long i = 1; i < exp; i++) {


result = (result*base) % mod;
}
return result;
}
}
9. Secure Hash Algorithm (Same as Akshit’s version 2)

Code:

import java.util.Scanner;

public class SecureHash{


static int simpleHash(String input, int prime) {
int hash = 0;
for (char c : input.toCharArray())
hash = (hash * prime + c) % 1_000_000_007;
return Math.abs(hash);
}

public static void main(String[] args) {


Scanner sc = new Scanner(System.in);

System.out.print("Enter a small prime (e.g., 31): ");


int prime = sc.nextInt();
sc.nextLine(); // clear buffer

System.out.print("Enter message to hash: ");


String message = sc.nextLine();

int hashValue = simpleHash(message, prime);


System.out.println("Hashed value: " + hashValue);

sc.close();
}
}
10. Digital Signature (Same as Akshit’s only with functions)

Logic:

1. Choose two small prime numbers p and q.

o These primes are used to compute n = p × q, the modulus used in both


signing and verification.

o p = 17, q = 11 → n = 187

2. Compute Euler's Totient Function phi = (p-1)(q-1).


o phi = (17-1)(11-1) = 160

3. Choose a public key exponent e such that 1 < e < phi and gcd(e, phi) = 1.
o e = 7 is chosen and checked to be coprime with 160.

4. Compute the private key exponent d, the modular inverse of e mod phi.

o d is calculated using the Extended Euclidean Algorithm.

o d × e ≡ 1 mod phi

5. Hash the message using a simple custom hash function.


o This hash just sums the ASCII values of characters and takes modulo 97
(a small prime).
6. Create the digital signature.

o Signature = hashd mod n

o This is encrypting the hash with the private key, simulating a digital
signature.

7. Verification:

o The verifier computes sige mod n (i.e., decrypts the signature using the
public key).

o If the result matches the hash of the original message, the signature is
valid.

Functions Used:

 gcd(a, b): Finds GCD using Euclidean Algorithm.

 modInverse(e, phi): Finds modular inverse.


 modPow(base, exp, mod): Performs modular exponentiation efficiently (square-
and-multiply).

 simpleHash(message): Toy hash function just to simulate digital signing.

Code:

import java.util.*;

public class ManualDigitalSignature {

// Simple GCD
public static long gcd(long a, long b) {
while (b != 0) {
long tmp = b;
b = a % b;
a = tmp;
}
return a;
}

// find modular inverse


public static long modInverse(long e, long phi) {
for (long x = 1; x < phi; x++) {
if ((x * e) % phi == 1) {
return x;
}
}
return -1; // No modular inverse found
}

// Simple modular exponentiation


private static long modExp(long base, long exp, long mod) {
//In long to initialize a value to 1, we use long.ONE. Likewise for 0, we use
long.ZERO
long result = 1;

for (long i = 1; i < exp; i++) {


result = (result*base) % mod;
}
return result;
}

// Very simple hash function: sum of ASCII values modulo a prime


public static long simpleHash(String message) {
long hash = 0;
for (char c : message.toCharArray()) {
hash = (hash + c) % 97; // 97 is a small prime
}
return hash;
}

public static void main(String[] args) {


Scanner scan = new Scanner(System.in);
// Step 1: Choose small primes
System.out.print("Enter two prime numbers: ");
long p = scan.nextLong();
long q = scan.nextLong();
long n = p * q;
long phi = (p - 1) * (q - 1);

// Step 2: Choose e such that 1 < e < phi and gcd(e, phi) == 1
System.out.print("Enter value of e: ");
long e = scan.nextLong();

while (gcd(e, phi) != 1) {


System.out.println("e and phi are not coprime!");
System.out.print("Enter value of e coprime to "+phi+" : ");
e = scan.nextLong();
}

// Step 3: Calculate d (modular inverse of e mod phi)


long d = modInverse(e, phi);
if (d == -1) {
System.out.println("Modular inverse not found!");
return;
}

// Message
System.out.print("Enter your message: ");
String message = scan.next();

// Step 4: Hash the message


long hashed = simpleHash(message);

// Step 5: Create signature -> sig = hash^d mod n


long signature = modExp(hashed, d, n);
System.out.println("Signature: " + signature);

// Step 6: Verify -> hash' = sig^e mod n


long decryptedHash = modExp(signature, e, n);
long originalHash = simpleHash(message);

System.out.println("Decrypted Hash: " + decryptedHash);


System.out.println("Original Hash : " + originalHash);

if (decryptedHash == originalHash) {
System.out.println("✅ Signature verified successfully!");
} else {
System.out.println("❌ Signature verification failed!");
}
scan.close();
}
}

/*
Signature: 11
Decrypted Hash: 53
Original Hash : 53
✅ Signature verified successfully!

Signature: 63
Decrypted Hash: 87
Original Hash : 87
✅ Signature verified successfully!
*/

You might also like