Index
The format for cryptography lab is given below
1. Front page (Name, roll no., department, semester, subject name and subject code). 2. List of experiments prescribed by the university.
3. Time table of instructional laboratory. 4. Index
5. Each experiment written in following manner (I) Experiment no.
(II) Name of experiment
(III) Objective of performing experiment (IV) Theory (in brief but be sufficient) (V) Program code
List of experiments prescribed by the university
(TIT-751) CRYPTOGRAPHY AND NETWORK SECURITY LABThe following programs should be implemented preferably on ' UNIX' platform using 'C' language (for 1-5) and other standard utilities available with 'UNIX' systems (for 6-8)
:-1. Implement the encryption and decryption of 8-bit data using 'Simplified DES Algorithm' (created by Prof. Edward Schaefer) in 'C'.
2. Implement 'Linear Congruential Algorithm' to generate 5 pseudo-random numbers in 'C'.
3. Implement Rabin-Miller Primality Testing Algorithm in 'C'.
4. Implement the Euclid Algorithm to generate the GCD of an array of 10 integers in 'C'.
5. Implement RSA algorithm for encryption and decryption in 'C'.
6. Configure a mail agent to support Digital Certificates, send a mail and verify the correctness of this system using the configured parameters.
7. Configure SSH (Secure Shell) and send/receive a file on this connection to verify the correctness of this system using the configured parameters.
8. Configure a firewall to block the following for 5 minutes and verify the correctness of this system using the configured parameters:
(a) Two neighborhood IP addresses on your LAN (b) All ICMP requests
(c) All TCP SYN Packets
Experiment no. 1
Objective of performing experiment: Data encryption/decrytion using S-DES
CAESAR CIPHER:
It was used by Julius Caesar. The Caesar cipher involves replacing each letter of the alphabet with the letter standing three places further down the alphabet
For example
Plain: meet me after the toga party Cipher: PHHW PH DIWHU WKH WRJD SDUWB Transformation is made using the following mapping:
Plain: a b c d e f g h i j k l m n o p q r s t u v w x y z Cipher: D E F G H I J K L M N O P Q R S T U V W X Y Z A B C
Let us assign a numerical equivalent to each letter from 0 to 25. Then the algorithm may be expressed as follows. For each plaintext letter p, substitute the ciphertext letter C:
C=E(p)=(p+3) mod 26
A shift may be of any amount, so that general Caesar algorithm is
C=E(p)=(p+k) mod 26,
Where k takes on a value in the range 1 to 25. The decryption algorithm is simply
P=D(C)=(C-k) mod 26
If it is known that a given ciphertext is a Caesar cipher, then a brute-force cryptanalysis is easily performed: simply try all possible 25 keys.
Three important characteristics of this problem enable us to use brute-force cryptanalysis: 1. The encryption and decryption algorithms are known
2. There are only 25 keys to try
3. The language of the plaintext is known and easily recognizable
In most networking situations algorithms are assumed to be known. Brute-force analysis is impractical when algorithm employs large of keys. The 3rd characteristic is also significant. If the language of the plaintext is not known, then the
Furthermore, if the input is compressed in some manner, again recognition is difficult. Below is example of compression by ZIP:
If this file is then encrypted with a simple substitution cipher (expanded to include more than just 26 characters), then the plaintext may not be recognized.
Program : Encryption/Decryption using Caesar Cipher */
#include <iostream.h> #include <conio.h> #include <ctype.h> int SQR(int x)
{
int yes=0, i=1;
while(i<=17 && yes==0) { if(i*i==x) { yes=1; sr=i; } else i++; } return yes; } void main() { clrscr(); int choice, n; cout<<"CAESAR CIPHER \n"; cout<<"1. Code your text \n"; cout<<"2. Decode a cipher \n"; cin>>choice; char A[300], W; switch (choice) { case 1: clrscr();
do {
cout<<"Enter the total number of letters in your message (perfect square) "; cin>>n;
} while(SQR(n)==0); cout<<"Enter your message : \n"; for(int o=0; o<n; o++)
{ do { cin>>A[o]; } while (isalnum(A[o])==0); } int z=0; clrscr();
for(int y=1; y<=2*sr; y+=2) { for(int q=1; q<=sr; q++) { gotoxy(y, q); cout<<(char)toupper(A[z]); z++; } cout<<endl; }
cout<<"\nOR\nThe coded text is \n"; for(int qw=0; qw<sr; qw++) { for(int c=0; c<n; c+=sr) cout<<(char)toupper(A[c+qw]); } break; case 2: clrscr(); do {
cin>>n;
} while(SQR(n)==0);
cout<<"Enter the cipher text as it appears in rows \n"; for(int b=0; b<n; b++)
{
cin>>A[b];
cout<<"\nThe decoded text is \n"; for(int h=0; h<sr; h++) { for(int c=0; c<n; c+=sr) cout<<A[c+h]; } } break; } getch(); }
Experiment no. 2
Objective of performing experiment: Data encryption/decrytion using Transposition cipher TRANSPOSITION TECHNIQUE:
Another approach to enciphering is usage of transpositions, or permutations on the plaintext letters. The simplest such cipher is the rail fence technique, in which the plaintext is written down as a sequence of diagonals and then read off as the sequence of rows.
For example, to encipher the message “meet me after the toga party” with a rail fence of depth 2, we write
m e m a t r h t g p r y e t e f e t e o a a t
The encrypted message is
MEMATRHTGPRYETEFETEOAAAT
A more complex scheme is to write the message in a rectangle, row by row, and read the message off, column by column, but to permute the order of columns. The order of columns then becomes the key to the algorithm. For example, Key: 4 3 1 2 5 6 7 Plaintext: a t t a c k p o s t p o n e d u n t i l t w o a m x y z Ciphertext: TTNAAPTMTSUOAODWCOIXKNLYPETZ
A pure transposition cipher is easily recognized because it has the same letter frequencies as the original plaintext. The transposition cipher can be made more secure by performing more than 1 transposition
Program:- Transposition cipher
#include <iostream> void main(void) {
char strOriginalIput[100], strPass[35], strENCR[100], outpass[100]; int istrLen = 0;
int iArray[20] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
cout << "\n Enter String(without space) : "; cin >> strOriginalIput;
istrLen = strlen(strOriginalIput); strOriginalIput[istrLen + 1] = '\0'; cout << "\n Enter Crypt Pass: "; cin >> strPass;
int iLen = strlen(strPass); strPass[iLen + 1] = '\0'; strcpy(outpass, strPass); outpass[iLen + 1] = '\0'; int cnt = 0;
//cout << strOriginalIput << "\n"; for (int i = 0; i < iLen - 1; i++)
{
for (int j = 0; j < iLen - 1 - i; j++) {
if (strPass[j + 1] < strPass[j]) {
/* compare the two neighbors */
char tmp = strPass[j]; /* swap a[j] and a[j+1] */ strPass[j] = strPass[j + 1]; strPass[j + 1] = tmp; int t = iArray[j]; iArray[j] = iArray[j + 1]; iArray[j + 1] = t; } } } cnt = 0;
for (int z = 0; z < iLen; z++) {
for (int x = 0; x <= iLen; x++) {
if ((iArray[z] + iLen * x) <= istrLen) {
strENCR[cnt++] = strOriginalIput[(iArray[z] + iLen * x) - 1]; }
} }
strENCR[istrLen] = '\0'; //cout << strENCR << "\n\n" ; // Output
int nl = 1;
for (i = 0; i < iLen; i++) {
cout << outpass[i] << " "; cout << "\n---"; cout << "\n";
for (i = 0; i < istrLen; i++) {
if (i == iLen * nl) { cout << "\n" << strOriginalIput[i] << " "; nl++; } else cout << strOriginalIput[i] << " "; }
cout << "\n\n" << "Encrypted String : " << strENCR; // Encryption is over, now going for decryption cout << "\n";
char strtmp[100]; cnt = 0;
for (z = 0; z < iLen; z++) {
for (int x = 0; x <= iLen; x++) {
if ((iArray[z] + iLen * x) <= (istrLen))
strtmp[iArray[z] + (iLen * x) - 1] = strENCR[cnt++]; }
}
strtmp[istrLen] = '\0';
cout << "Decrypted String :" << strtmp << "\n\n"; }
Experiment no. 3
Objective of performing experiment: Data encryption using S-DES
DATA ENCRYPTION STANDARD:
It was adopted in 1977 by the National Bureau of Standards (NBS), now National Institute of Standards and Technology (NIST), as Federal Information Processing Standard 46 (FIPS PUB 46). In 1971, IBM’s team under Horst Feistel leadership developed algorithm LUCIFER, operating on 64-bit blocks with 128-bit key. Further, IBM’s team leaded by Walter Tuchman and Carl Meyer revised LUCIFER to make it more resistant to cryptanalysis, but they reduced key size to 56 bits. In 1973, NBS issued a request for proposals for a national cipher standard. IBM submitted results of its Tuchman-Meyer project. This was by far the best algorithm proposed and was adopted in 1977 as Data Encryption Standard. In 1994, NIST reaffirmed DES for federal use for another 5 years. In 1999, NIST issued a new version of its standard (FIPS PUB 46-3) that indicated that DES should only be used for legacy systems and that triple DES be used.
Block ciphers and the Data Encryption Standard
1. Simplified DES 2. Block cipher principles 3. DES algorithm 4. Strength of DES
5. Differential and linear cryptanalysis 6. Block cipher design principles 7. Block cipher modes of operation
S-DES encryption (decryption) algorithm takes 8-bit block of plaintext (ciphertext) and a 10-bit key, and produces 8-bit ciphertext (plaintext) block. Encryption algorithm involves 5 functions: an initial permutation (IP); a complex function fK, which involves both permutation and substitution and depends on a key input; a simple
permutation function that switches (SW) the 2 halves of the data; the function fK again; and finally, a permutation
function that is the inverse of the initial permutation (IP-1). Decryption process is similar.
The function fK takes 8-bit key which is obtained from the 10-bit initial one two times. The key is first subjected to
a permutation P10. Then a shift operation is performed. The output of the shift operation then passes through a permutation function that produces an 8-bit output (P8) for the first subkey (K1). The output of the shift operation also feeds into another shift and another instance of P8 to produce the 2nd subkey K2.
We can express encryption algorithm as superposition:
IP f SW f IP K K 1 2 1 or
Ciphertext= IP-1 (fK2(SW(fK1(IP(plaint ext)))))
Where ))) ( 10 ( ( 8 1 P Shift P key K
K2 P8(Shift(Shift(P10(key))))
Decryption is the reverse of encryption:
S-DES KEY GENERATION
Scheme of key generation:
First, permute the 10-bit key k1,k2,..,k10:
P10(k1,k2,k3,k4,k5,k6,k7,k8,k9,k10)=(k3,k5,k2,k7,k4,k10,k1,k9,k8,k6) Or it may be represented in such a form
P10 3 5 2 7 4 10 1 9 8 6
Each position in this table gives the identity of the input bit that produces the output bit in this position. So, the 1st output bit is bit 3 (k3), the 2nd is k5 and so on. For example, the key (1010000010) is permuted to (1000001100). Next, perform a circular shift (LS-1), or rotation, separately on the 1st 5 bits and the 2nd 5 bits. In our example, the result is (00001 11000)
Next, we apply P8, which picks out and permutes 8 out of 10 bits according to the following rule: P8
6 3 7 4 8 5 10 9
The result is subkey K1. In our example, this yields (10100100)
We then go back to the pair of 5-bit strings produced by the 2 LS-1 functions and perform a circular left shift of 2 bit positions on each string. In our example, the value (00001 11000) becomes (00100 00011). Finally, P8 is applied again to produce K2. In our example, the result is (01000011)
S-DES ENCRYPTION
The input to the algorithm is an 8-bit block of plaintext, which is permuted by IP function: IP
2 6 3 1 4 8 5 7
At the end of the algorithm, the inverse permutation is used: IP-1
4 1 3 5 7 2 8 6
It may be verified, that IP-1(IP(X)) = X.
The most complex component of S-DES is the function fK, which consists of a combination of permutation and
substitution functions. The function can be expressed as follows. Let L and R be the leftmost 4 bits and rightmost 4 bits of the 8-bit input to fK, and let F be a mapping (not necessarily one to one) from 4-bit strings to 4-bit strings.
Then we let
where SK is a subkey and is the bit-by-bit XOR operation. For example, suppose the output of the IP stage in Fig.3.3 is (1011 1101) and F(1101,SK) = (1110) for some key SK. Then fK(1011 1101) = (0101 1101) because
(1011) (1110) = (0101).
We now describe the mapping F. The input is a 4-bit number (n1 n2 n3 n4). The 1st operation is an expansion/permutation:
E/P 4 1 2 3 2 3 4 1
For what follows, it is clearer to depict result in this fashion: n4|n1 n2|n3 n2|n3 n4|n1
The 8-bit subkey K1 = (k11, k12, k13, k14, k15, k16, k17, k18) is added to this value using XOR: n4+k11|n1+k12 n2+k13|n3+k14
n2+k15|n3+k16 n4+k17|n1+k18 Let us rename these bits:
p00|p01 p02|p03 p10|p11 p12|p13
The 1st 4 bits (1st row of the preceding matrix) are fed into the S-box S0 to produce a 2-bit output, and the
remaining 4 bits (2nd row) are fed into S1 to produce another 2-bit output. These 2 boxes are defined as follows: 0 12 3 0 12 3 3 2 1 0 3 0 3 3 0 1 1 2 1 0 0 1 2 3 2 0 1 3 2 1 0 2 3 0 2 3 1 1 3 1 2 2 0 3 0 3 1 0 S S
The S-boxes operate as follows. The 1st and 4th input bits are treated as a 2-bit number that specify a row of the S-box,
and the 2nd and 3rd input bits specify a column of the S-box. The entry in that row and column, in base 2, is the 2-bit
output. For example, if (p00, p03) = (00) and (p01, p02) = (10), then the output is from row 0, column 2 of S0, which is 3, or (11) in binary. Similarly, (p10, p13) and (p11, p12) are used to index into a row and column of S1 to produce an additional 2 bits.
Next, the 4 bits produced by S0 and S1 undergo a further permutation as follows: P4
2 4 3 1
The output of P4 is the output of function F.
The function fK only alters the leftmost 4 bits of input.
The switch function SW interchanges the left and right bits so that the 2nd instance of f
K operates on a different 4
bits. In the 2nd instance, the E/P, S0, S1, and P4 functions are the same. The key input is K2.
Program: DES Encryption
char plain[8]; char cipher[8];
char key[] = "TYPICAL"; void pbox(char *,int,int *); void sbox(char *);
void breakplain(char *, char *,char *); void copytoleft(char *,char *);
void copytoright(char *,char *); void findkey(char *,int);
void xor(char *,char *); void display(char *); void encrypt(void);
main(int argc,char **argv) {
FILE *src,*dest; int n,i;
if(argc!=3) {
printf("Usage: desencr <input-file> <output-file>"); exit(1); } src=fopen(argv[1],"rb"); dest=fopen(argv[2],"wb"); while(1) { n=fread(plain,sizeof(char),8,src); if(n<8) for(i=n;i<8;i++) plain[i]='\0'; encrypt(); fwrite(plain,sizeof(char),8,dest); if(n<8) break; } fcloseall(); } void encrypt(void) { int lkey[] = {1,5,4,2,6,7,0,3}; int rlkey[] = {6,0,3,7,2,1,4,5}; int skey[] = {1,3,0,2}; char tempkey[4]; char left[4],right[4]; int i;
pbox(plain,8,lkey); // 1st Stage Complete strcpy(key,"TYPICAL");
for(i=0;i<16;i++) { breakplain(left,right,plain); copytoleft(plain,right); findkey(tempkey,i); xor(right,tempkey); sbox(right); pbox(right,4,skey); xor(right,left); copytoright(plain,right); } // 18th Stage breakplain(left,right,plain); copytoleft(plain,right); copytoright(plain,left); // 19th stage pbox(plain,8,rlkey); }
void pbox(char *arr, int n, int *key) { int i; char *dest=(char*)malloc(n*sizeof(char)); for(i = 0; i < n; i++) dest[key[i]] = arr[i]; for(i=0; i < n; i++) arr[i] = dest[i]; return; }
void sbox(char *arr) { int i; for(i = 0; i < 4; i++) arr[i] = ~arr[i]; return; }
void breakplain(char *left, char *right, char *plain) { int i; for(i=0;i<4;i++) right[i] = plain[i]; for(;i<8;i++) left[i-4] = plain[i]; return; }
void copytoleft(char *dest, char *src) {
int i;
for(i = 3; i >= 0; i--) dest[i+4] = src[i]; return;
}
void copytoright(char *dest, char *src) { int i; for(i = 0; i < 4; i++) dest[i] = src[i]; return; }
int pow(int a,int b) { int i,temp = 1; for(i = 1; i <= b; i++) temp *= a; return (temp); }
void findkey(char *tkey, int n) {
int combine[] = { 60,27,43,23,54,75,90,39,92,46,102,30,105,71,120,15 }; int keyrule[] = { 2,0,3,1};
int i,count;
for(i=0,count = 0; i < 7 && count < 4; i++) if(ISSET(combine[n],i))
tkey[count++] = key[i]; pbox(tkey,4,keyrule); return;
}
void xor(char *dest, char *src) { int i; for(i = 0; i < 4; i++) dest[i] ^= src[i]; return; }
void display(char *arr) { int i; for(i = 0; i < 8; i++) printf("%c",arr[i]); return; }
Experiment no. 4
Objective of performing experiment: Data decryption using S-DES Program:- DES Decryption
#include<stdio.h> char plain[8];
char key[] = "TYPICAL"; void pbox(char *,int,int *); void sbox(char *);
void breakplain(char *, char *,char *); void copytoleft(char *,char *);
void copytoright(char *,char *); void findkey(char *n,int); void xor(char *,char *); void display(char *); void decrypt(void);
main(int argc,char **argv) {
FILE *src,*dest; int n;
if(argc!=3) {
printf("Usage: desdecr <input-file> <output-file>"); exit(1); } src=fopen(argv[1],"rb"); dest=fopen(argv[2],"wb"); while(1) { fread(plain,sizeof(char),8,src); if(feof(src)) break; decrypt(); fwrite(plain,sizeof(char),8,dest); } fcloseall(); } void decrypt(void) { int lkey[] = {1,5,4,2,6,7,0,3}; int rlkey[] = {6,0,3,7,2,1,4,5}; int skey[] = {1,3,0,2}; char tempkey[4]; char left[4],right[4]; int i,j;
// 18th Stage breakplain(left,right,plain); copytoleft(plain,right); copytoright(plain,left); // 2nd Stage start for(i=0;i<16;i++) { breakplain(left,right,plain); copytoright(plain,left); strcpy(key,"TYPICAL"); // for(j=0;j<(16-i);j++) findkey(tempkey,15-i); xor(left,tempkey); sbox(left); pbox(left,4,skey); xor(left,right); copytoleft(plain,left); } // 19th stage pbox(plain,8,rlkey); // display(plain); // getch(); return; }
void pbox(char *arr, int n, int *key) { int i; char *dest=(char*)malloc(n*sizeof(char)); for(i = 0; i < n; i++) dest[key[i]] = arr[i]; for(i=0; i < n; i++) arr[i] = dest[i]; return; }
void sbox(char *arr) { int i; for(i = 0; i < 4; i++) arr[i] = ~arr[i]; return; }
void breakplain(char *left, char *right, char *plain) {
int i;
for(i=0;i<4;i++) right[i] = plain[i]; for(;i<8;i++)
left[i-4] = plain[i]; return;
}
void copytoleft(char *dest, char *src) { int i; for(i = 3; i >= 0; i--) dest[i+4] = src[i]; return; }
void copytoright(char *dest, char *src) { int i; for(i = 0; i < 4; i++) dest[i] = src[i]; return; }
int pow(int a,int b) { int i,temp = 1; for(i = 1; i <= b; i++) temp *= a; return (temp); }
void findkey(char *tkey,int n) {
int combine[] = { 60,27,43,23,54,75,90,39,92,46,102,30,105,71,120,15 }; int keyrule[] = { 2,0,3,1};
int i,count;
for(i=0,count = 0; i < 7 && count < 4; i++) if(ISSET(combine[n],i))
tkey[count++] = key[i]; pbox(tkey,4,keyrule); return;
}
void xor(char *dest, char *src) { int i; for(i = 0; i < 4; i++) dest[i] ^= src[i]; return; }
void display(char *arr) {
int i;
for(i = 0; i < 8; i++) printf("%c",arr[i]);
return; }
Objective of performing experiment: Implement the Euclid Algorithm to generate the GCD of two numbers
EUCLID’S ALGORITHM
EUCLID(a,b) 1. A:=a; B:=b 2. if B=0 return A=gcd(a,b) 3. R=A mod B 4. A:=B 5. B:=R 6. goto 2The algorithm has the following progression: A1=B1xQ1+R1 A2=B2xQ2+R2 A3=B3xQ3+R3 To find gcd(1970,1066) 1970=1x1066+904 gcd(1066,904) 1066=1x904+162 gcd(904,162) 904=5x162+94 gcd(162,94) 162=1x94+68 gcd(94,68) 94=1x68+26 gcd(68,26) 68=2x26+16 gcd(26,16) 26=1x16+10 gcd(16,10) 16=1x10+6 gcd(10,6) 10=1x6+4 gcd(6,4) 6=1x4+2 gcd(4,2) 4=2x2+0 gcd(2,0) Therefore, gcd(1970,1066)=2
This process should terminate, otherwise we would get an endless sequence of positive integers, each one is strictly smaller than the one before, and this is clearly impossible.
Program:
#include <stdio.h>
int main (int argc, const char * argv[]) {
// This program is a C representation of Algorithm E
// in Donald E. Knuth's The Art of Computer Programming Vol 1
int a, A, b, B, c, d, m, n, q, r = 1, t, x; //A = a' B = b' from the book
printf("\n\n\n\nThis program will find the Greatest Common Factor of two numbers\n"); printf("m = "); scanf ("%d", &m); printf("n = "); scanf ("%d", &n); printf("\n\nWorking numbers\n\n"); printf("A\t a\t B\t b\t c\t d\t q\t r\n"); printf("---\n"); A = b = 1; a = B = 0; c = m; d = n; //a' <- b <- 1, a <- b' <- 0, c <- m, d <- n while (r != 0) { q = (c / d); r = (c % d); printf("%d\t %d\t %d\t %d\t %d\t %d\t %d\t %d\n", A, a, B, b, c, d, q, r); x = d; c = d; d = r; t = A; A = a; a = (t - (q * a)); t = B; B = b; b = (t - (q * b)); } printf("---\n");
printf("\nThe Greatest Common Divisor of %d and %d is %d\n\n", m, n, x);
return 0; }
Experiment no. 6
Objective of performing experiment: Implement RSA algorithm for encryption and decryption in 'C'
The RSA Algorithm
It was developed in 1977 by Ron Rivest, Adi Shamir, and Len Adleman at MIT and first published in 1978. The Rivest-Shamir-Adleman (RSA) has since that time reigned supreme as most widely accepted and implemented general-purpose approach to public-key encryption.
Description of the Algorithm
RSA makes use of an expression with exponentials. Plaintext is encrypted in blocks, with each block having a binary value less than some integer n. That is, the block size must be less or equal to log2n; in practice, the block size is k bits, where 2k n2k1. Encryption and
decryption are of the following form, for some plaintext block M and ciphertext block C:
n M n M n C M n M C ed d e d e mod mod ) ( mod mod
Both sender and receiver must know the value of n. The sender knows the value of e, and only receiver knows the value of d. Thus, this is a public-key encryption algorithm with a public key of KU={e,n}, and a private key of KR={d,n}. For this algorithm to be satisfactory for public-key encryption, the following requirements must be met:
1. It is possible to find values of e,d,n such that Med Mmodn for all M<n 2. It is relatively easy to calculate Me and C for all values of M<nd
3. It is infeasible to determine d given e and d.
For now, we focus on the 1st requirement and consider the other questions later. We need to find
a relationship of the form
n M Med mod A corollary to Euler’s theorem
(For every a and n that are relatively prime
n a(n) 1mod
where (n) is the Euler’s totient function – number of positive integers less than n and relatively prime to n),
fits the bill:
Given two prime numbers, p and q, and two integers, n and m, such that n=pq and 0<m<n, and arbitrary integer k, the following relationship holds:
n m m
mk(n)1 k(p1)(q1)1 mod
(*) (as far as for p,q prime, (n)(p1)(q1))
This is equivalent to saying: mod ( ) ) ( mod 1 1 n e d n ed
That is, e and d are multiplicative inverses mod(n). Note that, according to the rules of modular arithmetic, this is true only if d (and therefore e) is relatively prime to (n). Equivalently, gcd((n),d)1.
We are now ready to state the RSA scheme. The ingredients are the following: p,q, two prime numbers (private, chosen)
n=pq (public, calculated)
e, with gcd((n),e)1;1e(n) (public, chosen) ) ( mod 1 n e d (private, calculated)
The private key consists of {d,n}, and the public key consists of {e,n}. Suppose that user A has published its public key and that user B wishes to send message M to A. Then B calculates
n M
C emod
and transmits C. On receipt of this ciphertext, user A decrypts by calculating n
C M d mod
. It is worthwhile to summarize the justification for this algorithm. We have chosen e and d such that d e1mod(n).
Therefore ed 1mod(n). Therefore, ed is of the form k(n)1. But by the corollary to Euler’s theorem (*), given two prime numbers, p and q, and integer n=pq and M, with 0<M<n:
n M M
Mk(n)1 k(p1)(q1)1 mod
So, Med M modn. Now M C n M n M n M n
n M C ed d e d e mod mod mod ) ( mod mod Figure 9.5 summarizes RSA algorithm:
An example is shown in Figure 9.6
For this example, the keys were generated as follows: 1. Select two prime numbers, p=17, q=11
2. Calculate n=pq=17x11=187
3. Calculate (n)=(p-1)(q-1)=16x10=160
4. Select e such that e is relatively prime to (n)=160 and less than (n); we choose e=7. 5. Determine d such that de1mod160 and d<160. The correct value is d=23, because
23x7=161=1x160+1; d can be calculated using the extended Euclid’s algorithm: M=160, b=7 A=(1,0,m), B=(0,1,b) Q=A3/B3=160/7=22 T=A-QB=(1,-22,6) A=(0,1,b), B=(1,-22,6) Q=A3/B3=7/6=1 T=(-1,23,1) A=(1,-22,6), B=(-1,23,1) B3=1 =>b-1=B2=23.
The resulting keys are public key KU={7,187} and private key KR={23,187}. The example shows the use of these keys for a plaintext input of M=88. For encryption, we need to calculate C=887 mod 187. Exploiting the properties of modular arithmetic, we can do this as follows:
887 mod 187= [(884 mod 187)x(882 mod 187)x(88mod 187)] mod 187
88 mod 187 = 88
882 mod 187 = 7744 mod 187 = 77
884 mod 187 = 772 mod 187 =132
887 mod 187 = (88x77x132) mod 187 = [((88x77) mod 187) x (132 mod 187)] mod 187 =
(44x132) mod 187 = 5808 mod 187 = 11 For decryption, we calculate M=1123 mod 187:
1123 mod 187 = [(11 mod 187)x(112 mod 187)x(114 mod 187)x(118 mod 187)x
(118 mod 187)] mod 187 = [11x121x 14641 mod 187 x (118 mod 187)x
(118 mod 187)] mod 187 = [11x121x55x (3025 mod 187)x
(3025 mod 187)] mod 187 = [11x121x55x 33x33
] mod 187 = [((11x121) mod 187 )x((55x 33) mod 187) x 33 ] mod 187 = [(1331 mod 187)x(1815 mod 187)x33] mod 187 =
[ 22x132x33]mod 187 = [2904mod187x33]mod187= [99x33] mod 187= 3267 mod 187 = 88 Program :- RSA #define RSA #include<iostream> #include<string> #include<iomanip> #include<ctime> #include<cstdlib> #include<cmath> using namespace std; /* Function Declarations */ int menu(); int prime(int);
__int64 GCD(__int64, __int64); __int64 ExtEuclid(__int64,__int64); void FastEXP(__int64,__int64,__int64); void IntBin(__int64);
/* Global Arrays */
const __int64 maxsize = 50000; __int64 r[maxsize]; //holds remainders __int64 q[maxsize]; //holds quotients const __int64 bytesize = 1024; __int64 bin[bytesize]; __int64 top = 0; __int64 bottom = 0; //Start Main int main() { __int64 method(0),max(0),gcd(0),counter(1),test(0); __int64 b(0),c(0),d(0),e(0),f(0),i(0),j(0),p(0),q(0),t(0),a(0),n(0),m(0),theta(0); while (method != 5) { method = menu(); switch (method) { case 1:
cout<<"Enter the max value between 1000 and 9999"<<endl;
cin >> max;
system("CLS"); cout<<"Generating Keys"; while (p < 100) { p = prime(max);//get p }
while (q <= p && q <= max) {
q = prime(max);//get q counter++;
test = counter %50; //track attempts if (test == 0 ){cout<<".";}
}
cout<<endl;
n = p * q; //compute n
theta = (p-1)*(q-1); //compute theta while (e == q || e == 0) { e = prime(max); }// e < theta gcd = GCD(e,theta); cout<<"Gcd is "<<gcd<<endl; d = ExtEuclid(e,theta); if (d < 0) { d = theta - abs(d); } cout<<"p is "<<p<<endl; cout<<"q is "<<q<<endl; cout<<"n is "<<n<<endl; cout<<"theta is "<<theta<<endl; cout<<"e is "<<e<<endl; cout<<"d is "<<d<<endl; p = 0; q = 0; //reset p and q break; case 2: //Encrypt
cout<<"Enter Plaintext in decimal format"<<endl; cin>> t;
FastEXP(t,e,n); break;
case 3: //Decrypt
cout<<"Enter Ciphertext in decimal format"<<endl; cin>> c;
break; case 4: exit (0); break; default: break; } } return 0; } int menu() { int method; cout<<"RSA Encryption"<<endl;
cout<<"Please make a selection?"<<endl; cout<<"1. Generate Keys"<<endl; cout<<"2. Encrypt "<<endl; cout<<"3. Decrypt"<<endl; cout<<"4. Exit"<<endl; cin >> method; system("CLS"); return method; }
int prime(int max) {
int prime(0);
int matrix[333][8]; //[row][column] //all fixed top column numbers matrix[0][0] = 1; matrix[0][1] = 7; matrix[0][2] = 11; matrix[0][3] = 13; matrix[0][4] = 17; matrix[0][5] = 19; matrix[0][6] = 23; matrix[0][7] = 29; int i(0),j(0),k(0),sr(0),modnum(0),row(0),col(0);
max = max / 30; //determine array-row size needed for storage for (i = 0; i < max; i++)//rows
{
for (j = 0; j < 8; j++) //columns, fixed {
matrix[i][j] = (30 * i) + matrix[0][j];//i = row, j = columnn }
}
for (k = 0; k < max; k++)//total rows {
for (j = 0; j < 8; j++) //8 columns {
sr = sqrt(matrix[k][j]);
for ( i = 2; i < sr + 2; i++) //check up to the sq root {
modnum = matrix[k][j] % i; if (modnum == 0) //not prime
{
i = sr + 3; //exit loop after Square root matrix[k][j] = NULL; //delete non-primes }
if (modnum != 0 && i == sr + 1) //criteria for prime {
// cout<<" "<<matrix[k][j]<<endl;//print out prime number }
} }
}
srand((unsigned)time(0)); //seed random number generator with clock while (prime == 0)
{ //until suitable primes are picked row = rand()%max;
col = rand()%8;
prime = matrix[row][col]; //assign prime to value in matrix }
return prime; } //end function
/* This function will take 2 parameters and solve the GCD from Euclid's Algorithm a - smaller value
b - larger value */
__int64 ExtEuclid(__int64 a, __int64 b) { __int64 rem(0),gcd(0),i(0),k(0); //Initialize Array for (k=0;k<maxsize;k++) { r[k]=(0); q[k]=(0); } r[i] = b; i++; while (b%a != 0)
{ //Does not divide r[i] = a;
q[i] = b/a; b = a; a = rem; i++; } gcd = rem; if (i == 1) { gcd = a; } r[i] = a;
bottom = i+1;//store length of array for ExtEuclid loop return gcd;
}
/*This function will take 2 parameters sent in and solve a two variable equation using the Extended Euclid Algorithm
a - smaller value; b - larger value */ __int64 ExtEuclid(__int64 a, __int64 b)
{
__int64 d(0),k(0),length(0),i(0); const __int64 max = 5000;
__int64 x[max]; __int64 y[max]; for (k=0;k<max;k++) { x[k]=(0); y[k]=(0); } x[0] = 1; x[1] = 0; y[0] = 0; y[1] = 1; length = bottom;
for (i=2; i<length;i++) {
x[i]=x[i-2]- (q[i-1]* x[i-1]); y[i]=y[i-2]- (q[i-1]* y[i-1]); }
d = y[i-1]; return d; }
void FastEXP(__int64 a, __int64 m, __int64 n) {
IntBin(m); //convert m to a binary integer array
__int64 k = top; //k is equal to the length of the binary integer array cout<<"k "<<k<<endl;
int c = 0;
//Fast Exponentiation Algorithm for (int i = k; i > 0; i--)
{ c = 2*c; d = (d*d) % n; if (bin[i] == 1) { c = c+1; d = (d * a) % n; } cout<<""<<c <<""<< d <<endl; }
cout << "The Power "<<a<<" raised to the "<<m<<" (Mod "<<n<< ") is "<<d<<endl; }
/* This function will take a parameter sent in to determine the value that will be converted into a binary simulated integer array.
Once the array is created, the function will print out the binary number backwards m - Number to be converted into binary */
void IntBin(__int64 m) {
__int64 tmp(1),remain(1); int c(0),i(0),j(0),test(0); bool first(true);
for (i = 0; i < bytesize; i++) { bin[i] = 0; } //initialize array to 0 m = abs(m); while (m != 0) { while (tmp <= m) { tmp = tmp * 2; c++; //gets power }
test = m%2; //determine if even or odd if (c == 0 && test==0)//special case; ones place
{
bin[c]=0;//even number, so assign one's place as 0 }
else
{bin[c]=1;} for (j=1; j<c; j++)
{
remain = remain * 2; //get the actual va // lue of the highest power
}
if (first == true)//run only once {
top = c;//identify the highest power
first = false; //prevent condition from happening again }
m = m - remain; //move to the next significant digit c = 0; //reset counter
remain = 1; //reset remain tmp = 1;//reset tmp
cout<<"m is "<<m<<endl; }
for (i=1;i<top+1;i++){cout<<bin[i];} //print binary cout<<""<<endl;
Experiment no. 7
Objective of performing experiment: Implement Rabin-Miller Primality Testing Algorithm in 'C'.
program: Rabin miller #include<iostream> #include<cmath> void main() { int number = 5; int max = 0; int sr = 0; int i; int modnum = 0;
cout<<"how high do you want your prime number search to go to?"<<endl; cin>> max;
if (max > 1 && max < 100000000) {
cout<<"Prime Numbers"<<endl; cout<<" 2"<<endl;
cout<<" 3"<<endl; while (number < max)
{ sr = sqrt(number); for ( i = 2; i < sr + 2; i++) { modnum = number % i; if (modnum == 0) { //not prime i = sr + 3; } if (modnum != 0 && i == sr + 1) {
for (int j = 0; j < 7500000; j++); //delay
cout<<" "<<number<<endl; //print out prime number }
number++; number++;
} }
else
cout<<"Your choice is not a prime number"<<endl; }