You are on page 1of 63

Number Theory & Cryptography

Practical File

Vaibhav Meena : 2021UIT3074


Vibhav Goel : 2021UIT3082
Sharnam Kansal : 2021UIT3100
Aryan Nayar : 2021UIT3102
Branch: IT-2
Submitted to: Mr. Mohit Sajwan
INDEX

SNO EXPERIMENT DATE SIGN

1 Find the multiplicative inverse of a number using extended Euclidean


algorithm in modus n

2 Find the inverse of a matrix in modulus n.

3 Find the multiplicative inverse of a polynomial using extended


Euclidean algorithm in modus irreducible polynomial.

4 Implement the following traditional ciphers:


a) Shift Cipher
b) Multiplicative Cipher
c) Affine Cipher
d) Playfair Cipher
e) Hill Cipher
f) Vignere Ciphere
g) Rail fence—Row & column transformation

5 Implement the following algorithms:


a) DES
b) AES
c) RSA
d) ElGlgamal
e) Rabin
f) SHA-512

6 Implement the digital signature schemes: RSA and ElGlgamal.


Practical 1
Find the multiplicative inverse of a number using extended Euclidean
algorithm in modus n.
CODE
#include <bits/stdc++.h>
using namespace std;
int main(){
int n, b, r1, r2, t1, t2;
cout << "\n Enter n and b: \t";
cin >> n >> b;
r1 = n;
r2 = b;
t1 = 0;
t2 = 1;
int q, r, t;
cout << "\nq\tr1\t r2\t r\tt1\tt2\tt\t\n";
cout << "______________________________________________________\n";
while (r2 > 0){
q = float(r1) / r2;
int R1 = r1, R2 = r2, T1 = t1, T2 = t2;
r = r1 - q * r2;
r1 = r2;
r2 = r;
t = t1 - q * t2;
t1 = t2;
t2 = t;
cout << q << "\t" << R1 << "\t" << R2 << "\t" << r << "\t" << T1 << "\t" << T2 <<
"\t" << t << endl;
}
cout << q << "\t" << r1 << "\t" << r2 << "\t" << r << "\t" << t1 << "\t"<< t2 << "\t"
<< t << endl;
if (t1 < 0)
t1 += n;
if (r1 == 1)
cout << "\n Multiplicative Inverse Exist, it is " << t1 << endl;
else
cout << "\n Since GCD not equal to 1 hence Multiplicative Inverse does not exist."
<< endl;
}

OUTPUT:
Practical 2
Find the inverse of a matrix in modulo n.
CODE:
#include <bits/stdc++.h>
using namespace std;
#define N 4
int findInverseModulo(int b, int n)
{
int t1 = 0;
int t2 = 1;
int r1 = n;
int r2 = b;
while (r2 > 0)
{
int q = r1 / r2;
int r = r1 - q * r2;
int t = t1 - q * t2;
r1 = r2;
r2 = r;
t1 = t2;
t2 = t;
}
if (r1 == 1)
{
t1 = t1 < 0 ? t1 + n : t1;
return t1;
}
return -1;
}
void getCofactor(int A[N][N], int temp[N][N], int p, int q, int n)
{
int i = 0, j = 0;
for (int row = 0; row < n; row++)
{
for (int col = 0; col < n; col++)
{
if (row != p && col != q)
{
temp[i][j++] = A[row][col];
if (j == n - 1)
{
j = 0;
i++;
}
}
}
}
}
int determinant(int A[N][N], int n)
{
int D = 0;
if (n == 1)
return A[0][0];
int temp[N][N];
int sign = 1;
for (int f = 0; f < n; f++)
{
getCofactor(A, temp, 0, f, n);
D += sign * A[0][f] * determinant(temp, n - 1);
sign = -sign;
}
return D;
}
void adjoint(int A[N][N], int adj[N][N])
{
if (N == 1)
{
adj[0][0] = 1;
return;
}
int sign = 1, temp[N][N];
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
getCofactor(A, temp, i, j, N);
sign = ((i + j) % 2 == 0) ? 1 : -1;
adj[j][i] = (sign) * (determinant(temp, N - 1));
}
}
}
bool inverseMatrix(int A[N][N], int inverse[N][N], int r)
{
int det = determinant(A, N);
if (det == 0)
return false;
if (__gcd(det, r) != 1)
return false;
int detInverse = findInverseModulo(det, r);
int adj[N][N];
adjoint(A, adj);
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
{
inverse[i][j] = adj[i][j] * detInverse;
if (inverse[i][j] < 0)
{
int q = abs(inverse[i][j]) / r;
inverse[i][j] = inverse[i][j] + (q + 1) * r;
}
inverse[i][j] %= r;
}
return true;
}
void display(int A[N][N])
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
cout << A[i][j] << " ";
cout << endl;
}
}
int main()
{
int A[N][N] = {{3, 5, 7, 2},
{1, 4, 7, 2},
{6, 3, 9, 17},
{13, 5, 4, 16}};
int adj[N][N];
int inv[N][N];
cout << "Enter modulus n: ";
int r;
cin >> r;
cout << "Input matrix is :\n";
display(A);
cout << "\nThe Inverse is :\n";
if (inverseMatrix(A, inv, r))
display(inv);
return 0;
}

OUTPUT:
Practical 3
Find the multiplicative inverse of a polynomial using
extended Euclidean algorithm in modus irreducible
polynomial.
CODE:
#include <iostream>
#include <vector>
#include <sstream>
#include <string>
using namespace std;

vector<int> polydiv(vector<int> &a, vector<int> &b){


int m = a.size();
int n = b.size();
if (m < n)
return {0};
vector<int> q(m - n + 1, 0);
for (int i = m - n; i >= 0; --i){
int factor = a[i + n - 1] / b[n - 1];
q[i] = factor;
for (int j = 0; j < n; ++j)
{
a[i + j] -= b[j] * factor;
}
}
while (a.size() > 0 && a.back() == 0)
a.pop_back();
return a;
}

vector<int> polyadd(vector<int> &a, vector<int> &b)


{
int m = a.size();
int n = b.size();
int len = max(m, n);
vector<int> result(len, 0);
for (int i = 0; i < m; ++i)
result[i + (len - m)] = a[i];
for (int i = 0; i < n; ++i)
result[i + (len - n)] += b[i];
return result;
}

vector<int> polymul(vector<int> &a, vector<int> &b)


{
int m = a.size();
int n = b.size();
vector<int> result(m + n - 1, 0);
for (int i = 0; i < m; ++i)
{
for (int j = 0; j < n; ++j)
{
result[i + j] += a[i] * b[j];
}
}
return result;
}

