Mikrodenetleyici Tabanlı RSA ile Şifrelenmiş RF Haberleşmeli Kartlı Giriş Sistemi

Yüksek lisans kriptografi dersi için hazırladığım projeyi yayınlıyorum. Ders İngilizce olduğu için raporu da İngilizce yazmıştım. Proje ile ilgili tüm sorularınızı yorum kısmından gönderebilirsiniz. İlerleyen zamanlarda Türkçe’ye çevirebilirim.

Projeye Türkçe bir özet yapmak gerekirse; RSA şifreleme, RF haberleşme, Arduino, RFID teknolojileri / yöntemlerini kullanarak basit bir kartlı geçiş sistemi diyebiliriz.

MCH553 – Computer Systems and Network Security
MCU Based RSA Encrypted Card Entrance System via RFID Cards and RF
Communication Project Report

Mustafa Alper BALIM
Bursa Technical University

Background

RSA is a useful cryptology method for using projects that use 8 and 16 bit MCU’s. In this project; there are two MCU based control unit. First unit reads the RFID card, and second unit allows or rejects entries by controlling the door.

Communication will be made by RF communication modules as encrypted via RSA. First unit will send RFID card ID by encrypting it. Second unit will decrypt received data and will decide to allow or reject entrance. Then second unit will encrypt the answer of entrance request to first unit. First unit will decrypt the answer and will allow/reject the user.

Hardware

The system consist of two MCU’s , an MIFARE RFID Card Reader and two RF communication modules. Each RF modules has two part that recieve and transmit data. Two Arduino Nano based Atmega328 is used as MCU’s and proggrammed via Proccesinglike Arduino language.

System Block Scheme

MCU’s and RF Modules communicates with each other via software serail communication. RFID reader communicates via SPI(Serial Peripheral Interface).

Software

Central MCU Flow Chart
Terminal MCU Flow Chart

Encyrption and Decryption Algorithms & Colde Blocks

Encyrption or Decryption codes starts with define “p” and “q” prime numbers and “w” that determining which “e” and “d” will be used for encryption and decryption.

Defination of Cryptographic Parameters Block:

1. Choose two distinct prime numbers p and q.
2. Compute n = pq
3. Compute t(n) = t(p)t(q) = (p − 1)(q − 1)
4. Choose an integer e such that 1 < e < t(n) and GCD(e, t(n)) = 1
5. Determine d as ed = 1 (mod t(n))

p=37;
q=41;
w=3; // w= which e and d will be used?
n=p*q;
t=(p-1)*(q-1);
find_e(); // Finds “w”th “e” and “d”

Find “e” and “d” Block.

“e” must be 1<e<t and GCD(e,t)=1

p=37;
q=41;
w=3; // w= which e and d will be used?
n=p*q;
t=(p-1)*(q-1);
find_e(); // Finds “w”th “e” and “d” Find “e” and “d” Block.
“e” must be 1<e<t and GCD(e,t)=1
void find_e()
{
int k=0;
for(int i=2;i<t;i++)
{
if(t%i==0) continue; //Turn to start of loop if GCD(e,t)!=1
flag=is_prime(i); //is_prime() returns ”1” if the number is prime.
if(flag==1&&i!=p&&i!=q) //If “i” is prime and different from “p” and differen from “q”
{ // e=i
e=i;
flag=find_d(e); //finds “d” for “e”
if(flag>0)
{
d=flag;
if(k==w)break; // If iteration reached to “w” break the loop.
k++;
}}}}

“d*e” must be equal “1” in mod(t)

int find_d(int x)
{
int k=1;
while(1)
{
k=k+t; //k=( k+t) mod(t)
if(k%x==0) //If appropriate”d” is found return “d”
return(k/x);
}}

Encyrption Block:

Encyrption block computes the ciphertext “c” for plaintext “p” using the public key “e” for every character.

? = ?^? (??? ?)

“encyrpt(char)” function returns two character because ciphertext “c” that computed is too large for standart ANSII “char” variable and values that will be sent by RF module must be “char” variable type. First 8 bit of “c” is kept in cipherText[ctr] and last 8 bit is kept in cipherText[ctr+1]. “cipherText[]” array is doubled. If “p” and “q” is choosen too large, “c” will be larger than 2 “character” (bytes) and, cipherText has to be divided into 3 or more. Because of we have limited memory and limited computing capacity, “p” and “q” has to be chosen smaller then 100.

