Şİfreleme (c# kodlari) (dersteki haliyle duruyor ......bifid Şifreleme (İki boyutlu Şifreleme)...
TRANSCRIPT
ŞİFRELEME (C# KODLARI) (dersteki haliyle duruyor, düzenlenmedi)
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs"
Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" onclick="Button1_Click"
Text="Kodla" />
<br />
<br />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<br />
<br />
<asp:Button ID="Button2" runat="server" onclick="Button2_Click"
Text="Kod Çöz" />
<asp:Label ID="Label2" runat="server" Text="Label"></asp:Label>
</div>
</form>
</body>
</html>
********************
using System;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
//Kodlama (şifreleme)
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = base64Encode(TextBox1.Text);
}
//Kod çözme (Şifre Çözme)
protected void Button2_Click(object sender, EventArgs e)
{
Label2.Text = base64Decode(Label1.Text);
}
// Kodlayan Alt Fonksiyon------------------------
public string base64Encode(string data)
{
try
{
byte[] encData_byte = new byte[data.Length];
encData_byte = System.Text.Encoding.UTF8.GetBytes(data);
string encodedData = Convert.ToBase64String(encData_byte);
return encodedData;
}
catch (Exception e)
{
throw new Exception("Error in base64Encode" + e.Message);
}
}
//Kod çözen alt fonksiyon--------------------------------
public string base64Decode(string data)
{
try
{
System.Text.UTF8Encoding encoder = new
System.Text.UTF8Encoding();
System.Text.Decoder utf8Decode = encoder.GetDecoder();
byte[] todecode_byte = Convert.FromBase64String(data);
int charCount = utf8Decode.GetCharCount(todecode_byte, 0,
todecode_byte.Length);
char[] decoded_char = new char[charCount];
utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length,
decoded_char, 0);
string result = new String(decoded_char);
return result;
}
catch (Exception e)
{
throw new Exception("Error in base64Decode" + e.Message);
}
}
}
Bifid Şifreleme (İki Boyutlu Şifreleme) by Volkan Atasever 11. Kasım 2009 14:22
Bifid şifreleme de, 5x5 bir matris alınır, satır ve sütunlar numaralandırılır. Bu matris bizim rasgele
oluşturacağımız matristir. 5x5 olabileceği gibi,7x7 veya 8x8 gibi orantılı büyüklüklerde matris
oluşturabiliriz.
Mesajı sabit sayıda harf içeren parçalara ayrılır, daha sonra her harfin altına satır ve kolon numaraları
yazılır. Bu sayede matrisimizde satır ve sütun rakamlarını kullanmış oluruz. Gruplamalar matrisin satır
veya sütun büyüklüğü kadardır.
ve daha sonra her grup içinde kalarak sayıları sırasıyla 11555 14535 52453 33435 . . . şeklinde okuyup ikili
rakamlardan oluşan 11 55 51 45 35 52 . . . şeklindeki parçalara ayrılır. Ve bu parçaların tablodaki harf
karşılıkları bize gizli bir mesaj verecektir.
Şifrelenmiş rakamımız bu sayede elimize geçmiş olacaktır.
Bu şifreleme için kullandığım arayüz aşağıdadır. Konsol uygulaması olarak sade bir arayüz kullandım.
class Program
{
static void Main(string[] args)
{
string d;
do{
Bifid bfd = new Bifid();
Console.WriteLine("\nBifid Şifreleme");
Console.WriteLine("Açmak için 1");
Console.WriteLine("Şifreleme için 2");
Console.WriteLine("Çıkmak için 5");
d=Console.ReadLine();
if(d=="1"){
string msj;
string don;
Console.WriteLine("Decrypt yapılacak mesajı girin");
msj = Console.ReadLine();
don=bfd.EncryptDecrypt(msj, false);
Console.Write(don);
}
else if(d=="2"){
string msj;
string don;
Console.WriteLine("Encrypt yapılacak mesajı girin");
msj = Console.ReadLine();
don = bfd.EncryptDecrypt(msj, true);
Console.WriteLine(don);
}
else if(d=="5")
break;
else
Console.WriteLine("Lütfen seçim yağınız çıkış için 5");
}while(d!="5");
}
}
Bifid Algoritması için bifid şifreleme sınıfım;
public class Bifid
{
string[,] KeyMatrix = new string[5, 5];
public Bifid()
{
BuildKeyMatrix();
}
private void BuildKeyMatrix()
{
int k = 65;
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
if (k == 74) { k++; } // j’yi alma (j ascii = 64)
KeyMatrix[i, j] = ((char)k).ToString();
k++;
}
}
}
public string EncryptDecrypt(string Text, bool Encrypt)
{
int k = 0;
string CharofMessage = string.Empty;
StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder();
StringBuilder sbOut = new StringBuilder();
bool HasGotChar = false;
while (k < Text.Length)
{
CharofMessage = Text.Substring(k, 1);
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
if (string.Compare(KeyMatrix[i, j], CharofMessage, true) == 0)
{
sb1.Append(i.ToString());
if (Encrypt)
sb2.Append(j.ToString());
else
sb1.Append(j.ToString());
HasGotChar = true;
break;
}
}
if (HasGotChar)
{
HasGotChar = false;
break;
}
}
k++;
}
k = 0;
if (Encrypt)
{
sb1.Append(sb2.ToString());
while (k < sb1.Length)
{
sbOut.Append(KeyMatrix[Convert.ToInt32(sb1[k].ToString()), Convert.ToInt32(sb1[k +
1].ToString())]);
k += 2;
}
}
else
{
int SplitNum = (sb1.Length) / 2;
while (k < SplitNum)
{
sbOut.Append(KeyMatrix[Convert.ToInt32(sb1[k].ToString()), Convert.ToInt32(sb1[k +
SplitNum].ToString())]);
k++;
}
}
return sbOut.ToString();
}
}
Bu sınıfta üç temel işlem gerçekleşmektedir. 5x5 boyutundaki matrisin oluşumu. Mesajın şifrelenmesi ve
mesajın çözülmesi.
Kaynaklar:
[1] Öğr. Gör. Erdal Güvenoğlu’ nun Bilgi Sistemleri ve Güvenliği Ders notları
[2]http://programmingpraxis.com/2009/10/13/bifid-cipher/
*************
VERİ ŞİFRELEME Bu yazıda ele alınan yöntem ile veri şifreleme olayı gerçekleştirilecektir. Şifreleme olayını
sağlayacak olan .dll dosyası oluşturulacaktır. Yani projemiz “Class Library” tipinde olacaktır.
Projemiz içerisinde iki tane “Class” ımız bulunacak. Bunlardan birisi veriyi şifrelemeyi
sağlayan “sifreKoy” sınıfı, diğeri şifreli veriyi eski haline döndürecek olan “sifreCoz”
sınıfıdır.
İlk olarak “sifreKoy” sınıfımızdan başlayalım… Bu sınıfımız içerisine dışarıdan parametre
olarak bir veri gelecek ve sınıf içerisindeki işlemler sonucunda geriye verinin şifrelenmiş hali
dönecektir. Peki şifreleme olayı nasıl gerçekleşecek? Bir örnek üzerinde açıklamamız
gerekirse; diyelim ki bir üye kayıt sayfasında üyenin girdiği parola veri tabanına şifrelenmiş
bir şekilde kaydedilecek. Üyemizin belirlediği parolanın “karabük” olduğunu varsayalım. Biz
“karabük” verisini şifreleyerek sadece “1” ve “0” lardan meydana gelen anlaşılmaz bir veri
haline getireceğiz. Bunun için parolanın her bir karakterini ayrı ayrı işleyeceğiz. Bir döngü
içerisinde sırayla tüm karakterler üzerinde işlem yapacağız. İlk olarak işlem yaptığımız
karakterin ascii kodunu bulacağız. Ardından bu değeri f(x)=255-x fonksiyonuna sokarak
sahip olduğu ascii kodunun ilk şifreleme işlemini gerçekleştirmiş olacağız. Buradaki
f(x)=255-x olmasının nedeni en büyük ascii kodunun 255 olmasından kaynaklanmaktadır. Bu
fonksiyondan 0 ile 255 arasında bir sayı çıkabilmektedir. Yani her bir karakteri 8 bitlik(1 ve 0
lardan meydana gelen) hale dönüştüreceğiz.Bunun yerine başka bir fonksiyon da
belirleyebiliriz elbette, fakat kaç bitlik veri ile uğraşacağımızı doğru hesap edip olabilecek
hataların önüne geçmeliyiz.
İşlem gören karakterin ascii kodunun f(x) fonksiyonuna soktuktan sonra elde ettiğimiz değeri
ikilik taban çevireceğiz ve bu haliyle kayıt edeceğiz. Burada dikkat edilmesi gereken nokta;
ikilik tabandaki verinin hane sayısıdır. Eğer elde ettiğimiz veri 8 karakterden az ise başına 0
koyarak 8 haneye ulaşmalıyız. Çünkü bu şifreyi çözerken 8 bitlik veriler halinde işlem
yapacağız.
“sifreKoy” sınıfımızda 3 tane fonksiyonumuz ve bu sınıf içerisinde global olarak
tanımladığımız değişkenimiz bulunmaktadır. Değişkenimiz, sadece bu sınıf içerisinde
kullanılabilecektir ve dışarıdan gelecek olan şifrelenmemiş veriyi temsil edecektir;
private string sifresizVeri;
Yukarıda bahsedildiği gibi “private” deyimi sayesinde bu değişken sadece bu sınıf içerisinde
kullanılabilecektir.
Şimdi sınıfımızın kurucu fonksiyonuna gelelim. Kurucu fonksiyonlar sınıfın ismini alırlar ve
geriye değer döndürmezler. Bizim “sifreKoy” sınıfımızda da “sifresizVeri” değişkenimize ilk
değer atamasının gerçekleştirilmesi için kurucu fonksiyonumuzu yazalım;
public sifreKoy(string gelen)
{
sifresizVeri = gelen;
}
Kurucu fonksiyonumuz sayesinde “sifresizVeri” değişkenimize dışarıdan gelecek olan
“gelen” değişkeni atanacaktır.
Şimdi sıra şifrelemeyi gerçekleştirecek olan “veriSifrele()” fonksiyonumuzu yazmaya geldi.
Bu fonksiyonumuza dışarıdan da erişmemiz gerekeceği için erişim düzeyi “public” olmalıdır.
public string veriSifrele()
{
char karakter;
string cikanDeger = null;
int Ascii, sifreliAscii;
for (int i = 0; i != sifresizVeri.Length; i++)
{
karakter = Convert.ToChar(sifresizVeri.Substring(i,1));
Ascii = (int)karakter;
sifreliAscii = 255 - Ascii;
cikanDeger += binaryCevir(sifreliAscii);
}
return cikanDeger;
}
Fonksiyon incelendiğinde, sırayla verinin tüm karakterleri üzerinde işlem yapıldığı fark
edilmektedir. Önce işlem yapılacak karakter belirleniyor ardından bu karakterin ascii kodu
bulunup, bu değer f(x)=255-x fonksiyonuna sokulmaktadır. Bundan sonra da elimizdeki veri
“binaryCevir” fonksiyonuna gönderilerek, ikilik tabandaki hali elde edilmektedir. Her
karakterin şifreli halleri ardı ardına eklenerek son hali geri döndürülmektedir.
private string binaryCevir(int gelen)
{
string binaryTers = null;
while (gelen >= 2)
{
binaryTers += Convert.ToString(gelen%2);
gelen = gelen / 2;
}
binaryTers += Convert.ToString(gelen);
string binaryDuz = null;
for (int i = 0; i != binaryTers.Length; i++)
binaryDuz += binaryTers.Substring(binaryTers.Length-1-i,1);
while (binaryDuz.Length < 8)
{
binaryDuz += "0";
}
return binaryDuz;
}
“binaryCevir” fonksiyonumuza baktığımızda ise bu fonksiyonunu paylaşımının “private”
olduğunu görüyoruz. Bunun sebebi bu fonksiyonun sadece bu sınıf içerisinden çağırılmasıdır.
Yani dışarıdan bu fonksiyonu çağırmamıza gerek yoktur.
Şifreleme işlemimizi gerçekleştirdikten sonra şimdi de, şifrelenmiş bir veriyi eski haline
döndürelim.
“sifreCoz” sınıfımızla dışarıdan gelen şifreli veriyi eski haline döndüreceğiz. Bu sınıfımızda
iki tane fonksiyonumuz ve yine sadece bu sınıf içerisinde kullanabileceğimiz bir değişkenimiz
olacaktır.
private string sifreliVeri;
“sifreliVeri” değişkenimize değer atamamızı sağlayan kurucu fonksiyonumuz;
public sifreCoz(string gelen)
{
sifreliVeri = gelen;
}
Son olarak da şifreyi çözmemizi sağlayacak olan “sifreyiKir()” fonksiyonumuz;
public string sifreyiKir()
{
string cikanDeger = null;
string byteVeri;
int ilkBit = 0;
int Ascii;
int veriUzunlugu = sifreliVeri.Length;
while(ilkBit<=veriUzunlugu-8)
{
byteVeri=sifreliVeri.Substring(ilkBit,8);
int sifreliAscii=0;
for(int i=0;i!=8;i++)
sifreliAscii+=(Convert.ToInt16(byteVeri.Substring(i,1)))*Convert.ToInt16
(Math.Pow(2,Convert.ToInt16(byteVeri.Length-1-i)));
Ascii = 255 - sifreliAscii;
cikanDeger = cikanDeger + Convert.ToString((char)Ascii);
ilkBit += 8;
}
return cikanDeger;
}
Bu fonksiyon içerisinde, şifreli verimiz 8 bitlik bloklar halinde işleme alınarak önce onluk
sayı sistemine dönüştürülüyor. Ardından bu sayı 255’ten çıkarılarak karakterimizin gerçek
ascii kodunu elde etmiş oluyoruz. Ascii kodunu string bir ifadeye dönüştürerek, sırayla tüm
karakterleri ardı ardına ekliyoruz ve gerçek verimizi elde ediyoruz.
Projenin tüm kodları aşağıda verilmiştir.
using System;
using System.Collections.Generic;
using System.Text;
namespace sifre
{
public class sifreCoz
{
public sifreCoz(string gelen)
{
sifreliVeri = gelen;
}
public string sifreyiKir()
{
string cikanDeger = null;
string byteVeri;
int ilkBit = 0;
int Ascii;
int veriUzunlugu = sifreliVeri.Length;
while(ilkBit<=veriUzunlugu-8)
{
byteVeri=sifreliVeri.Substring(ilkBit,8);
int sifreliAscii=0;
for(int i=0;i!=8;i++)
sifreliAscii+=(Convert.ToInt16(byteVeri.Substring(i,1)))*Convert.ToInt16
(Math.Pow(2,Convert.ToInt16(byteVeri.Length-1-i)));
Ascii = 255 - sifreliAscii;
cikanDeger = cikanDeger + Convert.ToString((char)Ascii);
ilkBit += 8;
}
return cikanDeger;
}
private string sifreliVeri;
}
public class sifreKoy
{
public sifreKoy(string gelen)
{
sifresizVeri = gelen;
}
public string veriSifrele()
{
char karakter;
string cikanDeger = null;
int Ascii, sifreliAscii;
for (int i = 0; i != sifresizVeri.Length; i++)
{
karakter = Convert.ToChar(sifresizVeri.Substring(i,1));
Ascii = (int)karakter;
sifreliAscii = 255 - Ascii;
cikanDeger += binaryCevir(sifreliAscii);
}
return cikanDeger;
}
private string binaryCevir(int gelen)
{
string binaryTers = null;
while (gelen >= 2)
{
binaryTers += Convert.ToString(gelen%2);
gelen = gelen / 2;
}
binaryTers += Convert.ToString(gelen);
string binaryDuz = null;
for (int i = 0; i != binaryTers.Length; i++)
binaryDuz += binaryTers.Substring(binaryTers.Length-1-i,1);
while (binaryDuz.Length < 8)
{
binaryDuz += "0";
}
return binaryDuz;
}
private string sifresizVeri;
}
}
Projemizi derleyip kaydettikten sonra artık .dll dosyamız kullanıma hazırdır. Oluşturduğumuz
.dll nin çalışıp çalışmadığını kontrol etmek için bir “Windows application” projesi
oluşturalım. Burada bir veriyi önce şifreleyelim sonra da bu şifreyi çözdürerek gösterelim.
Formumuzu aşağıdaki gibi tasarlayalım;
“Girilen Veri” kutusuna bir veri girip “Şifrele” butonuna bastığımızda “Şifrelenmiş Veri”
kutusunda verinin şifreli halini görüntüleyelim. Bundan sonra “Şifreyi Çöz” butonuna
bastığımızda da “Şifresi Çözülmüş Veri” kutusunda şifreyi çözerek görüntüleyelim.
İlk olarak projemize referans olarak .dll dosyamızı eklemeliyiz ve ardından da “using sifre”
ile proje içerisinden çağırmalıyız.
Şimdi “Şifrele” butonumuzun kodlarını yazalım;
private void buttonSifrele_Click(object sender, EventArgs e)
{
sifreKoy a = new sifreKoy(textBoxGirilenVeri.Text);
textBoxSifrelenmisVeri.Text = a.veriSifrele();
}
Görüldüğü gibi iki satırlık kod ile ilk kutudaki veriyi şifreledik. Projemizi çalıştırdığımızda;
“ac” verinin şifrelenmiş hali altındaki textbox içerisinde görüntülenmektedir. Şimdi “Şifreyi
Çöz” butonumuza gerekli kodları yazarak şifreli veriyi çözerek “Şifresi Çözülmüş Veri”
kutusunda görüntüleyelim;
private void buttonSifreCoz_Click(object sender, EventArgs e)
{
sifreCoz a = new sifreCoz(textBoxSifrelenmisVeri.Text);
textBoxCozulmusVeri.Text = a.sifreyiKir();
}
Projemizi çalıştırıp, ilk kutuya verimizi girip sırayla butonlara bastığımızda;
256 BİTLİK ŞİFRELEME ALGORİTMASI
//UYE GIRİŞ BUTONU*******************************************
protected void ButtonButtonUyeGiris_Click(object sender, EventArgs e)
{
Nesneler Nesne = new Nesneler();
LabelGiris.Text = Nesne.UyeGirisiKontrol(TextBoxKullaniciAdi.Text,
TextBoxSifre.Text);
}
//ÜYE GİRİŞİ YAP
=========================================================
public string UyeGirisiKontrol(string KullaniciAdi, string Sifre)
{
Nesneler Nesne = new Nesneler();
//String Sorgu = string.Format("SELECT UyeID, UyeTipi, UyelikDurumu
FROM UyelerID WHERE KullaniciAdi ='{0}' AND Sifre ='{1}'", KullaniciAdi,
Sifre);
String Sorgu = string.Format("SELECT * FROM UyelerID");
OleDbDataReader Okuyucu = Nesne.BilgileriReaderaOku(Sorgu);
while (Okuyucu.Read()) // okunacak kayıt varsa kullaniciAdi ve
şifre doğru demektir..
{
string SifreCozulmusKullaniciAdi=
Sifreleme(Okuyucu["KullaniciAdi"].ToString(),false);
string SifreCozulmusSifre =
Sifreleme(Okuyucu["Sifre"].ToString(), false);
if (SifreCozulmusKullaniciAdi == KullaniciAdi &&
SifreCozulmusSifre == Sifre) //Kullanici Adi şifrelenerek kaydedildiğinden
önce şifreyi çözüyor.
{
if (bool.Parse(Okuyucu["UyelikDurumu"].ToString()) == true)
//Eğer şifre iptal edilmemişse girişe izin verecek.
{
HttpCookie Cerez = new HttpCookie("Cerez");
if (Okuyucu["UyeTipi"].ToString() == "FirmaUye")
{
Cerez.Values["FirmaID"] =
Okuyucu["UyeID"].ToString();
HttpContext.Current.Response.Cookies.Add(Cerez);
int FirmaID =
int.Parse(HttpContext.Current.Request.Cookies["Cerez"]["FirmaID"]);
//Çerezden FirmaID sini tekrar okuyup diğer sayfaya gönderecek
Nesne.AdminIstatistikleriniKaydet(FirmaID);
HttpContext.Current.Response.Redirect(string.Format("~/FirmaZiyaretci/Firma
AnaSayfa.aspx?FirmaID={0}", FirmaID));
}
else if (Okuyucu["UyeTipi"].ToString() ==
"ZiyaretciUye")
{
Cerez.Values["ZiyaretciID"] =
Okuyucu["UyeID"].ToString();
HttpContext.Current.Response.Cookies.Add(Cerez);
int ZiyaretciID =
int.Parse(HttpContext.Current.Request.Cookies["Cerez"]["ZiyaretciID"]);
//Çerezden FirmaID sini tekrar okuyup diğer sayfaya gönderecek
Nesne.AdminIstatistikleriniKaydet(ZiyaretciID);
HttpContext.Current.Response.Redirect(string.Format("~/ZiyaretciSayfalari/Z
iyaretciAnaSayfa.aspx?ZiyaretciID={0}", ZiyaretciID));
}
else if (Okuyucu["UyeTipi"].ToString() ==
"AkademikUye")
{
Cerez.Values["AkademikID"] =
Okuyucu["UyeID"].ToString(); //FirmaID sini çereze atıyor..
HttpContext.Current.Response.Cookies.Add(Cerez);
int AkademikID =
int.Parse(HttpContext.Current.Request.Cookies["Cerez"]["FirmaID"]);
//Çerezden FirmaID sini tekrar okuyup diğer sayfaya gönderecek
Nesne.AdminIstatistikleriniKaydet(AkademikID);
HttpContext.Current.Response.Redirect(string.Format("~/AkademikSayfalar/Aka
demikAnaSayfa.aspx?AkademikID={0}", AkademikID));
}
else
{
return "Üye tipinde hata vardır. Hata kodu:102!";
}
}
else
{
return "Şifrenin Kullanımı Durdurulmuş!";
}
break;
}
}
Nesne.Kapat();
return "Veritabanında böyle bir üye kayıtlı degildir! Hata
kodu:103!";
}
//Sifreleme Yapacak/Çözecek
======================================================
public string Sifreleme(string Metin, bool islem)
{
string SifreIfadesi = "abc"; //Şifreleme anahtarı 1-çok gizli tut
Herhangi bir metin olabilir Örnek:"Pas5pr@se"
string BaslangicVektoru = "abc"; //Şifreleme anahtarı 2-çok gizli
tut 16 byte olmalıdır Örnek: "@abc"
if (islem == true) //Sifreleme Yapacak
{
SifrelemeSinifi AlgoritmaAnahtari = new
SifrelemeSinifi(SifreIfadesi, BaslangicVektoru);
string SifrelenmisMetin = AlgoritmaAnahtari.Sifrele(Metin);
return SifrelenmisMetin;
}
else //Şifreyi Çözecek
{
SifrelemeSinifi AlgoritmaAnahtari = new
SifrelemeSinifi(SifreIfadesi, BaslangicVektoru);
string CozulmusMetin = AlgoritmaAnahtari.SifreCoz(Metin);
return CozulmusMetin;
}
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////
//******************************* ŞİFRELEME İÇİN HAZIRLANAN NESNELER
********************************
public class SifrelemeSinifi
{
private static string DEFAULT_HASH_ALGORITHM = "SHA1";
private static int DEFAULT_KEY_SIZE = 256;
private static int MAX_ALLOWED_SALT_LEN = 255;
private static int MIN_ALLOWED_SALT_LEN = 4;
private static int DEFAULT_MIN_SALT_LEN = MIN_ALLOWED_SALT_LEN;
private static int DEFAULT_MAX_SALT_LEN = 8;
private int minSaltLen = -1;
private int maxSaltLen = -1;
private ICryptoTransform encryptor = null;
private ICryptoTransform decryptor = null;
public SifrelemeSinifi(string SifreIfadesi)
: this(SifreIfadesi, null)
{
}
public SifrelemeSinifi(string SifreIfadesi, string BaslangicVektoru)
: this(SifreIfadesi, BaslangicVektoru, -1)
{
}
public SifrelemeSinifi(string SifreIfadesi, string BaslangicVektoru,
int minSaltLen)
: this(SifreIfadesi, BaslangicVektoru, minSaltLen, -1)
{
}
public SifrelemeSinifi(string SifreIfadesi,
string BaslangicVektoru,
int minSaltLen,
int maxSaltLen) :
this(SifreIfadesi, BaslangicVektoru, minSaltLen, maxSaltLen, -1)
{
}
public SifrelemeSinifi(string SifreIfadesi,
string BaslangicVektoru,
int minSaltLen,
int maxSaltLen,
int keySize) :
this(SifreIfadesi, BaslangicVektoru, minSaltLen, maxSaltLen,
keySize, null)
{
}
public SifrelemeSinifi(string SifreIfadesi,
string BaslangicVektoru,
int minSaltLen,
int maxSaltLen,
int keySize,
string hashAlgorithm) :
this(SifreIfadesi, BaslangicVektoru, minSaltLen, maxSaltLen,
keySize,
hashAlgorithm, null)
{
}
public SifrelemeSinifi(string SifreIfadesi,
string BaslangicVektoru,
int minSaltLen,
int maxSaltLen,
int keySize,
string hashAlgorithm,
string saltValue) :
this(SifreIfadesi, BaslangicVektoru, minSaltLen, maxSaltLen,
keySize,
hashAlgorithm, saltValue, 1)
{
}
public SifrelemeSinifi(string SifreIfadesi,
string BaslangicVektoru,
int minSaltLen,
int maxSaltLen,
int keySize,
string hashAlgorithm,
string saltValue,
int passwordIterations)
{
// Save min salt length; set it to default if invalid value is
passed.
if (minSaltLen < MIN_ALLOWED_SALT_LEN)
this.minSaltLen = DEFAULT_MIN_SALT_LEN;
else
this.minSaltLen = minSaltLen;
// Save max salt length; set it to default if invalid value is
passed.
if (maxSaltLen < 0 || maxSaltLen > MAX_ALLOWED_SALT_LEN)
this.maxSaltLen = DEFAULT_MAX_SALT_LEN;
else
this.maxSaltLen = maxSaltLen;
// Set the size of cryptographic key.
if (keySize <= 0)
keySize = DEFAULT_KEY_SIZE;
// Set the name of algorithm. Make sure it is in UPPER CASE and
does
// not use dashes, e.g. change "sha-1" to "SHA1".
if (hashAlgorithm == null)
hashAlgorithm = DEFAULT_HASH_ALGORITHM;
else
hashAlgorithm = hashAlgorithm.ToUpper().Replace("-", "");
// Initialization vector converted to a byte array.
byte[] initVectorBytes = null;
// Salt used for password hashing (to generate the key, not during
// encryption) converted to a byte array.
byte[] saltValueBytes = null;
// Get bytes of initialization vector.
if (BaslangicVektoru == null)
initVectorBytes = new byte[0];
else
initVectorBytes = Encoding.ASCII.GetBytes(BaslangicVektoru);
// Get bytes of salt (used in hashing).
if (saltValue == null)
saltValueBytes = new byte[0];
else
saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
// Generate password, which will be used to derive the key.
PasswordDeriveBytes password = new PasswordDeriveBytes(
SifreIfadesi,
saltValueBytes,
hashAlgorithm,
passwordIterations);
// Convert key to a byte array adjusting the size from bits to
bytes.
byte[] keyBytes = password.GetBytes(keySize / 8);
// Initialize Rijndael key object.
RijndaelManaged symmetricKey = new RijndaelManaged();
// If we do not have initialization vector, we cannot use the CBC
mode.
// The only alternative is the ECB mode (which is not as good).
if (initVectorBytes.Length == 0)
symmetricKey.Mode = CipherMode.ECB;
else
symmetricKey.Mode = CipherMode.CBC;
// Create encryptor and decryptor, which we will use for
cryptographic
// operations.
encryptor = symmetricKey.CreateEncryptor(keyBytes,
initVectorBytes);
decryptor = symmetricKey.CreateDecryptor(keyBytes,
initVectorBytes);
}
//-----------------------------------------------------
public string Sifrele(string SifrelenecekMetin)
{
return Sifrele(Encoding.UTF8.GetBytes(SifrelenecekMetin));
}
public string Sifrele(byte[] plainTextBytes)
{
return Convert.ToBase64String(EncryptToBytes(plainTextBytes));
}
public byte[] EncryptToBytes(string SifrelenecekMetin)
{
return EncryptToBytes(Encoding.UTF8.GetBytes(SifrelenecekMetin));
}
public byte[] EncryptToBytes(byte[] plainTextBytes)
{
// Add salt at the beginning of the plain text bytes (if needed).
byte[] plainTextBytesWithSalt = AddSalt(plainTextBytes);
// Encryption will be performed using memory stream.
MemoryStream memoryStream = new MemoryStream();
// Let's make cryptographic operations thread-safe.
lock (this)
{
// To perform encryption, we must use the Write mode.
CryptoStream cryptoStream = new CryptoStream(
memoryStream,
encryptor,
CryptoStreamMode.Write);
// Start encrypting data.
cryptoStream.Write(plainTextBytesWithSalt,
0,
plainTextBytesWithSalt.Length);
// Finish the encryption operation.
cryptoStream.FlushFinalBlock();
// Move encrypted data from memory into a byte array.
byte[] cipherTextBytes = memoryStream.ToArray();
// Close memory streams.
memoryStream.Close();
cryptoStream.Close();
// Return encrypted data.
return cipherTextBytes;
}
}
//-----------------------------------------------
public string SifreCoz(string SifrelenmisMetin)
{
return SifreCoz(Convert.FromBase64String(SifrelenmisMetin));
}
public string SifreCoz(byte[] cipherTextBytes)
{
return Encoding.UTF8.GetString(DecryptToBytes(cipherTextBytes));
}
public byte[] DecryptToBytes(string SifrelenmisMetin)
{
return DecryptToBytes(Convert.FromBase64String(SifrelenmisMetin));
}
public byte[] DecryptToBytes(byte[] cipherTextBytes)
{
byte[] decryptedBytes = null;
byte[] plainTextBytes = null;
int decryptedByteCount = 0;
int saltLen = 0;
MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
decryptedBytes = new byte[cipherTextBytes.Length];
// Let's make cryptographic operations thread-safe.
lock (this)
{
// To perform decryption, we must use the Read mode.
CryptoStream cryptoStream = new CryptoStream(
memoryStream,
decryptor,
CryptoStreamMode.Read);
// Decrypting data and get the count of plain text bytes.
decryptedByteCount = cryptoStream.Read(decryptedBytes,
0,
decryptedBytes.Length);
// Release memory.
memoryStream.Close();
cryptoStream.Close();
}
// If we are using salt, get its length from the first 4 bytes of
plain
// text data.
if (maxSaltLen > 0 && maxSaltLen >= minSaltLen)
{
saltLen = (decryptedBytes[0] & 0x03) |
(decryptedBytes[1] & 0x0c) |
(decryptedBytes[2] & 0x30) |
(decryptedBytes[3] & 0xc0);
}
// Allocate the byte array to hold the original plain text (without
salt).
plainTextBytes = new byte[decryptedByteCount - saltLen];
// Copy original plain text discarding the salt value if needed.
Array.Copy(decryptedBytes, saltLen, plainTextBytes,
0, decryptedByteCount - saltLen);
// Return original plain text value.
return plainTextBytes;
}
//--------------------------------------------------------
private byte[] AddSalt(byte[] plainTextBytes)
{
// The max salt value of 0 (zero) indicates that we should not use
// salt. Also do not use salt if the max salt value is smaller than
// the min value.
if (maxSaltLen == 0 || maxSaltLen < minSaltLen)
return plainTextBytes;
// Generate the salt.
byte[] saltBytes = GenerateSalt();
// Allocate array which will hold salt and plain text bytes.
byte[] plainTextBytesWithSalt = new byte[plainTextBytes.Length +
saltBytes.Length];
// First, copy salt bytes.
Array.Copy(saltBytes, plainTextBytesWithSalt, saltBytes.Length);
// Append plain text bytes to the salt value.
Array.Copy(plainTextBytes, 0,
plainTextBytesWithSalt, saltBytes.Length,
plainTextBytes.Length);
return plainTextBytesWithSalt;
}
private byte[] GenerateSalt()
{
// We don't have the length, yet.
int saltLen = 0;
// If min and max salt values are the same, it should not be
random.
if (minSaltLen == maxSaltLen)
saltLen = minSaltLen;
// Use random number generator to calculate salt length.
else
saltLen = GenerateRandomNumber(minSaltLen, maxSaltLen);
// Allocate byte array to hold our salt.
byte[] salt = new byte[saltLen];
// Populate salt with cryptographically strong bytes.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetNonZeroBytes(salt);
// Split salt length (always one byte) into four two-bit pieces and
// store these pieces in the first four bytes of the salt array.
salt[0] = (byte)((salt[0] & 0xfc) | (saltLen & 0x03));
salt[1] = (byte)((salt[1] & 0xf3) | (saltLen & 0x0c));
salt[2] = (byte)((salt[2] & 0xcf) | (saltLen & 0x30));
salt[3] = (byte)((salt[3] & 0x3f) | (saltLen & 0xc0));
return salt;
}
private int GenerateRandomNumber(int minValue, int maxValue)
{
// We will make up an integer seed from 4 bytes of this array.
byte[] randomBytes = new byte[4];
// Generate 4 random bytes.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
// Convert four random bytes into a positive integer value.
int seed = ((randomBytes[0] & 0x7f) << 24) |
(randomBytes[1] << 16) |
(randomBytes[2] << 8) |
(randomBytes[3]);
// Now, this looks more like real randomization.
Random random = new Random(seed);
// Calculate a random number.
return random.Next(minValue, maxValue + 1);
}
****************************
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master"
AutoEventWireup="true" CodeFile="Default4.aspx.cs" Inherits="Default4"
Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1"
Runat="Server">
<asp:Label ID="Label2" runat="server" Text="Şifrelenecek Olan
Bilgi"></asp:Label>
<asp:TextBox ID="txtSifrelenecekBilgi" runat="server"></asp:TextBox>
<asp:Button ID="btnYaziyiSifrele" runat="server"
onclick="btnYaziyiSifrele_Click" Text="ŞİFRELE" />
<br />
<br />
<br />
<asp:Label ID="Label1" runat="server" Text="Oluşturulan Şifreli
Bilgi"></asp:Label>
<asp:TextBox ID="txtSifrelenmisBilgi" runat="server"></asp:TextBox>
<asp:Button ID="btnSifreliBilgiyiCoz" runat="server" Text="ŞİFREYİ ÇÖZ"
onclick="btnSifreliBilgiyiCoz_Click" />
<br />
<br />
<br />
Sifre Cozulmuş Bilgi
<asp:TextBox ID="txtSifreCozulmusBilgi" runat="server"></asp:TextBox>
<br />
</asp:Content>
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Text;
public partial class Default4 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnYaziyiSifrele_Click(object sender, EventArgs e)
{
string SifrelenecekBilgi = txtSifrelenecekBilgi.Text;
string SifrelenmisBilgi = SifreleFonksiyonu(SifrelenecekBilgi);
txtSifrelenmisBilgi.Text = SifrelenmisBilgi;
}
// Şifreleyen Alt Fonksiyon------------------------
public string SifreleFonksiyonu(string Bilgi)
{
try
{
//byte[] encData_byte = new byte[Bilgi.Length];
byte[] Dizi = new byte[Bilgi.Length]; //İkilik Dizi
Tanımlıyoruz.
Dizi = Encoding.UTF8.GetBytes(Bilgi); //Şifreleme Yapıyor.
using System.Text; Kütüphanesi eklenmelidir.
string SifrelenmisBilgi = Convert.ToBase64String(Dizi); //
return SifrelenmisBilgi;
}
catch (Exception e)
{
throw new Exception("Sifrelemede Hata:" + e.Message);
//Sifrelemede hata olustugunda Hata mesajıyla birlikte gösterecektir.
}
}
protected void btnSifreliBilgiyiCoz_Click(object sender, EventArgs e)
{
txtSifreCozulmusBilgi.Text =
SifreCozucuFonksiyon(txtSifrelenmisBilgi.Text);
}
public string SifreCozucuFonksiyon(string Bilgi)
{
try
{
System.Text.UTF8Encoding SifreCozucu = new
System.Text.UTF8Encoding();
System.Text.Decoder CozulmusBilgi = SifreCozucu.GetDecoder();
byte[] IkilikKod = Convert.FromBase64String(Bilgi);
int KarekterSayisi = CozulmusBilgi.GetCharCount(IkilikKod, 0,
IkilikKod.Length );
char[] KoduCozulmusKarekterler = new char[KarekterSayisi];
CozulmusBilgi.GetChars(IkilikKod, 0, IkilikKod.Length,
KoduCozulmusKarekterler, 0);
string result = new String(KoduCozulmusKarekterler);
return result;
}
catch (Exception e)
{
throw new Exception("Kod Cozerken Hata Olustu: " + e.Message);
}
}
}
Encrypting data with the Blowfish algorithm
By Bill Gatliff, Courtesy of Embedded Systems Programming
Jul 15 2003 (11:00 AM) URL: http://www.embedded.com/showArticle.jhtml?articleID=12800442
Many embedded systems depend on obscurity to achieve security. We often
design systems to download unsigned or unencrypted firmware upgrades or
store unencrypted user data, a practice we justify because it's invisible to the
end user and makes our lives easier. The stealthy practice, however, is no
longer kosher. With the help of this public-domain encryption algorithm, we can clean up our act.
Modern embedded systems need data security more than ever before. Our PDAs store
personal e-mail and contact lists; GPS receivers and, soon, cell phones keep logs of our
movements;[1] and our automobiles record our driving habits.[2] On top of that, users
demand products that can be reprogrammed during normal use, enabling them to eliminate bugs and add new features as firmware upgrades become available.
Data security helps keep private data private. Secure data transmissions prevent contact
lists and personal e-mail from being read by someone other than the intended recipient,
keep firmware upgrades out of devices they don't belong in, and verify that the sender of
a piece of information is who he says he is. The sensibility of data security is even
mandated by law in certain applications: in the U.S. electronic devices cannot exchange
personal medical data without encrypting it first, and electronic engine controllers must
not permit tampering with the data tables used to control engine emissions and performance.
Data security techniques have a reputation for being computationally intensive,
mysterious, and fraught with intellectual property concerns. While some of this is true,
straightforward public domain techniques that are both robust and lightweight do exist.
One such technique, an algorithm called Blowfish, is perfect for use in embedded systems.
Terminology
In cryptographic circles, plaintext is the message you're trying to transmit. That message
could be a medical test report, a firmware upgrade, or anything else that can be
represented as a stream of bits. The process of encryption converts that plaintext message into ciphertext, and decryption converts the ciphertext back into plaintext.
Generally speaking, encryption algorithms come in two flavors, symmetric and public
key. Symmetric algorithms, such as Blowfish, use the same key for encryption and
decryption. Like a password, you have to keep the key secret from everyone except the sender and receiver of the message.
Public key encryption algorithms use two keys, one for encryption and another for
decryption. The key used for encryption, the "public key" need not be kept secret. The
sender of the message uses that public key to encrypt their message, and the recipient
uses their secret decryption key, or "private key", to read it. In a sense, the public key
"locks" the message, and the private key "unlocks" it: once encrypted with the public
key, nobody except the holder of the private key can decrypt the message. RSA is a popular public key encryption algorithm.
Most credible encryption algorithms are published and freely available for analysis,
because it's the security of the key that actually makes the algorithm secure. A good
encryption algorithm is like a good bank vault: even with complete plans for the vault,
the best tools, and example vaults to practice on, you won't get inside the real thing without the key.
Sometimes an encryption algorithm is restricted, meaning that the algorithm itself is kept
secret. But then you can never know for sure just how weak a restricted algorithm really is, because the developer doesn't give anyone a chance to analyze it.
Encryption algorithms can be used for several kinds of data security. Sometimes you
want data integrity, the assurance that the recipient received the same message you
sent. Encryption algorithms can also provide authentication, the assurance that a
message came from whom it says it came from. Some encryption algorithms can even
provide nonrepudiation, a way to prove beyond a doubt (say, in a courtroom) that a
particular sender was the originator of a message. And of course, most encryption
algorithms can also assure data privacy, a way to prevent someone other than the intended recipient from reading the message.
Data security in practice
Let's say an embedded system wants to establish a secure data-exchange session with a
laptop, perhaps over a wireless medium. At the start of the session, both the embedded
system and laptop compute a private Blowfish key and public and private RSA keys. The
embedded system and laptop exchange the public RSA keys and use them to encrypt and
exchange their private Blowfish keys. The two machines then encrypt the remainder of
their communications using Blowfish. When the communications session is over, all the
keys are discarded.
In this example, it doesn't matter if someone is eavesdropping on the entire
conversation. Without the private RSA keys, which never go over the airwaves, the
eavesdropper can't obtain the Blowfish keys and, therefore, can't decrypt the messages
passed between the two machines. This example is similar to how the OpenSSH
command shell works (although OpenSSH takes additional steps to prevent the public keys from being tampered with during transit).
Now let's say that a server wants to send a firmware upgrade to a device and wants to
be sure that the code isn't intercepted and modified during transit. The firmware upgrade
may be delivered over a network connection, but could just as easily be delivered via a
CD-ROM. In any case, the server first encrypts the firmware upgrade with its private RSA
key, and then sends it to the device. The recipient decrypts the message with the
server's public key, which was perhaps programmed into the device during manufacture.
If the firmware upgrade is successfully decrypted, in other words a checksum of the
image equals a known value, or the machine instructions look valid, the firmware upgrade is considered authentic.
The RSA algorithm is computationally expensive, although not unreasonably so for the
level of functionality and security it provides. A lighter-weight approach to firmware
exchange with an embedded system would be to encrypt the image with Blowfish,
instead of RSA. The downside to this approach is that the Blowfish key in the embedded
system has to be kept secret, which can be difficult to achieve for a truly determined
attacker with hardware skills. In less extreme cases, however, Blowfish is probably fine
since an attacker with such intimate knowledge of the target system and environment
will likely find another way into the device anyway (in other words, simply snatching the firmware upgrade from flash memory once it's decrypted).
The Blowfish algorithm
Blowfish is a symmetric encryption algorithm, meaning that it uses the same secret key
to both encrypt and decrypt messages. Blowfish is also a block cipher, meaning that it
divides a message up into fixed length blocks during encryption and decryption. The
block length for Blowfish is 64 bits; messages that aren't a multiple of eight bytes in size
must be padded.
Blowfish is public domain, and was designed by Bruce Schneier expressly for use in
performance-constrained environments such as embedded systems.[3] It has been
extensively analyzed and deemed "reasonably secure" by the cryptographic community.
Implementation examples are available from several sources, including the one by Paul
Kocher that's excerpted in this article as Listing 1. (The complete code is available for download at ftp://ftp.embedded.com/pub/2003/08blowfish.)
/*
Blowfish algorithm. Written 1997 by Paul Kocher ([email protected]).
This code and the algorithm are in the0 public domain.
*/
#define MAXKEYBYTES 56 /* 448 bits */
#define N 16
typedef struct {
uint32_t P[16 + 2];
uint32_t S[4][256];
} BLOWFISH_CTX;
unsigned long
F(BLOWFISH_CTX *ctx, uint32_t x)
{
uint16_t a, b, c, d;
uint32_t y;
d = x & 0x00FF;
x >>= 8;
c = x & 0x00FF;
x >>= 8;
b = x & 0x00FF;
x >>= 8;
a = x & 0x00FF;
y = ctx->S[0][a] + ctx->S[1][b];
y = y ^ ctx->S[2][c];
y = y + ctx->S[3][d];
return y;
}
void
Blowfish_Encrypt(BLOWFISH_CTX *ctx, uint32_t *xl, uint32_t *xr)
{
uint32_t Xl;
uint32_t Xr;
uint32_t temp;
int ii;
Xl = *xl;
Xr = *xr;
for (i = 0; i < N; ++i)
{
Xl = Xl ^ ctx->P[i];
Xr = F(ctx, Xl) ^ Xr;
temp = Xl;
Xl = Xr;
Xr = temp;
}
temp = Xl;
Xl = Xr;
Xr = temp;
Xr = Xr ^ ctx->P[N];
Xl = Xl ^ ctx->P[N + 1];
*xl = Xl;
*xr = Xr;
}
void
Blowfish_Decrypt(BLOWFISH_CTX *ctx, uint32_t *xl, uint32_t *xr)
{
uint32_t Xl;
uint32_t Xr;
uint32_t temp;
int ii;
Xl = *xl;
Xr = *xr;
for (i = N + 1; i > 1; --i)
{
Xl = Xl ^ ctx->P[i];
Xr = F(ctx, Xl) ^ Xr;
temp = Xl;
Xl = Xr;
Xr = temp;
}
temp = Xl;
Xl = Xr;
Xr = temp;
Xr = Xr ^ ctx->P[1];
Xl = Xl ^ ctx->P[0];
*xl = Xl;
*xr = Xr;
}
void
Blowfish_Init(BLOWFISH_CTX *ctx, uint16_t *key, int KeyLen)
{
uint32_t Xl;
{
int i, j, k;
uint32_t data, datal, datar;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 256; j++) ctx->S[i][j] = ORIG_S[i][j];
}
j = 0;
for (i = 0; i < N + 2; ++i)
{
data = 0x00000000;
for (k = 0; k < 4; ++k)
{
data = (data << 8) | key[j];
j = j + 1;
if (j >= keyLen) j = 0;
}
ctx->P[i] = ORIG_P[i] ^ data;
}
datal = 0x00000000;
datar = 0x00000000;
for (i = 0; i < N + 2; i += 2)
{
Blowfish_Encrypt(ctx, &datal, &datar);
ctx->P[i] = datal;
ctx->P[i + 1] = datar;
}
for (i = 0; i < 4; ++i)
{
for (j = 0; j < 256; j += 2)
{
Blowfish_Encrypt(ctx, &datal, &datar);
ctx->S[i][j] = datal;
ctx->S[i][j + 1] = datar;
}
}
}
int
Blowfish_Test(BLOWFISH_CTX *ctx)
{
uint32_t L = 1, R = 2;
Blowfish_Init(ctx, (unsigned char*)"TESTKEY", 7);
Blowfish_Encrypt(ctx, &L, &R);
if (L != 0xDF333FD2L || R != 0x30A71BB4L) return (-1);
Blowfish_Decrypt(ctx, &L, &R);
if (L != 1 || R != 2) return (-1); return (0);
}
Blowfish requires about 5KB of memory. A careful implementation on a 32-bit processor
can encrypt or decrypt a 64-bit message in approximately 12 clock cycles. (Not-so-
careful implementations, like Kocher, don't increase that time by much.) Longer
messages increase computation time in a linear fashion; for example, a 128-bit message
takes about (2 x 12) clocks. Blowfish works with keys up to 448 bits in length.
Figure 1: Blowfish algorithm
A graphical representation of the Blowfish algorithm appears in Figure 1. In this
description, a 64-bit plaintext message is first divided into 32 bits. The "left" 32 bits are
XORed with the first element of a P-array to create a value I'll call P', run through a
transformation function called F, then XORed with the "right" 32 bits of the message to
produce a new value I'll call F'. F' then replaces the "left" half of the message and P'
replaces the "right" half, and the process is repeated 15 more times with successive
members of the P-array. The resulting P' and F' are then XORed with the last two entries in the P-array (entries 17 and 18), and recombined to produce the 64-bit ciphertext.
Figure 2: Graphic representation of F
A graphical representation of F appears in Figure 2. The function divides a 32-bit input
into four bytes and uses those as indices into an S-array. The lookup results are then added and XORed together to produce the output.
Because Blowfish is a symmetric algorithm, the same procedure is used for decryption as
well as encryption. The only difference is that the input to the encryption is plaintext; for
decryption, the input is ciphertext.
The P-array and S-array values used by Blowfish are precomputed based on the user's
key. In effect, the user's key is transformed into the P-array and S-array; the key itself
may be discarded after the transformation. The P-array and S-array need not be recomputed (as long as the key doesn't change), but must remain secret.
I'll refer you to the source code for computing the P and S arrays and only briefly
summarize the procedure as follows:
P is an array of eighteen 32-bit integers.
S is a two-dimensional array of 32-bit integer of dimension 4x256.
Both arrays are initialized with constants, which happen to be the hexadecimal
digits of π (a pretty decent random number source).
The key is divided up into 32-bit blocks and XORed with the initial elements of the
P and S arrays. The results are written back into the array.
A message of all zeros is encrypted; the results of the encryption are written back
to the P and S arrays. The P and S arrays are now ready for use.
Using the example code
Of course, firmware upgrades and data logs are seldom exactly 64 bits in length. To
encrypt long strings of data using Blowfish, carve the message up into 64-bit blocks,
encrypt each block and save the results. Pad the message with a value of your choosing
to end on a 64-bit boundary. The code in the main() of Listing 2 does exactly this.
Listing 2: Example of Blowfish use
#include <stdio.h>
#include <string.h>
int
main (void)
{
BLOWFISH_CTX ctx;
int n;
/* must be less than 56 bytes */
char *key = "a random number string would be a better key";
int keylen = strlen(key);
uint8_t *plaintext_string = "this is our message";
int plaintext_len = strlen(plaintext_string);
uint8_t ciphertext_buffer[256];
uint8_t *ciphertext_string = &ciphertext_buffer[0];
int ciphertext_len = 0;
uint32_t message_left;
uint32_t message_right;
int block_len;
#if 1
/* sanity test, encrypts a known message */
n = Blowfish_Test(&ctx);
printf("Blowfish_Test returned: %d.%s\n", n, n ? " Abort." : "");
if (n) return n;
#endif
Blowfish_Init(&ctx, key, keylen);
printf("Plaintext message string is: %s\n", plaintext_string);
/* encrypt the plaintext message string */
printf("Encrypted message string is: ");
while (plaintext_len)
{
message_left = message_right = 0UL;
/* crack the message string into a 64-bit block (ok, really two 32-bit blocks); pad with
zeros if necessary */
for (block_len = 0; block_len < 4; block_len++)
{
message_left = message_left << 8;
if (plaintext_len)
{
message_left += *plaintext_string++;
plaintext_len--;
}
else message_left += 0;
}
for (block_len = 0; block_len < 4; block_len++)
{
message_right = message_right << 8;
if (plaintext_len)
{
message_right += *plaintext_string++;
plaintext_len--;
}
else message_right += 0;
}
/* encrypt and print the results */
Blowfish_Encrypt(&ctx, &message_left, &message_right);
printf("%lx%lx", message_left, message_right);
/* save the results for decryption below */
*ciphertext_string++ = (uint8_t)(message_left >> 24);
*ciphertext_string++ = (uint8_t)(message_left >> 16);
*ciphertext_string++ = (uint8_t)(message_left >> 8);
*ciphertext_string++ = (uint8_t)message_left;
*ciphertext_string++ = (uint8_t)(message_right >> 24);
*ciphertext_string++ = (uint8_t)(message_right >> 16);
*ciphertext_string++ = (uint8_t)(message_right >> 8);
*ciphertext_string++ = (uint8_t)message_right;
ciphertext_len += 8;
printf("\n");
/* reverse the process */
printf("Decrypted message string is: ");
ciphertext_string = &ciphertext_buffer[0];
while(ciphertext_len)
{
message_left = message_right = 0UL;
for (block_len = 0; block_len < 4; block_len++)
{
message_left = message_left << 8;
message_left += *ciphertext_string++;
if (ciphertext_len)
ciphertext_len--;
}
for (block_len = 0; block_len < 4; block_len++)
{
message_right = message_right << 8;
message_right += *ciphertext_string++;
if (ciphertext_len)
ciphertext_len--;
}
Blowfish_Decrypt(&ctx, &message_left, &message_right);
/* if plaintext message string padded, extra zeros here */
printf("%c%c%c%c%c%c%c%c",
(int)(message_left >> 24), (int)(message_left >> 16),
(int)(message_left >> 8), (int)(message_left),
(int)(message_right >> 24), (int)(message_right >> 16),
(int)(message_right >> 8), (int)(message_right));
}
printf("\n");
return 0; }
Now is a good time to start thinking about adding data integrity and privacy capabilities
to your embedded system. The Blowfish algorithm is an excellent choice for encryption,
since it's lightweight, public domain, and considered secure even after extensive analysis.
Bill Gatliff is a consultant who specializes in solving embedded development problems
using free software tools. He's the creator of the gdbstubs library, a free collection of embeddable stubs for the GNU debugger. You can reach him at [email protected].
End notes:
1. Not an actual log per se, but so-called ephemerides information that allows the
device to find GPS transmitters without doing a time-consuming search of the
entire GPS spectrum. Such information can also be used to pinpoint the receiver's
location at a previous point in time. Because of this capability, GPS receivers are
routinely collected and analyzed during searches by law enforcement. A digital
signature would authenticate the ephimeride, verifying that it hadn't been
tampered with or rendered invalid before being used as evidence.
Back
2. In the U.S., commercial automotive systems do this to prevent warranty claims
for user-damaged hardware; in Europe, it's to prevent speeding.
Back
3. Schneier, Bruce. Applied Cryptography: Protocols, Algorithms, and Source Code in
C, Second Edition. New York, NY: John Wiley & Sons, 1995.
Back
Copyright 2005 © CMP Media LLC
Blowfish Encryption / Decryption
Download C# Project Files and Source Code
C# example source code showing how to do 256-bit blowfish encryption and decryption.
NOTE: This example uses the Chilkat.Crypt class, not Chilkat.Crypt2
public static byte[] StrToByteArray(string str)
{
System.Text.ASCIIEncoding encoding=new
System.Text.ASCIIEncoding();
return encoding.GetBytes(str);
}
private void button1_Click(object sender, System.EventArgs e)
{
Chilkat.Crypt crypt = new Chilkat.Crypt();
crypt.UnlockComponent("UnlockCode");
// Generate some data.
String fileContents = "Test\n";
int i;
for (i=0; i<100; i++)
{
fileContents = fileContents + "This is a test
1234\n";
}
byte [] byteData = StrToByteArray(fileContents);
textBox1.Text = "Data Length = " +
Convert.ToString(byteData.Length);
// Set our algorithm and key-length
crypt.SetAlgorithmBlowfish();
crypt.KeyLength = 256; // 256-bit encryption.
// Set our password.
crypt.SetSecretKeyViaPassPhrase("myPassword");
// Encrypt the data.
byte [] encryptedData = crypt.Encrypt(byteData);
textBox1.Text = textBox1.Text + "\r\nEncrypted Length = " +
Convert.ToString(encryptedData.Length);
// Write the encrypted binary file.
System.IO.BinaryWriter bw = new System.IO.BinaryWriter(
System.IO.File.Create("encrypted.dat"));
bw.Write(encryptedData);
bw.Close();
// Now read the binary file
System.IO.FileInfo fInfo = new
System.IO.FileInfo("encrypted.dat");
System.IO.BinaryReader br = new System.IO.BinaryReader(
System.IO.File.OpenRead("encrypted.dat"));
byte [] eBytes = br.ReadBytes((int)fInfo.Length);
br.Close();
// Decrypt the bytes.
byte [] dBytes = crypt.Decrypt(eBytes);
string str = "";
System.Text.ASCIIEncoding enc = new
System.Text.ASCIIEncoding();
str = enc.GetString(dBytes);
textBox1.Text = textBox1.Text + "\r\n" + str;
}
}