pair<vector<int>, vector<int>> extended_gcd_poly(vector<int> &a, vector<int> &b,


vector<int> &irreducible_poly){
if (b == vector<int>{0}){
vector<int> one = {1};
return {vector<int>(a.begin(), a.end()), one};
}
auto qr = polydiv(a, b);
vector<int> q = qr;
vector<int> r = a;
for (int i = 0; i < qr.size(); ++i){
r[i] = qr[i];
}
auto gcd_x = extended_gcd_poly(b, r, irreducible_poly);
vector<int> gcd = gcd_x.first;
vector<int> x = gcd_x.second;

vector<int> x_poly = {0};


x_poly = polyadd(x_poly, x);
vector<int> q_x_poly = polymul(q, x_poly);
vector<int> result = polyadd(x, q_x_poly);

return {gcd, result};


}

vector<int> mod_inverse_poly(vector<int> &a, vector<int> &irreducible_poly)


{
auto aa_inverse = extended_gcd_poly(a, irreducible_poly, irreducible_poly);
vector<int> aa = aa_inverse.first;
vector<int> inverse = aa_inverse.second;
if (aa != vector<int>{1})
{
throw invalid_argument("The polynomial has no inverse modulo the irreducible
polynomial");
}
for (auto &coefficient : inverse)
{
coefficient = coefficient % irreducible_poly.back();
}
return inverse;
}

vector<int> parseInput(string input)


{
vector<int> result;
istringstream iss(input);
string token;
while (getline(iss, token, ' '))
{
result.push_back(stoi(token));
}
return result;
}

int main()
{
string irreducible_poly_str, a_str;
cout << "Enter the irreducible polynomial coefficients as a space-separated list
(e.g., 1 0 1 1): ";
getline(cin, irreducible_poly_str);
vector<int> irreducible_poly = parseInput(irreducible_poly_str);
cout << "Enter the polynomial coefficients for 'a' as a space-separated list (e.g., 1
0 1 0): ";
getline(cin, a_str);
vector<int> a = parseInput(a_str);
try
{
vector<int> inverse = mod_inverse_poly(a, irreducible_poly);
cout << "The multiplicative inverse is: ";
for (int i = 0; i < inverse.size(); i++)
{
cout << inverse[i] << " ";
}
cout << endl;
}
catch (const invalid_argument &e)
{
cout << e.what() << endl;
}
return 0;
}

OUTPUT:
Practical 4
Implement the following traditional ciphers:
● Shift Cipher
CODE:
#include <bits/stdc++.h>
using namespace std;
map<char, int> m;
int main()
{
for (char c = 'A'; c <= 'Z'; ++c)
{
m[c] = c - 'A';
}
string input;
cout << "Enter Msg:" cin >> input;
transform(input.begin(), input.end(), input.begin(), ::toupper);
int key;
cin >> key;
string crypt;
for (auto i : input)
{
cout << m[i] << " " << i << " , ";
crypt.push_back((m[i] + key) % 26 + 'A');
}
cout << endl<< crypt << endl;
string decrypt;
for (auto i : crypt)
{
decrypt.push_back(((m[i] - key) + 26) % 26 + 'A');
}
cout << decrypt << endl;
}
OUTPUT:
Multiplicative Cipher
CODE:
#include <bits/stdc++.h>
using namespace std;
int multi_inverse(int n, int a, int t1, int t2)
{
if (a == 0)
return (t1 + 26) % 26;
int q = n / a;
int r = n % a;
int t = t1 - q * t2;
return multi_inverse(a, r, t2, t);
}
map<char, int> m;
int main()
{
for (char c = 'A'; c <= 'Z'; ++c)
{
m[c] = c - 'A';
}
string input;
cin >> input;
int a, b;
cin >> a >> b;
string crypt;
for (auto i : input)
{
crypt.push_back((a * m[i] + b) % 26 + 'A');
}
int inverse = multi_inverse(26, a, 0, 1);
cout << inverse << endl;
cout << crypt << endl;
string decrypt;
for (auto i : crypt)
{
decrypt.push_back((((i - 'A' - b + 26)) * inverse + 26) % 26 + 'A');
}
cout << decrypt << endl;
}

OUTPUT:
Affine Cipher
CODE:
#include<bits/stdc++.h>
using namespace std;
static int a = 7;
static int b = 6;
string encryption(string m) {
//Cipher Text initially empty
string c = "";
for (int i = 0; i < m.length(); i++) {
// Avoid space to be encrypted
if(m[i]!=' ')
// added 'A' to bring it in range of ASCII alphabet [ 65-90 | A-Z ]
c = c + (char) ((((a * (m[i]-'A') ) + b) % 26) + 'A');
else
//else append space character
c += m[i];
}
return c;
}
string decryption(string c) {
string m = "";
int a_inverse = 0;
int flag = 0;
//Find a^-1 (the multiplicative inverse of a
//in the group of integers modulo m.)
for (int i = 0; i < 26; i++) {
flag = (a * i) % 26;
//Check if (a * i) % 26 == 1,
//then i will be the multiplicative inverse of a
if (flag == 1) {
a_inverse = i;
}
}
for (int i = 0; i < c.length(); i++) {
if(c[i] != ' ')
// added 'A' to bring it in range of ASCII alphabet [ 65-90 | A-Z ]
m = m + (char) (((a_inverse * ((c[i]+'A' - b)) % 26)) + 'A');
else
//else append space character
m += c[i];
}
return m;
}
int main(void) {
string msg = "TUTORIALSPOINT";
string c = encryption(msg);
cout << "Encrypted Message is : " << c<<endl;
cout << "Decrypted Message is: " << decryption(c);
return 0;
}

OUTPUT:

Playfair Cipher
CODE:
#include <bits/stdc++.h>
#define SIZE 30
using namespace std;
void toLowerCase(char plain[], int ps){
int i;
for (i = 0; i < ps; i++)
{
if (plain[i] > 64 && plain[i] < 91)
plain[i] += 32;
}
}
int removeSpaces(char *plain, int ps)
{
int i, count = 0;
for (i = 0; i < ps; i++)
if (plain[i] != ' ')
plain[count++] = plain[i];
plain[count] = '\0';
return count;
}
void generateKeyTable(char key[], int ks, char keyT[5][5])
{
int i, j, k, flag = 0, *dicty;
dicty = (int *)calloc(26, sizeof(int));
for (i = 0; i < ks; i++)
{
if (key[i] != 'j')
dicty[key[i] - 97] = 2;
}
dicty['j' - 97] = 1;
i = 0;
j = 0;
for (k = 0; k < ks; k++)
{
if (dicty[key[k] - 97] == 2)
{
dicty[key[k] - 97] -= 1;
keyT[i][j] = key[k];
j++;
if (j == 5)
{
i++;
j = 0;
}
}
}
for (k = 0; k < 26; k++)
{
if (dicty[k] == 0)
{
keyT[i][j] = (char)(k + 97);
j++;
if (j == 5)
{
i++;
j = 0;
}
}
}
cout << "\n Key :\n";
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
cout << keyT[i][j] << " ";
cout << endl;
}
}
void search(char keyT[5][5], char a, char b, int arr[])
{
int i, j;
if (a == 'j')
a = 'i';
else if (b == 'j')
b = 'i';
for (i = 0; i < 5; i++)
{
for (j = 0; j < 5; j++)
{
if (keyT[i][j] == a)
{
arr[0] = i;
arr[1] = j;
}
else if (keyT[i][j] == b)
{
arr[2] = i;
arr[3] = j;
}
}
}
}
int mod5(int a)
{
return (a % 5);
}
int prepare(char str[], int ptrs)
{
if (ptrs % 2 != 0)
{
str[ptrs++] = 'z';
str[ptrs] = '\0';
}
return ptrs;
}
void encrypt(char str[], char keyT[5][5], int ps)
{
int i, a[4];
for (i = 0; i < ps; i += 2)
{
search(keyT, str[i], str[i + 1], a);
if (a[0] == a[2])
{
str[i] = keyT[a[0]][mod5(a[1] + 1)];
str[i + 1] = keyT[a[0]][mod5(a[3] + 1)];
}
else if (a[1] == a[3])
{
str[i] = keyT[mod5(a[0] + 1)][a[1]];
str[i + 1] = keyT[mod5(a[2] + 1)][a[1]];
}
else
{
str[i] = keyT[a[0]][a[3]];
str[i + 1] = keyT[a[2]][a[1]];
}
}
}
void encryptByPlayfairCipher(char str[], char key[])
{
char ps, ks, keyT[5][5];
ks = strlen(key);
ks = removeSpaces(key, ks);
toLowerCase(key, ks);
ps = strlen(str);
toLowerCase(str, ps);
ps = removeSpaces(str, ps);
ps = prepare(str, ps);
generateKeyTable(key, ks, keyT);
encrypt(str, keyT, ps);
}
int main()
{
char str[SIZE], key[SIZE];
strcpy(key, "fruits");
printf("Key text: %s\n", key);
strcpy(str, "watermelon");
printf("Plain text: %s\n", str);
encryptByPlayfairCipher(str, key);
printf("Cipher text: %s\n", str);
return 0;
}

OUTPUT:
Hill Cipher
CODE:
#include <iostream>
using namespace std;
void getKeyMatrix(string key, int keyMatrix[][3])
{
int k = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
keyMatrix[i][j] = (key[k]) % 65;
k++;
}
}
}
void encrypt(int cipherMatrix[][1],
int keyMatrix[][3],
int messageVector[][1])
{
int x, i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 1; j++)
{
cipherMatrix[i][j] = 0;

for (x = 0; x < 3; x++)


{
cipherMatrix[i][j] +=
keyMatrix[i][x] * messageVector[x][j];
}
cipherMatrix[i][j] = cipherMatrix[i][j] % 26;
}
}
}
void HillCipher(string message, string key){
int keyMatrix[3][3];
getKeyMatrix(key, keyMatrix);
int messageVector[3][1];
for (int i = 0; i < 3; i++)
messageVector[i][0] = (message[i]) % 65;
int cipherMatrix[3][1];
encrypt(cipherMatrix, keyMatrix, messageVector);
string CipherText;
for (int i = 0; i < 3; i++)
CipherText += cipherMatrix[i][0] + 65;
cout << " Ciphertext:" << CipherText;
}
int main(){
string message;
cout<<"Enter message:";
cin>>message;
string key;
cout<<"Enter key:";
cin>>key;

HillCipher(message, key);

return 0;
}

OUTPUT:

Vignere Cipher
CODE:
#include <bits/stdc++.h>
using namespace std;
string generateKey(string str, string key)
{
int x = str.size();
for (int i = 0;; i++)
{
if (x == i)
i = 0;
if (key.size() == str.size())
break;
key.push_back(key[i]);
}
return key;
}
string cipherText(string str, string key)
{
string cipher_text;
for (int i = 0; i < str.size(); i++)
{
char x = (str[i] + key[i]) % 26;
x += 'A';
cipher_text.push_back(x);
}
return cipher_text;
}
string originalText(string cipher_text, string key)
{
string orig_text;
for (int i = 0; i < cipher_text.size(); i++)
{
char x = (cipher_text[i] - key[i] + 26) % 26;
x += 'A';
orig_text.push_back(x);
}
return orig_text;
}
int main()
{
string str = "NUMBERTHEORY";
string keyword = "APPLE";
string key = generateKey(str, keyword);
string cipher_text = cipherText(str, key);
cout << "Plaintext : "<< str << "\n";
cout << "key : "<< keyword << "\n";
cout << "Ciphertext : "<< cipher_text << "\n";
cout << "Decrypted Text : "<< originalText(cipher_text, key);
return 0;
}
OUTPUT:

Rail fence—Row & column transformation Cipher


CODE:
#include <bits/stdc++.h>
using namespace std;
string encryptRailFence(string text, int key)
{
char rail[key][(text.length())];
for (int i = 0; i < key; i++)
for (int j = 0; j < text.length(); j++)
rail[i][j] = '\n';
bool dir_down = false;
int row = 0, col = 0;
for (int i = 0; i < text.length(); i++)
{
if (row == 0 || row == key - 1)
dir_down = !dir_down;
rail[row][col++] = text[i];
dir_down ? row++ : row--;
}
string result;
for (int i = 0; i < key; i++)
for (int j = 0; j < text.length(); j++)
if (rail[i][j] != '\n')
result.push_back(rail[i][j]);
return result;
}
string decryptRailFence(string cipher, int key)
{
char rail[key][cipher.length()];
for (int i = 0; i < key; i++)
for (int j = 0; j < cipher.length(); j++)
rail[i][j] = '\n';
bool dir_down;
int row = 0, col = 0;
for (int i = 0; i < cipher.length(); i++)
{
if (row == 0)
dir_down = true;
if (row == key - 1)
dir_down = false;
rail[row][col++] = '*';
dir_down ? row++ : row--;
}
int index = 0;
for (int i = 0; i < key; i++)
for (int j = 0; j < cipher.length(); j++)
if (rail[i][j] == '*' && index < cipher.length())
rail[i][j] = cipher[index++];
string result;
row = 0, col = 0;
for (int i = 0; i < cipher.length(); i++)
{
if (row == 0)
dir_down = true;
if (row == key - 1)
dir_down = false;
if (rail[row][col] != '*')
result.push_back(rail[row][col++]);
dir_down ? row++ : row--;
}
return result;
}
int main()
{
string text = "meet me at the park", cipher;
int key = 2;
cout << "\nPlain text: " << text;
cipher = encryptRailFence(text, key);
cout << "\nCipher text: " << cipher << endl;
cout << "\nDeciphered text: " << decryptRailFence(cipher, key) << endl;
return 0;
}

OUTPUT:

Practical 5
Implement the following algorithms:
DES
CODE:
#include <bits/stdc++.h>
using namespace std;
string hex2bin(string s)
{
// hexadecimal to binary conversion
unordered_map<char, string> mp;
mp['0'] = "0000";
mp['1'] = "0001";
mp['2'] = "0010";
mp['3'] = "0011";
mp['4'] = "0100";
mp['5'] = "0101";
mp['6'] = "0110";
mp['7'] = "0111";
mp['8'] = "1000";
mp['9'] = "1001";
mp['A'] = "1010";
mp['B'] = "1011";
mp['C'] = "1100";
mp['D'] = "1101";
mp['E'] = "1110";
mp['F'] = "1111";
string bin = "";
for (int i = 0; i < s.size(); i++)
{
bin += mp[s[i]];
}
return bin;
}
string bin2hex(string s)
{
// binary to hexadecimal conversion
unordered_map<string, string> mp;
mp["0000"] = "0";
mp["0001"] = "1";
mp["0010"] = "2";
mp["0011"] = "3";
mp["0100"] = "4";
mp["0101"] = "5";
mp["0110"] = "6";
mp["0111"] = "7";
mp["1000"] = "8";
mp["1001"] = "9";
mp["1010"] = "A";
mp["1011"] = "B";
mp["1100"] = "C";
mp["1101"] = "D";
mp["1110"] = "E";
mp["1111"] = "F";
string hex = "";
for (int i = 0; i < s.length(); i += 4)
{
string ch = "";
ch += s[i];
ch += s[i + 1];
ch += s[i + 2];
ch += s[i + 3];
hex += mp[ch];
}
return hex;
}
string permute(string k, int *arr, int n)
{
string per = "";
for (int i = 0; i < n; i++)
{
per += k[arr[i] - 1];
}
return per;
}
string shift_left(string k, int shifts)
{
string s = "";
for (int i = 0; i < shifts; i++)
{
for (int j = 1; j < 28; j++)
{
s += k[j];
}
s += k[0];
k = s;
s = "";
}
return k;
}
string xor_(string a, string b)
{
string ans = "";
for (int i = 0; i < a.size(); i++)
{
if (a[i] == b[i])
{
ans += "0";
}
else
{
ans += "1";
}
}
return ans;
}
string encrypt(string pt, vector<string> rkb, vector<string> rk)
{
// Hexadecimal to binary
pt = hex2bin(pt);
// Initial Permutation Table
int initial_perm[64] = {58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7};
// Initial Permutation
pt = permute(pt, initial_perm, 64);
cout << "After initial permutation: " << bin2hex(pt) << endl;
// Splitting
string left = pt.substr(0, 32);
string right = pt.substr(32, 32);
cout << "After splitting: L0=" << bin2hex(left)
<< " R0=" << bin2hex(right) << endl;
// Expansion D-box Table
int exp_d[48] = {32, 1, 2, 3, 4, 5, 4, 5,
6, 7, 8, 9, 8, 9, 10, 11,
12, 13, 12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21, 20, 21,
22, 23, 24, 25, 24, 25, 26, 27,
28, 29, 28, 29, 30, 31, 32, 1};
int s[8][4][16] = {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0,
7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3,
8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5,
0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6,
13},
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5,
10,
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11,
5,
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2,
15,
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14,
9},
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2,
8,
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15,
1,
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14,
7,
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2,
12},
{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4,
15,
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14,
9,
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8,
4,
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2,
14},
{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14,
9,
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8,
6,
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0,
14,
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5,
3},
{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5,
11,
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3,
8,
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11,
6,
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8,
13},
{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6,
1,
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8,
6,
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9,
2,
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3,
12},
{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12,
7,
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9,
2,
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5,
8,
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6,
11}};
// Straight Permutation Table
int per[32] = {16, 7, 20, 21,
29, 12, 28, 17,
1, 15, 23, 26,
5, 18, 31, 10,
2, 8, 24, 14,
32, 27, 3, 9,
19, 13, 30, 6,
22, 11, 4, 25};
cout << endl;
for (int i = 0; i < 16; i++)
{
// Expansion D-box
string right_expanded = permute(right, exp_d, 48);
// XOR RoundKey[i] and right_expanded
string x = xor_(rkb[i], right_expanded);
// S-boxes
string op = "";
for (int i = 0; i < 8; i++)
{
int row = 2 * int(x[i * 6] - '0') + int(x[i * 6 + 5] - '0');
int col = 8 * int(x[i * 6 + 1] - '0') + 4 * int(x[i * 6 + 2] -
'0') + 2 * int(x[i * 6 + 3] - '0') + int(x[i * 6 + 4] - '0');
int val = s[i][row][col];
op += char(val / 8 + '0');
val = val % 8;
op += char(val / 4 + '0');
val = val % 4;
op += char(val / 2 + '0');
val = val % 2;
op += char(val + '0');
}
// Straight D-box
op = permute(op, per, 32);
// XOR left and op
x = xor_(op, left);
left = x;
// Swapper
if (i != 15)
{
swap(left, right);
}
cout << "Round " << i + 1 << " " << bin2hex(left) << " "
<< bin2hex(right) << " " << rk[i] << endl;
}
// Combination
string combine = left + right;
// Final Permutation Table
int final_perm[64] = {40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25};
// Final Permutation
string cipher = bin2hex(permute(combine, final_perm, 64));
return cipher;
}
int main()
{
// pt is plain text
string pt, key;
/*cout<<"Enter plain text(in hexadecimal): ";
cin>>pt;
cout<<"Enter key(in hexadecimal): ";
cin>>key;*/
pt = "123456ABCD132536";
key = "AABB09182736CCDD";
// Key Generation
// Hex to binary
key = hex2bin(key);
// Parity bit drop table
int keyp[56] = {57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4};
// getting 56 bit key from 64 bit using the parity bits
key = permute(key, keyp, 56); // key without parity
// Number of bit shifts
int shift_table[16] = {1, 1, 2, 2,
2, 2, 2, 2,
1, 2, 2, 2,
2, 2, 2, 1};
// Key- Compression Table
int key_comp[48] = {14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32};
// Splitting
string left = key.substr(0, 28);
string right = key.substr(28, 28);
vector<string> rkb; // rkb for RoundKeys in binary
vector<string> rk; // rk for RoundKeys in hexadecimal
for (int i = 0; i < 16; i++)
{
// Shifting
left = shift_left(left, shift_table[i]);
right = shift_left(right, shift_table[i]);
// Combining
string combine = left + right;
// Key Compression
string RoundKey = permute(combine, key_comp, 48);
rkb.push_back(RoundKey);
rk.push_back(bin2hex(RoundKey));
}
cout << "\nEncryption:\n\n";
string cipher = encrypt(pt, rkb, rk);
cout << "\nCipher Text: " << cipher << endl;
cout << "\nDecryption\n\n";
reverse(rkb.begin(), rkb.end());
reverse(rk.begin(), rk.end());
string text = encrypt(cipher, rkb, rk);
cout << "\nPlain Text: " << text << endl;
}