void encrypt(char *plainText, char *cipherText)
{
long m = 1;
int ctr = 0;
for(int i = 0; i <sizeof_plaintext ; i++) //For every character
{
for(int j = 0; j<e ; j++) //m = plainText()^e (mod n)
{
m = (m * plainText[i]) % n;
}
ctr = i * sizeof(int); //How many bytes an integer?
//Equalize first 8 bit of “m” to cipherText[ctr]
cipherText[ctr] =(char)(m & 0x00ff);
//Shift right second 8 bit of “m” and equalize to cipherText[ctr+1]
cipherText[ctr + 1] = (char) ((m & 0xff00) >> 8);
m = 1;
}}

Decyrption Block:

Decyrption block computes the plaintext “p” for ciphertext “c”using the private key “d” for every character.

? = ?^? (??? ?)

“decyrpt(char)” function gets two character that computed by ”encyrpt()” function and returns one character that belongs to plaintext. Before the computing char array will be reassembled to ”long” variable type by combining two characters cipherText[ctr] and cipherText[ctr+1]. After computing, computed “M” is smaller then “c” (one byte). But it is still stored as two (or more) bytes. ). “M & 0xFF” operatormasks first 8 bit of “M”. And thats equals “plainText[i]”, “i”th character of plaintext.

void decrypt(char *plainText, char *cipherText)
{
long M = 1;
int temp = 0;
int ctr = 0;
for(int i = 0; i < sizeof_plaintext; i++) //For every character (plaintext)
{
ctr = i * sizeof(int); //How many bytes an integer?
//Reassemble the divided cipher characters to ”temp” value.
temp = (((unsigned char)cipherText[ctr + 1] << 8) | (unsigned char)cipherText[ctr]);
for(int j = 0; j < d; j++) //M = cipherText()^d (mod n)
{
M = (M * temp) % n;
}
// “long” “M” converted to “char”plainText[i]
plainText[i] = (unsigned char)(M & 0xFF);
M = 1;
}
}

Every step of application is printed to Arduino IDE Serial Monitor for observing with serial communication by USB ports.

Central MCU Source Code