OUTPUT:
AES
CODE:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
#define Nb 4
int Nr = 0;
int Nk = 0;
// in - the array that holds the plain text to be encrypted.
// out - the array that holds the cipher text.
// state - the array that holds the intermediate results during encryption.
unsigned char in[1024], out[1024], state[4][Nb];
// The array that stores the round keys.
unsigned char RoundKey[240];
// The Key input to the AES Program
unsigned char Key[32];
int getSBoxValue(int num)
{
int sbox[256] = {
// 0 1 2 3 4 5 6 7
// 8 9 A B C D E F
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, // 0
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, // 1
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, // 2
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, // 3
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, // 4
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, // 5
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, // 6
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, // 7
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, // 8
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, // 9
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, // A
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, // B
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, // C
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, // D
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, // E
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; // F
return sbox[num];
}
// The round constant word array, Rcon[i], contains the values given by
// x to the power (i-1) being powers of x (x is denoted as {02}) in the
// field GF(28). Note that i starts at 1, not 0).
int Rcon[255] = {
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91,
0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d,
0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa,
0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66,
0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d,
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f,
0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a,
0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74,
0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab,
0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97,
0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2,
0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83,
0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,
0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3,
0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33,
0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb};
// This function produces Nb(Nr+1) round keys. The round keys are used in
// each round to encrypt the states.
void KeyExpansion()
{
int i, j;
unsigned char temp[4], k;
// The first round key is the key itself.
for (i = 0; i < Nk; i++)
{
RoundKey[i * 4] = Key[i * 4];
RoundKey[i * 4 + 1] = Key[i * 4 + 1];
RoundKey[i * 4 + 2] = Key[i * 4 + 2];
RoundKey[i * 4 + 3] = Key[i * 4 + 3];
}
// All other round keys are found from the previous round keys.
while (i < (Nb * (Nr + 1)))
{
for (j = 0; j < 4; j++)
{
temp[j] = RoundKey[(i - 1) * 4 + j];
}
if (i % Nk == 0)
{
// This function rotates the 4 bytes in a word to the left once.
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
// Function RotWord()
k = temp[0];
temp[0] = temp[1];
temp[1] = temp[2];
temp[2] = temp[3];
temp[3] = k;
// SubWord() is a function that takes a four-byte input word and
// applies the S-box to each of the four bytes to produce an
output
// word.
// Function Subword()
temp[0] = getSBoxValue(temp[0]);
temp[1] = getSBoxValue(temp[1]);
temp[2] = getSBoxValue(temp[2]);
temp[3] = getSBoxValue(temp[3]);
temp[0] = temp[0] ^ Rcon[i / Nk];
}
else if (Nk > 6 && i % Nk == 4)
{
// Function Subword()
temp[0] = getSBoxValue(temp[0]);
temp[1] = getSBoxValue(temp[1]);
temp[2] = getSBoxValue(temp[2]);
temp[3] = getSBoxValue(temp[3]);
}
RoundKey[i * 4 + 0] = RoundKey[(i - Nk) * 4 + 0] ^ temp[0];
RoundKey[i * 4 + 1] = RoundKey[(i - Nk) * 4 + 1] ^ temp[1];
RoundKey[i * 4 + 2] = RoundKey[(i - Nk) * 4 + 2] ^ temp[2];
RoundKey[i * 4 + 3] = RoundKey[(i - Nk) * 4 + 3] ^ temp[3];
i++;
}
}
// This function adds the round key to state.
// The round key is added to the state by an XOR function.
void AddRoundKey(int round)
{
int i, j;
for (i = 0; i < Nb; i++)
{
for (j = 0; j < 4; j++)
{
state[j][i] ^= RoundKey[round * Nb * 4 + i * Nb + j];
}
}
}
// The SubBytes Function Substitutes the values in the
// state matrix with values in an S-box.
void SubBytes()
{
int i, j;
for (i = 0; i < 4; i++)
{
for (j = 0; j < Nb; j++)
{
state[i][j] = getSBoxValue(state[i][j]);
}
}
}
// The ShiftRows() function shifts the rows in the state to the left.
// Each row is shifted with different offset.
// Offset = Row number. So the first row is not shifted.
void ShiftRows()
{
unsigned char temp;
// Rotate first row 1 columns to left
temp = state[1][0];
state[1][0] = state[1][1];
state[1][1] = state[1][2];
state[1][2] = state[1][3];
state[1][3] = temp;
// Rotate second row 2 columns to left
temp = state[2][0];
state[2][0] = state[2][2];
state[2][2] = temp;
temp = state[2][1];
state[2][1] = state[2][3];
state[2][3] = temp;
// Rotate third row 3 columns to left
temp = state[3][0];
state[3][0] = state[3][3];
state[3][3] = state[3][2];
state[3][2] = state[3][1];
state[3][1] = temp;
}
// xtime is a macro that finds the product of {02} and the argument to
// xtime modulo {1b}
#define xtime(x) ((x << 1) ^ (((x >> 7) & 1) * 0x1b))
// MixColumns function mixes the columns of the state matrix
void MixColumns()
{
int i;
unsigned char Tmp, Tm, t;
for (i = 0; i < Nb; i++)
{
t = state[0][i];
Tmp = state[0][i] ^ state[1][i] ^ state[2][i] ^ state[3][i];
Tm = state[0][i] ^ state[1][i];
Tm = xtime(Tm);
state[0][i] ^= Tm ^ Tmp;
Tm = state[1][i] ^ state[2][i];
Tm = xtime(Tm);
state[1][i] ^= Tm ^ Tmp;
Tm = state[2][i] ^ state[3][i];
Tm = xtime(Tm);
state[2][i] ^= Tm ^ Tmp;
Tm = state[3][i] ^ t;
Tm = xtime(Tm);
state[3][i] ^= Tm ^ Tmp;
}
}
// Cipher is the main function that encrypts the PlainText.
void Cipher()
{
int i, j, round = 0;
// Copy the input PlainText to state array.
for (i = 0; i < Nb; i++)
{
for (j = 0; j < 4; j++)
{
state[j][i] = in[i * 4 + j];
}
}
// Add the First round key to the state before starting the rounds.
AddRoundKey(0);
// There will be Nr rounds.
// The first Nr-1 rounds are identical.
// These Nr-1 rounds are executed in the loop below.
for (round = 1; round < Nr; round++)
{
SubBytes();
ShiftRows();
MixColumns();
AddRoundKey(round);
}
// The last round is given below.
// The MixColumns function is not here in the last round.
SubBytes();
ShiftRows();
AddRoundKey(Nr);
// The encryption process is over.
// Copy the state array to output array.
for (i = 0; i < Nb; i++)
{
for (j = 0; j < 4; j++)
{
out[i * 4 + j] = state[j][i];
}
}
}
int fillBlock(int sz, char *str, unsigned char *in)
{
int j = 0;
while (sz < strlen(str))
{
if (j >= Nb * 4)
break;
in[j++] = (unsigned char)str[sz];
sz++;
}
// Pad the block with 0s, if necessary
if (sz >= strlen(str))
for (; j < Nb * 4; j++)
in[j] = 0;
return sz;
}
int main(int argc, char **argv)
{
int i;
int argc;
if (argc != 2)
{
cerr << "Usage: " << argv[0] << " <keysize: 1=128, 2=192, 3=256>\n";
exit(0);
}
switch (atoi(argv[1]))
{
case 1:
Nk = 4;
break;
case 2:
Nk = 6;
break;
case 3:
Nk = 8;
break;
default:
Nk = 4;
break;
}
// Calculate Nr from Nk and, implicitly, from Nb
Nr = Nk + 6;
// The key values are placed here
Key[0] = 0x2b;
Key[1] = 0x7e;
Key[2] = 0x15;
Key[3] = 0x16;
Key[4] = 0x28;
Key[5] = 0xae;
Key[6] = 0xd2;
Key[7] = 0xa6;
Key[8] = 0xab;
Key[9] = 0xf7;
Key[10] = 0x15;
Key[11] = 0x88;
Key[12] = 0x09;
Key[13] = 0xcf;
Key[14] = 0x4f;
Key[15] = 0x3c;
// Get the input string
char str[1024];
fgets(str, 1024, stdin);
// The KeyExpansion routine is called before encryption.
KeyExpansion();
// sz is the cursor into the input string
int sz = 0;
// Each iteration encrypts one block = Nb*4 bytes = 128 bits in this case
while (sz < strlen(str))
{
// Fill the array 'in' with the next plaintext block
sz = fillBlock(sz, str, in);
// The block is encrypted here - the result is in the array 'out'
Cipher();
// Output the encrypted block.
for (i = 0; i < Nb * 4; i++)
cout << (int)out[i] << " ";
}
printf("\n\n");
}

OUTPUT:
RSA
CODE:
#include <iostream>
#include <math.h>
using namespace std;
int gcd(int a, int h)
{
int temp;
while (1)
{
temp = a % h;
if (temp == 0)
return h;
a = h;
h = temp;
}
}
int main()
{
double p = 3;
double q = 7;
double n = p * q;
double count;
double totient = (p - 1) * (q - 1);
double e = 2;
while (e < totient)
{
count = gcd(e, totient);
if (count == 1)
break;
else
e++;
}
double d;
double k = 2;
d = (1 + (k * totient)) / e;
double msg = 12;
double c = pow(msg, e);
double m = pow(c, d);
c = fmod(c, n);
m = fmod(m, n);
cout << "Message data = " << msg;
cout << "\n"
<< "p = " << p;
cout << "\n"
<< "q = " << q;
cout << "\n"
<< "n = pq = " << n;
cout << "\n"
<< "totient = " << totient;
cout << "\n"
<< "e = " << e;
cout << "\n"
<< "d = " << d;
cout << "\n"
<< "Encrypted data = " << c;
cout << "\n"
<< "Original Message sent = " << m;
return 0;
}
OUTPUT:

ElGamel
CODE:
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cmath>

using namespace std;

// Function to calculate the greatest common divisor


int gcd(int a, int b) {
if (a < b) {
return gcd(b, a);
} else if (a % b == 0) {
return b;
} else {
return gcd(b, a % b);
}
}

// Function to generate a random key


long long int gen_key(long long int q) {
long long int key = rand() % q + pow(10, 20);
while (gcd(q, key) != 1) {
key = rand() % q + pow(10, 20);
}
return key;
}
// Function for modular exponentiation
long long int power(long long int a, long long int b, long long int c) {
long long int x = 1;
long long int y = a;

while (b > 0) {
if (b % 2 != 0) {
x = (x * y) % c;
}
y = (y * y) % c;
b = b / 2;
}

return x % c;
}

// Function for asymmetric encryption


pair<vector<long long int>, long long int> encrypt(string msg, long long int q, long long
int h, long long int g) {
vector<long long int> en_msg;
long long int k = gen_key(q); // Private key for sender
long long int s = power(h, k, q);
long long int p = power(g, k, q);

for (int i = 0; i < msg.length(); i++) {


en_msg.push_back(msg[i]);
}

cout << "g^k used: " << p << endl;


cout << "g^ak used: " << s << endl;

for (int i = 0; i < en_msg.size(); i++) {


en_msg[i] = s * int(en_msg[i]);
}

return make_pair(en_msg, p);


}

// Function to decrypt the message


string decrypt(vector<long long int> en_msg, long long int p, long long int key, long long
int q) {
vector<char> dr_msg;
long long int h = power(p, key, q);

for (int i = 0; i < en_msg.size(); i++) {


dr_msg.push_back(char(en_msg[i] / h));
}

string decrypted_msg(dr_msg.begin(), dr_msg.end());


return decrypted_msg;
}

// Driver code
int main() {
srand(time(0));

string msg = "encryption";


cout << "Original Message: " << msg << endl;

long long int q = rand() % int(pow(10, 50)) + pow(10, 20);


long long int g = int(rand()) % q + 2;

long long int key = gen_key(q); // Private key for receiver


long long int h = power(g, key, q);
cout << "g used: " << g << endl;
cout << "g^a used: " << h << endl;

pair<vector<long long int>, long long int> encrypted = encrypt(msg, q, h, g);


vector<long long int> en_msg = encrypted.first;
long long int p = encrypted.second;
string dmsg = decrypt(en_msg, p, key, q);

cout << "Decrypted Message: " << dmsg << endl;

return 0;
}

OUTPUT:

Rabin
CODE:
#include <iostream>
#include <vector>
#include <random>
#include <string>
#include <cstring>
#include <sstream>
#include <iomanip>

using namespace std;

class Cryptography {
private:
static random_device r;
static mt19937_64 gen;
static uniform_int_distribution<long long> dis;
static const long long TWO = 2;
static const long long THREE = 3;
static const long long FOUR = 4;

static vector<long long> Gcd(long long a, long long b) {


long long s = 0;
long long old_s = 1;
long long t = 1;
long long old_t = 0;
long long r = b;
long long old_r = a;

while (r != 0) {
long long q = old_r / r;
long long tr = r;
r = old_r - q * r;
old_r = tr;

long long ts = s;
s = old_s - q * s;
old_s = ts;

long long tt = t;
t = old_t - q * t;
old_t = tt;
}

vector<long long> result{old_r, old_s, old_t};


return result;
}

public:
static vector<long long> generateKey(int bitLength) {
long long p = blumPrime(bitLength / 2);
long long q = blumPrime(bitLength / 2);
long long N = p * q;
return vector<long long>{N, p, q};
}

static long long encrypt(long long m, long long N) {


return (m * m) % N;
}
static vector<long long> decrypt(long long c, long long p, long long q) {
long long N = p * q;
long long p1 = pow(c, (p + 1) / FOUR);
long long p2 = p - p1;
long long q1 = pow(c, (q + 1) / FOUR);
long long q2 = q - q1;

vector<long long> ext = Gcd(p, q);


long long y_p = ext[1];
long long y_q = ext[2];

long long d1 = (y_p * p * q1 + y_q * q * p1) % N;


long long d2 = (y_p * p * q2 + y_q * q * p1) % N;
long long d3 = (y_p * p * q1 + y_q * q * p2) % N;
long long d4 = (y_p * p * q2 + y_q * q * p2) % N;

return vector<long long>{d1, d2, d3, d4};


}

static long long blumPrime(int bitLength) {


long long p;
do {
p = dis(gen);
} while (p % FOUR != THREE);
return p;
}
};

random_device Cryptography::r;
mt19937_64 Cryptography::gen(Cryptography::r());
uniform_int_distribution<long long> Cryptography::dis(0, 1LL << 62);

int main() {
vector<long long> key = Cryptography::generateKey(512);
long long n = key[0];
long long p = key[1];
long long q = key[2];
string finalMessage;
int i = 1;
string s = "Hello";

cout << "Message sent by sender: " << s << endl;

long long m = 0;
stringstream ss;
ss << hex << s;
ss >> m;

long long c = Cryptography::encrypt(m, n);

cout << "Encrypted Message: " << c << endl;

vector<long long> m2 = Cryptography::decrypt(c, p, q);


for (long long b : m2) {
ostringstream os;
os << hex << b;
string dec(os.str());
string message;
for (size_t i = 0; i < dec.length(); i += 2) {
string byte = dec.substr(i, 2);
char chr = (char)(int)strtol(byte.c_str(), nullptr, 16);
message.push_back(chr);
}
if (message == s) {
finalMessage = message;
}
i++;
}

cout << "Message received by Receiver: " << finalMessage << endl;

return 0;
}

OUTPUT:
SHA-512
CODE:
// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long int int64;

int64 Message[80];

// Stores the hexadecimal values for


// calculating hash values
const int64 Constants[80]
= { 0x428a2f98d728ae22, 0x7137449123ef65cd,
0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019,
0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe,
0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1,
0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483,
0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210,
0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725,
0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926,
0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8,
0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001,
0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910,
0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60,
0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9,
0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207,
0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6,
0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493,
0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
0x5fcb6fab3ad6faec, 0x6c44198c4a475817 };

// Function to convert a binary string


// to hexa-decimal value
string gethex(string bin)
{
if (bin == "0000")
return "0";
if (bin == "0001")
return "1";
if (bin == "0010")
return "2";
if (bin == "0011")
return "3";
if (bin == "0100")
return "4";
if (bin == "0101")
return "5";
if (bin == "0110")
return "6";
if (bin == "0111")
return "7";
if (bin == "1000")
return "8";
if (bin == "1001")
return "9";
if (bin == "1010")
return "a";
if (bin == "1011")
return "b";
if (bin == "1100")
return "c";
if (bin == "1101")
return "d";
if (bin == "1110")
return "e";
if (bin == "1111")
return "f";
}

// Function to convert a decimal value


// to hexa decimal value
string decimaltohex(int64 deci)
{
// Stores the value as string
string EQBIN = bitset<64>(deci).to_string();

// Stores the equivalent hexa decimal


string hexstring = "";
string temp;

// Traverse the string EQBIN


for (unsigned int i = 0;
i < EQBIN.length(); i += 4) {
temp = EQBIN.substr(i, 4);
hexstring += gethex(temp);
}

// Return the hexstring


return hexstring;
}

// Function to convert a binary


// string to decimal value
int64 BintoDec(string bin)
{

int64 value = bitset<64>(bin)


.to_ullong();
return value;
}

// Function to right rotate x by n bits


int64 rotate_right(int64 x, int n)
{
return (x >> n) | (x << (64 - n));
}

// Function to right shift x by n bits


int64 shift_right(int64 x, int n)
{
return (x >> n);
}

// Function to divide the string


// into chunks
void separator(string getBlock)
{
// Stores the size of chunks
int chunknum = 0;

// Traverse the string S


for (unsigned int i = 0;
i < getBlock.length();
i += 64, ++chunknum) {

// Update the Message[chunknum]


Message[chunknum]
= BintoDec(getBlock.substr(i, 64));
}

// Iterate over the range [16, 80]


for (int g = 16; g < 80; ++g) {

// Find the WordA


int64 WordA = rotate_right(Message[g - 2], 19)
^ rotate_right(Message[g - 2], 61)
^ shift_right(Message[g - 2], 6);

// Find the WordB


int64 WordB = Message[g - 7];

// Find the WordC


int64 WordC = rotate_right(Message[g - 15], 1)
^ rotate_right(Message[g - 15], 8)
^ shift_right(Message[g - 15], 7);

// Find the WordD


int64 WordD = Message[g - 16];

// Find the resultant code


int64 T = WordA + WordB + WordC + WordD;

// Return the resultant Hash Code


Message[g] = T;
}
}

// Function to find the major of a, b, c


int64 maj(int64 a, int64 b, int64 c)
{
return (a & b) ^ (b & c) ^ (c & a);
}

// Function to find the ch value of a,


// b, and c
int64 Ch(int64 e, int64 f, int64 g)
{
return (e & f) ^ (~e & g);
}

// Function to find the Bitwise XOR with


// the right rotate over 14, 18, and 41
int64 sigmaE(int64 e)
{
// Return the resultant value
return rotate_right(e, 14)
^ rotate_right(e, 18)
^ rotate_right(e, 41);
}

// Function to find the Bitwise XOR with


// the right rotate over 28, 34, and 39
int64 sigmaA(int64 a)
{

// Return the resultant value


return rotate_right(a, 28)
^ rotate_right(a, 34)
^ rotate_right(a, 39);
}

// Function to generate the hash code


void Func(int64 a, int64 b, int64 c,
int64& d, int64 e, int64 f,
int64 g, int64& h, int K)
{
// Find the Hash Code
int64 T1 = h + Ch(e, f, g) + sigmaE(e) + Message[K]
+ Constants[K];
int64 T2 = sigmaA(a) + maj(a, b, c);

d = d + T1;
h = T1 + T2;
}

// Function to convert the hash value


// of a given string
string SHA512(string myString)
{
// Stores the 8 blocks of size 64
int64 A = 0x6a09e667f3bcc908;
int64 B = 0xbb67ae8584caa73b;
int64 C = 0x3c6ef372fe94f82b;
int64 D = 0xa54ff53a5f1d36f1;
int64 E = 0x510e527fade682d1;
int64 F = 0x9b05688c2b3e6c1f;
int64 G = 0x1f83d9abfb41bd6b;
int64 H = 0x5be0cd19137e2179;

int64 AA, BB, CC, DD, EE, FF, GG, HH;

stringstream fixedstream;
// Traverse the string S
for (int i = 0;
i < myString.size(); ++i) {

// Add the character to stream


fixedstream << bitset<8>(myString[i]);
}

// Stores string of size 1024


string s1024;

// Stores the string in the


// fixedstream
s1024 = fixedstream.str();

// Stores the length of string


int orilen = s1024.length();
int tobeadded;

// Find modded string length


int modded = s1024.length() % 1024;

// If 1024-128 is greater than modded


if (1024 - modded >= 128) {
tobeadded = 1024 - modded;
}

// Else if 1024-128 is less than modded


else if (1024 - modded < 128) {
tobeadded = 2048 - modded;
}

// Append 1 to string
s1024 += "1";

// Append tobeadded-129 zeros


// in the string
for (int y = 0; y < tobeadded - 129; y++) {
s1024 += "0";
}

// Stores the binary representation


// of string length
string lengthbits
= std::bitset<128>(orilen).to_string();

// Append the lengthbits to string


s1024 += lengthbits;

// Find the count of chunks of


// size 1024 each
int blocksnumber = s1024.length() / 1024;
// Stores the numbering of chunks
int chunknum = 0;

// Stores hash value of each blocks


string Blocks[blocksnumber];

// Traverse the string s1024


for (int i = 0; i < s1024.length();
i += 1024, ++chunknum) {
Blocks[chunknum] = s1024.substr(i, 1024);
}

// Traverse the array Blocks[]


for (int letsgo = 0;
letsgo < blocksnumber;
++letsgo) {

// Divide the current string


// into 80 blocks size 16 each
separator(Blocks[letsgo]);

AA = A;
BB = B;
CC = C;
DD = D;
EE = E;
FF = F;
GG = G;
HH = H;

int count = 0;

// Find hash values


for (int i = 0; i < 10; i++) {

// Find the Hash Values

Func(A, B, C, D, E, F, G, H, count);
count++;
Func(H, A, B, C, D, E, F, G, count);
count++;
Func(G, H, A, B, C, D, E, F, count);
count++;
Func(F, G, H, A, B, C, D, E, count);
count++;
Func(E, F, G, H, A, B, C, D, count);
count++;
Func(D, E, F, G, H, A, B, C, count);
count++;
Func(C, D, E, F, G, H, A, B, count);
count++;
Func(B, C, D, E, F, G, H, A, count);
count++;
}
// Update the value of A, B, C,
// D, E, F, G, H

A += AA;
B += BB;
C += CC;
D += DD;
E += EE;
F += FF;
G += GG;
H += HH;
}

stringstream output;

// Print the hexadecimal value of


// strings as the resultant SHA-512
output << decimaltohex(A);
output << decimaltohex(B);
output << decimaltohex(C);
output << decimaltohex(D);
output << decimaltohex(E);
output << decimaltohex(F);
output << decimaltohex(G);
output << decimaltohex(H);

// Return the string


return output.str();
}

// Driver Code
int main()
{
// Input
string S = "GeeksForGeeks";

// Function Call
cout << S << ": " << SHA512(S);

return 0;
}

OUTPUT:
Practical 6: Implement the digital signature schemes: RSA
and ElGamal:
RSA
CODE:
#include <iostream>
#include <vector>

using namespace std;

int euclid(int m, int n) {


if (n == 0) {
return m;
} else {
int r = m % n;
return euclid(n, r);
}
}

pair<int, int> exteuclid(int a, int b) {


int r1 = a;
int r2 = b;
int s1 = 1;
int s2 = 0;
int t1 = 0;
int t2 = 1;

while (r2 > 0) {


int q = r1 / r2;
int r = r1 - q * r2;
r1 = r2;
r2 = r;
int s = s1 - q * s2;
s1 = s2;
s2 = s;
int t = t1 - q * t2;
t1 = t2;
t2 = t;
}

if (t1 < 0) {
t1 = t1 % a;
}

return make_pair(r1, t1);


}

int main() {
int p = 823;
int q = 953;
int n = p * q;
int Pn = (p - 1) * (q - 1);

vector<int> key;
for (int i = 2; i < Pn; i++) {
int gcd = euclid(Pn, i);
if (gcd == 1) {
key.push_back(i);
}
}

int e = 313;
pair<int, int> result = exteuclid(Pn, e);
int r = result.first;
int d = result.second;

if (r == 1) {
d = d < 0 ? d + Pn : d;
cout << "decryption key is: " << d << endl;
} else {
cout << "Multiplicative inverse for the given encryption key does not exist.
Choose a different encryption key" << endl;
}

int M = 19070;
int S = 1;
for (int i = 0; i < d; i++) {
S = (S * M) % n;
}
int M1 = 1;
for (int i = 0; i < e; i++) {
M1 = (M1 * S) % n;
}

if (M == M1) {
cout << "As M = M1, Accept the message sent by Alice" << endl;
} else {
cout << "As M not equal to M1, Do not accept the message sent by Alice" << endl;
}

return 0;
}

OUTPUT:

ElGamal
CODE:
#include <iostream>
#include <random>
#include <cmath>

using namespace std;

int inverse(int k, int m) {


k = k % m;
for (int x = 1; x < m; x++) {
if ((k * x) % m == 1) {
return x;
}
}
return 1;
}

pair<int, int> pair(int s) {


int safe_prime = 0;
while (true) {
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<int> dis(2, pow(2, s));

int p = dis(gen);
safe_prime = 2 * p + 1;
if (pow(2, safe_prime - 1) % safe_prime == 1) {
break;
}
}

while (true) {
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<int> dis(2, safe_prime - 1);

int a = dis(gen);
if ((safe_prime - 1) % a != 1) {
break;
}
}
return make_pair(safe_prime, a);
}

tuple<int, int, int, int> egKey(int s) {


auto p_a = pair(s);
int p = p_a.first;
int a = p_a.second;

random_device rd;
mt19937 gen(rd());
uniform_int_distribution<int> dis(1, p - 2);
int x = dis(gen);

int y = pow(a, x) % p;
return make_tuple(p, a, x, y);
}

tuple<int, int> egGen(int p, int a, int x, int m) {


while (true) {
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<int> dis(1, p - 2);
int k = dis(gen);

if (__gcd(k, p - 1) == 1) {
int r = pow(a, k) % p;
int l = inverse(k, p - 1);
int s = (l * (m - x * r)) % (p - 1);
return make_tuple(r, s);
}
}
}

bool egVer(int p, int a, int y, int r, int s, int m) {


if (r < 1 || r > p - 1) {
return false;
}

int v1 = (int)(pow(y, r) % p * pow(r, s) % p);


int v2 = (int)pow(a, m) % p;

return v1 == v2;
}

int main() {
int message = 36;
cout << "Message: " << message << endl;

tuple<int, int, int, int> key = egKey(10);


int prime = get<0>(key);
int alpha = get<1>(key);
int private_key = get<2>(key);
int public_key = get<3>(key);
cout << "prime,alpha,private,public: " << prime << "," << alpha << "," <<
private_key << "," << public_key << endl;

tuple<int, int> generated = egGen(prime, alpha, private_key, message);


int rr = get<0>(generated);
int ss = get<1>(generated);
cout << "rr,ss: " << rr << "," << ss << endl;

bool is_valid = egVer(prime, alpha, public_key, rr, ss, message);


cout << "Valid Signature: " << (is_valid ? "true" : "false") << endl;

return 0;
}

OUTPUT:

You might also like