#include <VirtualWire.h>
char cipher_msg[200];
char plain[25];
//---------------------------------------
int p;
int q;
int n;
int t;
int w;
int e;
int d;
int flag;
//---------------------------------------
char recieved_data[200];
boolean stringComplete = false;
String stringRecieved;
void setup()
{
Serial.begin(9600);
vw_set_rx_pin(A5);
vw_set_tx_pin(A4);
vw_rx_start();
p=37;
q=41;
w=3; // w= which e and d will be used?
n=p*q;
t=(p-1)*(q-1);
find_e(); // Finds “w”th “e” and “d”
//Print parameters.
Serial.print("P=");Serial.println(p);
Serial.print("Q=");Serial.println(q);
Serial.print("N=");Serial.println(n);
Serial.print("T=");Serial.println(t);
Serial.print("E=");Serial.println(e);
Serial.print("D=");Serial.println(d);
}
void loop()
{
uint8_t buf[320];
uint8_t buflen = 320;
vw_setup(2000);
vw_wait_rx(); //Wait if data is not recieved
RF_Read();
if(stringComplete) //If data not recieved
{
Serial.print("Şifreli ID Alındı: ");
Serial.println(stringRecieved);
Serial.print("Kart ID Çözülüyor: ");
decrypt(plain, recieved_data);
String plaintxt="";
//CharArray to String Conversation
for(int i = 0; i <= 25; i++) {plaintxt+=plain[i];}
Serial.println(plaintxt);
String Name = "";
//Users
if(plaintxt=="227435119") Name="yAlper ";
else if(plaintxt=="1821504759") Name="yMisafir ";
else Name="not";
if(plaintxt!="not") Serial.println("ID Eşleşti");
else if(plaintxt=="not") Serial.println("ID Eşleşmedi");
char charName[20];
Name.toCharArray(charName,20);
encrypt(charName, cipher_msg);
Serial.print("Cevap Şifreleniyor: ");
for(int i = 0; i < buflen; i++) {Serial.print(cipher_msg[i]);}
Serial.println();
const char* mesaj = (const char*) cipher_msg;
vw_setup(2000);
vw_send((uint8_t *)mesaj, 320);
}
Serial.println("///////////////////////////////////////////////////////////
");
Serial.println("");
}
// Read data from RF recieve buffer.
void RF_Read()
{
stringRecieved = "";
recieved_data[320] = {};
char inChar;
uint8_t buf[320];
uint8_t buflen = 320;
if (vw_get_message(buf, &buflen))
{
for (int i = 0; i < buflen; i++)
{
inChar = buf[i];
recieved_data[i]=buf[i];
stringRecieved+=inChar;
}
stringComplete=true;
}
}
void find_e()
{
int k=0;
for(int i=2;i<t;i++)
{
if(t%i==0) continue; //Turn to start of loop if GCD(e,t)!=1
flag=is_prime(i); //is_prime() returns ”1” if the number is
//prime.
if(flag==1&&i!=p&&i!=q) //If “i” is prime and different from “p” and
//differen from “q” e=i
{
e=i;
flag=find_d(e); //finds “d” for “e”
if(flag>0)
{
d=flag;
if(k==w)break; // If iteration reached to “w” break the loop.
k++;
}}}}
int find_d(int x)
{
int k=1;
while(1)
{
k=k+t;
if(k%x==0) //k=( k+t) mod(t)
return(k/x); //If appropriate”d” is found return “d”
} }
//Returns "1" if "pr" is a prime number.
int is_prime(int pr)
{
int j;
j=sqrt(pr);
for(int i=2;i<=j;i++)
{
if(pr%i==0)
return 0;
}
return 1;
}
void encrypt(char *plainText, char *cipherText)
{
long m = 1;
int ctr = 0;
for(int i = 0; i < 20; i++) //For every character
{
for(int j = 0; j<e ; j++) //m = plainText()^e (mod n)
{
m = (m * plainText[i]) % n;
}
ctr = i * sizeof(int); //How many bytes an integer?
//Equalize first 8 bit of “m” to cipherText[ctr]
cipherText[ctr] = (char) (m & 0x00ff);
//Shift right second 8 bit of “m” and equalize to
cipherText[ctr+1]
cipherText[ctr + 1] = (char) ((m & 0xff00) >> 8);
m = 1;
}
}
void decrypt(char *plainText, char *cipherText)
{
long M = 1;
int temp = 0;
int ctr = 0;
for(int i = 0; i < 20; i++) //For every character (plaintext)
{
ctr = i * sizeof(int); //How many bytes an integer?
//Reassemble the divided cipher characters to ”temp” value.
temp = (((unsigned char)cipherText[ctr + 1] << 8) | (unsigned
char)cipherText[ctr]);
for(int j = 0; j < d; j++) //M = cipherText()^d (mod n)
{
M = (M * temp) % n;
}
// “long” “M” converted to “char”plainText[i]
plainText[i] = (unsigned char)(M & 0xFF);
M = 1;
}
}

Terminal MCU Source Code

#include <SPI.h>
#include <MFRC522.h>
#include <VirtualWire.h>
#define door_open A0
#define door_closed A2
char cipher_msg[200];
char plain[25];
//---------------------------------------
int p;
int q;
int n;
int t;
int w;
int e;
int d;
int flag;
//---------------------------------------
#define RST_PIN 9
#define SS_PIN 10
MFRC522 mfrc522(SS_PIN, RST_PIN);
MFRC522::MIFARE_Key key;
char gelen_veri[200];
boolean stringComplete = false;
String stringGelen;
byte readCard[4];
char cardID[30];
String stringID="";
int sizeID;
void setup()
{
pinMode(door_open, OUTPUT);
pinMode(door_closed, OUTPUT);
digitalWrite(door_open, LOW);
digitalWrite(door_closed, HIGH);
Serial.begin(9600);
SPI.begin();
mfrc522.PCD_Init();
vw_set_rx_pin(A5);
vw_set_tx_pin(A4);
vw_rx_start();
p=37;
q=41;
w=3; // w= which e and d will be used?
n=p*q;
t=(p-1)*(q-1);
find_e(); // Finds “w”th “e” and “d”
//Print parameters.
Serial.print("P=");Serial.println(p);
Serial.print("Q=");Serial.println(q);
Serial.print("N=");Serial.println(n);
Serial.print("T=");Serial.println(t);
Serial.print("E=");Serial.println(e);
Serial.print("D=");Serial.println(d);
}
void loop()
{
uint8_t buf[320];
uint8_t buflen = 320;
//Wait for new card
if ( ! mfrc522.PICC_IsNewCardPresent()) return;
if ( ! mfrc522.PICC_ReadCardSerial()) return;
Serial.print("Kart ID Okunuyor: ");
ID_Read();
mfrc522.PICC_HaltA();
Serial.println(stringID);
Serial.print("Kart ID Şifreleniyor: ");
encrypt( cardID, cipher_msg);
for(int i = 0; i < buflen; i++)
Serial.print(cipher_msg[i]);
Serial.println();
Serial.println("Şifreli ID Gönderiliyor...");
const char* mesaj = (const char*) cipher_msg;
vw_setup(2000);
vw_send((uint8_t *)mesaj, buflen);
Serial.println("Giriş İzni Bekleniyor");
delay(4500); //Wait for Central MCU's Answer
RF_Read(); // Read data from RF recieve buffer.
Serial.println("Cevap Alındı");
decrypt(plain, gelen_veri);
String plaintxt="";
for(int i = 0; i <= plaintxt.length()+1; i++)
plaintxt+=plain[i];
if(plaintxt=="not") Serial.println("Giriş İzni Verilmedi");
else if(plain[0]=='y')
{
Serial.print("Giriş İzni Verildi => ");
Serial.print("Kullanıcı:");
for(int i=1;i<25;i++) Serial.print(plain[i]);
Serial.println("");
digitalWrite(door_open, HIGH);
digitalWrite(door_closed, LOW);
}
plain[0]='x';
Serial.println("///////////////////////////////////////////////////////////
");
Serial.println("");
delay(3000);
digitalWrite(door_open, LOW); //Open Door
digitalWrite(door_closed, HIGH); // Close Door
}
//Read Card ID and convert to char array and string
void ID_Read()
{
stringID="";
for (int i = 0; i < 4; i++)
{
readCard[i] = mfrc522.uid.uidByte[i];
stringID+=readCard[i];
}
sizeID=stringID.length()+1;
stringID.toCharArray(cardID, sizeID ) ;
}
//// Read data from RF recieve buffer and convert to string and char array.
void RF_Read()
{
uint8_t buf[320];
uint8_t buflen = 320;
stringGelen = "";
gelen_veri[320] = {};
char inChar;
if (vw_get_message(buf, &buflen))
{
for (int i = 0; i < buflen; i++)
{
inChar = buf[i];
gelen_veri[i]=buf[i];
stringGelen+=inChar;
}
stringComplete=true;
}}
void find_e()
{
int k=0;
for(int i=2;i<t;i++)
{
if(t%i==0) continue;
flag=is_prime(i);
if(flag==1&&i!=p&&i!=q)
{
e=i;
flag=find_d(e);
if(flag>0)
{
d=flag;
if(k==w)break;
k++;
}}}}
int find_d(int x)
{
int k=1;
while(1)
{
k=k+t;
if(k%x==0)
return(k/x);
}}
int is_prime(int pr)
{
int j;
j=sqrt(pr);
for(int i=2;i<=j;i++)
{
if(pr%i==0)
return 0;
}
return 1;
}
void encrypt(char *plainText, char *cipherText)
{
long m = 1;
int ctr = 0;
for(int i = 0; i <sizeID ; i++)
{
for(int j = 0; j<e ; j++)
{
m = (m * plainText[i]) % n;
}
ctr = i * sizeof(int);
cipherText[ctr] = (char) (m & 0x00ff);
cipherText[ctr + 1] = (char) ((m & 0xff00) >> 8);
m = 1;
}}
void decrypt(char *plainText, char *cipherText)
{
long M = 1;
int temp = 0;
int ctr = 0;
//re-assemble char array to array of int
for(int i = 0; i < sizeID; i++) {
ctr = i * sizeof(int);
temp = (((unsigned char)cipherText[ctr + 1] << 8) | (unsigned
char)cipherText[ctr]);
for(int j = 0; j < d; j++) {
M = (M * temp) % n;
}
plainText[i] = (unsigned char)(M & 0xFF);
M = 1;
}}