:smile: Download File Listing Source Code disini !!! (KLIK KANAN, LALU SAVE AS DENGAN EKSTENSI 7z)

Di dalam kriptografi ada berbagai macam algoritma yang dapat digunakan, baik yang termasuk algoritma kriptografi modern maupun algoritma kriptografi klasik. Yang termasuk di dalam algoritma kriptografi modern adalah algoritma cipher block. Chiper block merupakan sebuah algoritma simetri yang mengoperasikan bit-bit yang mempunyai panjang yang sama. Sebagai contoh, ketika melakukan enkripsi, sebuah 128-bit blok plaintext akan menghasilkan sebuah 128-bit blok ciphertext. Begitu pula dengan proses deskripsi. Sebuah 128-bit blok ciphertext akan menghasilkan 128-bit blok plaintext.

Sudah banyak sekali algoritma cipher block yang dikembangkan. Salah satunya adalah LOKI. LOKI dirancang oleh kriptografer Australia yaitu Lawrie Brown, Josef Pieprzyk, dan Jennifer Seberry. LOKI didesain sebagai hasil dari analisis yang dilakukan secara detail terhadap blok cipher yang standar digunakan pada saat itu, yaitu DES (Data Encryption Standar). Dikarenakan ada versi terbaru dari LOKI ini, maka LOKI yang dibuat pertama kali lebih dikenal dengan nama LOKI89 sesuai

dengan tahun pembuatannya, walaupun LOKI pertama kali diperkenalkan pada tahun 1990. LOKI91 dibuat sebagai revisi dari LOKI89. Oleh karena itulah terdapat beberapa kesamaan antara LOKI91 dan LOKI89.

LOKI didesain untuk menggantikan DES sehingga strukturnya pun dibuat hampir sama dengan DES. LOKI menggunakan blok data sepanjang 64 bit dan kunci sepanjang 64 bit pula.

Desain LOKI91

Tambahan-tambahan yang terdapat pada LOKI91 dari LOKI89 adalah sebagai berikut.

  • Jadwal pembangkitan kunci diperbaiki sehingga meminimalkan pembangkitan kunci yang sama ataupun pasangan kunci dan plainteks yang berhubungan.
  • Meminimalkan probabilitas f(x) menghasilkan 0
  • Menjamin bahwa blok telah diputar dengan jumlah yang cukup sehingga serangan yang mungkin ada hanya exhaustive search.
  • Menjamin bahwa S-box tidak akan menghasilkan 0 sehingga meningkatkan keamanan untuk mode hashing.

Spesifikasi LOKI91

Perubahan-perubahan yang terdapat pada LOKI91 adalah sebagai berikut.

  1. Merubah jadwal pembangkitan kunci sedemikian sehingga kunci kanan KR dan kunci kiri KL ditukar setiap dua putaran.
  2. Merubah jadwal rotasi kunci dengan menggunakan dua buah cara yaitu antara ROT12 (putaran ganjil) dan ROT13 (putaran genap).
  3. Menghilangkan operasi XOR di awal dan akhir antara kunci dan blok yang akan dienkripsi/didekripsi.
  4. Merubah fungsi S-box menjadi sebagai berikut.

Sfn (r,c) = (c + ((r*17) (+) ff16) & ff16) 31 mod genr

Implementasi LOKI91

Kunci masukan disimpan di dalam array of Unsigned Integer32. Sedangkan subkunci untuk 16 putaran dideklarasikan dengan cara :

public class loki_ctx {

public uint[] loki_subkeys ;

public loki_ctx()

{

loki_subkeys = new uint[16];

}

}

public class LOKI

{

// deklarasi variabel di sini

loki_ctx lctx;

// deklarasi variabel di sini

}

Fungsi perputaran didefinisikan sebagai berikut.

private uint CircularShift( int bitsCount, UInt32 word )

{

return (word << bitsCount) | (word >> (32 - bitsCount));

}

CircularShift( 12, b ); digunakan untuk menggeser 32 bit blok b ke kiri secara sirkular sepanjang 12 bit. Sedangkan CircularShift( 13, b ); digunakan untuk menggeser 32 bit blok b ke kiri secara sirkular sepanjang 13 bit.

Sebelum melakukan proses enkripsi/dekripsi, subkunci sebanyak 16 buah harus dibangkitkan terlebih dahulu. Sebelum pembangkitan kunci dilakukan, kunci masukan harus dibagi

dua bagian yaitu KL dan KR seperti pada pembagian kunci di LOKI89.

Pembangkitan subkunci dilakukan dengan cara :

public void SetLokiKey( byte[] key)

{

int i;

uint KL, KR;

KL = Get32BitFrom64Bit( key, 0 );

KR = Get32BitFrom64Bit( key, 1 );

for (i=0; i<ROUNDS; i+=4) { /* Generate the 16 subkeys */

lctx.loki_subkeys[i] = KL;

CircularShift( 12, KL );

lctx.loki_subkeys[i+1] = KL;

CircularShift( 13, KL );

lctx.loki_subkeys[i+2] = KR;

CircularShift( 12, KR );

lctx.loki_subkeys[i+3] = KR;

CircularShift( 13, KR );

}

}

Dengan ROUNDS=16.

Proses Enkripsi

Blok masukan dibagian menjadi dua buah bagian yang sama besar, yaitu R dan L.

uint L, R; /* left & right data halves */

L = Get32BitFrom64Bit( data8byte, 0 );

R = Get32BitFrom64Bit( data8byte, 1 );

Kemudian dilakukan proses enkripsi dengan menggunakan 16 buah subkunci yang telah dibangkitkan sebelumnya. Proses enkripsi dengan menggunakan subkunci ini dilakukan dengan cara sebagai berikut.

for (i = 0; i < ROUNDS; i += 2)

{ /* Encrypt with the 16 subkeys */

L ^= f( R, lctx.loki_subkeys[i] );

R ^= f( L, lctx.loki_subkeys[i + 1] );

}

Operasi yang terakhir dilakukan dalam proses enkripsi adalah dengan menukar L dan R :

byte[] bL = SplitUIntToByte( R );

byte[] bR = SplitUIntToByte( L );

data8byte[0] = bL[0];

data8byte[1] = bL[1];

data8byte[2] = bL[2];

data8byte[3] = bL[3];

data8byte[4] = bR[0];

data8byte[5] = bR[1];

data8byte[6] = bR[2];

data8byte[7] = bR[3];

Proses Dekripsi

Pada dasarnya proses dekripsi mirip dengan proses enkripsi, hanya saja putaran dilakukan dengan urutan yang terbalik dari proses enkripsi.

Pertama-tama, blok yang akan didekripsi dibagi menjadi dua buah bagian yang sama, yaitu L dan R.

uint L, R; /* left & right data halves */

L = Get32BitFrom64Bit( data8byte, 0 );

R = Get32BitFrom64Bit( data8byte, 1 );

Kemudian dilakukan putaran dengan cara sebagai berikut.

for (i=ROUNDS; i>0; i-=2) { /* subkeys in reverse order */

L ^= f(R, lctx.loki_subkeys[i-1]);

R ^= f(L, lctx.loki_subkeys[i-2]);

}

Proses terakhir yang dilakukan pada dekripsi adalah dengan melakukan penukaran antara L dengan R sebagai berikut

byte[] bL = SplitUIntToByte( R );

byte[] bR = SplitUIntToByte( L );

data8byte[0] = bL[0];

data8byte[1] = bL[1];

data8byte[2] = bL[2];

data8byte[3] = bL[3];

data8byte[4] = bR[0];

data8byte[5] = bR[1];

data8byte[6] = bR[2];

data8byte[7] = bR[3];

Fungsi f(r,k)

Fungsi didefinisikan dengan private uint f( uint r, uint k )

Fungsi f(r,k) merupakan sebuah fungsi LOKI91yang kompleks dan nonlinier yang menghasilkan keluaran yang merupakan hasil dari fungsi kompleks dari masukan dan subkunci. Hal ini dilakukan dengan cara sebagai berikut:

Operasi XOR dilakukan terhadap data masukan (r) dengan subkunci(k). Setelah itu data diperpanjang menjadi 4×12 bit yang akan dimasukkan ke dalam S-box. Keluaran 4×8 bit dari S-box akan dipermutasikan untuk menghasilkan 32 bit keluaran dari fungsi f ini.

Pertama-tama data masukan r dikenai fungsi XOR dengan subkunci masukan dan hasilnya disimpan dalam a.

a = r ^ k;

Sejauh ini operasi yang dilakukan adalah : A = R(i-1) XOR K(i)

Setelah itu dilakukan ekspansi dan hasilnya dimasukkan ke dalam S-box.

b = ((uint) s( (uint)(a & MASK12) )) |

((uint) s( (uint)((a >> 8) & MASK12) ) << 8) |

((uint) s( (uint)((a >> 16) & MASK12) ) << 16) |

((uint) s( (uint)(((a >> 24) | (a << 8)) & MASK12) ) << 24);

Dimana MASK12 adalah 0×0fff. Sejauh ini operasi yang telah dilakukan adalah.

B = S(E(R(i-1))^K(i))

Operasi yang terakhir dilakukan pada fungsi f ini adalah melakukan permutasi dengan cara :

perm32(ref C, b, P );

Dengan P didefinisikan sebagai berikut

byte[] P = {

31, 23, 15, 7, 30, 22, 14, 6, 29, 21, 13, 5, 28, 20, 12, 4,

27, 19, 11, 3, 26, 18, 10, 2, 25, 17, 9, 1, 24, 16, 8, 0

};

Dengan demikian, keseluruhan proses fungsi f ini adalah :

C=P(S(E(R(i-1)) XOR K(i)))

Dengan C adalah nilai yang dihasilkan oleh fungsi f ini.

S-box

Fungsi ini didefinisikan dengan private short s(uint i)

Proses yang dilakukan dalam S-box ini adalah sebagai berikut.

Pertama-tama penentuan nilai baris.

r = (short)(((i>>8) & 0xc) | (i & 0×3));

Setelah penentuan baris selesai, selanjutnya adalah penentuan kolom

c = (short) ((i >> 2) & 0xff);

Kemudian menentukan nilai basis untuk Sfn.

t = (short)((c + ((r * 17) ^ 0xff)) & 0xff);

Tahapan terakhir yang dilakukan adalah menghitung nilai Sfn[r] = t ^ exp mod gen.

v = exp8(t, sfn[r].exp, sfn[r].gen);

Dengan demikian nilai yang dihasilkan dari fungsi S-box ini adalah v.

Permutasi : perm32(out, in, perm)

Didefinisikan dengan private void perm32(ref uint b_out, uint b_in , byte[] p)

Fungsi permutasi pada LOKI91 sama dengan fungsi permutasi pada LOKI89 dimana melakukan operasi permutasi biasa yang mendapat masukan 32 bit blok in, menghasilkan 32 bit blok out. Setiap elemen dari perm menspesifikasikan bit masukan mana yang harus dipermutasikan menjadi bit keluaran dengan indeks yang sama dengan elemen perm.

Fungsi permutasi ini dilakukan dengan cara :

uint mask = 0×80000000;

int i, o, b;

b_out = 0;

for (o=0; o<32; o++) {

i =(int)p[o];

b = (int)(b_in >> i) & 0×1;

if (b == 1)

{

b_out |= mask;

}

mask >>= 1;

}

/*

p = perm

o = indeks bit keluaran

i = indeks bit masukan

*/

Untuk setiap bit keluaran di posisi o, ambil nilai masukan yang akan dipermutasikan ke bit keluaran o. Hitung nilai dari untuk bit masukan i. Jika i telah diset, lakukan OR pada mask untuk bit keluaran i. Geser mask ke bit selanjutnya.

Eksponensial : exp8(base, exponent, gen)

didefinisikan dengan private short exp8(short expbase, short exponent, short gen)

Fungsi eksponensial LOKI91 sama dengan LOKI89, tidak ada perubahan sama sekali. Fungsi ini tetap melakukan operasi : exp = base ^ exp mod gen

Proses dari fungsi ini adalah sebagai berikut.

short accum = expbase;

short result = 1;

if ( expbase == 0) {

return(0);

}

while (exponent != 0) {

if (( exponent & 0×0001) == 0×0001) {

result = mult8(result, accum, gen);

}

exponent >>= 1;

accum = mult8(accum, accum, gen);

}

return (result);

Jika nilai base adalah 0 maka fungsi akan otomatis mengembalikan nilai 0. Jika tidak 0 maka dilakukan proses perulangan hingga exponent menjadi 0. Eksponen akan dikenai fungsi mult8 jika nilai eksponen adalah 1. Lalu nilai eksponen bergeser ke digit selanjutnya.

Multiply : mult8(a, b, gen)

Fungsi ini didefinisikan dengan private short mult8( short a, short b, short gen )

Fungsi mult8 mengembalikan hasil perkalian dari dua buah string biner a dan b serta menggunakan generator gen sebagai modulus.

mult = a * b mod gen

Proses dari fungsi ini adalah sebagai berikut.

short product = 0; /* result of multiplication */

while (b != 0)

{ /* while multiplier is non–zero */

if ((b & 1) == 1)

{

product ^= a; /* add multiplicand if LSB of b set */

}

a <<= 1; /* shift multiplicand one place */

if (a >= SIZE)

{

a ^= gen; /* and modulo reduce if needed */

}

b >>= 1; /* shift multiplier one place */

}

return (product);

Selama pengali b tidak 0, lakukan proses berikut ini : jika LSB dari b merupakan 1, tambahkan hasil perkalian dengan a. Geser a sebanyak satu digit. Jika a lebih besar dari 256, maka a dikurangi modulo. Geser a sebanyak satu digit.

ScreenShoot Program

clip_image002

Mengetikkan plain text secara manual, dan mengetikkan hexadecimal password. (Password hanya bisa menerima karakter 0-9 dan A-F

clip_image004

Hasil enkripsi pesan diatas

clip_image006

Pesan juga bisa disimpan ke dalam File.

clip_image008

clip_image010

clip_image013

Jika dilakukan dekrip bisa kempali seperti semula

clip_image015

Tersedia juga fitur Copy, Edit, dan Paste

clip_image017

clip_image019

SOURCE CODE


Keterangan

Program dibuat menggunakan bahasa C#.NET dan dikompilasi menggunakan .NET Framework v.2.0. Untuk menjalankan program minimal Microsoft .NET Famework versi 2.0 (Windows) atau Mono versi 2.4 (Linux) sudah terinstall di komputer.

Untuk menjalankan program di Windows, jalankan KriptoIlkompLoki91.exe

Untuk menjalankan di linux, melalui console jalankan perintah

$> mono KriptoIlkompLoki91.exe

Jika ingin mengkompilasi ulang source code di Windows, ketikkan

$> msbuild KriptoIlkompLoki91.sln

Jika ingin mengkompilasi ulang source code di Linux, ketikkan

$> xbuild KriptoIlkompLoki91.sln


File : LOKI.cs (Berisi class untuk LOKI)

using System;

using System.Collections.Generic;

using System.Text;

namespace KriptoIlkompLoki91

{

public class LOKI

{

const string VER = “LOKI91″;

const byte ROUNDS = 16;

const byte LOKIBLK = 9;

const short MASK12 = 0×0fff ;

const uint MSB = 0×80000000;

const short SIZE = 256;

byte[] P = {

31, 23, 15, 7, 30, 22, 14, 6,

29, 21, 13, 5, 28, 20, 12, 4,

27, 19, 11, 3, 26, 18, 10, 2,

25, 17, 9, 1, 24, 16, 8, 0

};

sfn_desc[] sfn;

loki_ctx lctx;

private uint CircularShift( int bitsCount, UInt32 word )

{

return (word << bitsCount) | (word >> (32 - bitsCount));

}

private void enloki( ref byte[] data8byte )

{

int i;

uint L, R; /* left & right data halves */

L = Get32BitFrom64Bit( data8byte, 0 );

R = Get32BitFrom64Bit( data8byte, 1 );

for (i = 0; i < ROUNDS; i += 2)

{ /* Encrypt with the 16 subkeys */

L ^= f( R, lctx.loki_subkeys[i] );

R ^= f( L, lctx.loki_subkeys[i + 1] );

}

byte[] bL = SplitUIntToByte( R );

byte[] bR = SplitUIntToByte( L );

data8byte[0] = bL[0];

data8byte[1] = bL[1];

data8byte[2] = bL[2];

data8byte[3] = bL[3];

data8byte[4] = bR[0];

data8byte[5] = bR[1];

data8byte[6] = bR[2];

data8byte[7] = bR[3];

return;

}

private void deloki( ref byte[] data8byte )

{

int i;

uint L, R; /* left & right data halves */

L = Get32BitFrom64Bit( data8byte, 0 );

R = Get32BitFrom64Bit( data8byte, 1 );

for (i=ROUNDS; i>0; i-=2) { /* subkeys in reverse order */

L ^= f(R, lctx.loki_subkeys[i-1]);

R ^= f(L, lctx.loki_subkeys[i-2]);

}

byte[] bL = SplitUIntToByte( R );

byte[] bR = SplitUIntToByte( L );

data8byte[0] = bL[0];

data8byte[1] = bL[1];

data8byte[2] = bL[2];

data8byte[3] = bL[3];

data8byte[4] = bR[0];

data8byte[5] = bR[1];

data8byte[6] = bR[2];

data8byte[7] = bR[3];

}

private uint f( uint r, uint k )

{

/* r Data value R(i–1) */

/* k Key K(i) */

uint a, b, C; /* 32 bit S–box output, & P output */

a = r ^ k; /* A = R(i–1) XOR K(i) */

C = 0;

b = ((uint) s( (uint)(a & MASK12) )) | /* B = S(E(R(i–1))^K(i)) */

((uint) s( (uint)((a >> 8) & MASK12) ) << 8) |

((uint) s( (uint)((a >> 16) & MASK12) ) << 16) |

((uint) s( (uint)(((a >> 24) | (a << 8)) & MASK12) ) << 24);

perm32(ref C, b, P ); /* C = P(S( E(R(i–1)) XOR K(i))) */

return C; /* f returns the result C */

}

private short s(uint i)

{

short r, c, v, t;

r = (short)(((i>>8) & 0xc) | (i & 0×3));

c = (short) ((i >> 2) & 0xff);

t = (short)((c + ((r * 17) ^ 0xff)) & 0xff);

v = exp8(t, sfn[r].exp, sfn[r].gen);

return (v);

}

private void perm32(ref uint b_out, uint b_in , byte[] p)

{

uint mask = MSB; /* mask used to set bit in output */

int i, o, b; /* input bit no, output bit no, value */

b_out = 0; /* clear output block */

for (o=0; o<32; o++) { /* For each output bit position o */

i =(int)p[o]; /* get input bit permuted to output o */

b = (int)(b_in >> i) & 0×1; /* value of input bit i */

if (b == 1)

{ /* If the input bit i is set */

b_out |= mask; /* OR in mask to output i */

}

mask >>= 1; /* Shift mask to next bit */

}

}

private short mult8( short a, short b, short gen )

{

short product = 0; /* result of multiplication */

while (b != 0)

{ /* while multiplier is non–zero */

if ((b & 1) == 1)

{

product ^= a; /* add multiplicand if LSB of b set */

}

a <<= 1; /* shift multiplicand one place */

if (a >= SIZE)

{

a ^= gen; /* and modulo reduce if needed */

}

b >>= 1; /* shift multiplier one place */

}

return (product);

}

private short exp8(short expbase, short exponent, short gen)

{

short accum = expbase; /* superincreasing sequence of base */

short result = 1; /* result of exponentiation */

if ( expbase == 0) { /* if zero base specified then */

return(0); /* the result is “0” if base = 0 */

}

while (exponent != 0) { /* repeat while exponent non–zero */

if (( exponent & 0×0001) == 0×0001) {

result = mult8(result, accum, gen);

}

exponent >>= 1;

accum = mult8(accum, accum, gen);

}

return (result);

}

private uint ConcateByteToUInt( byte[] data )

{

uint a = (data[0] & 0xFFFFFFFF) << 24;

uint b = (data[1] & 0xFFFFFFFF) << 16;

uint c = (data[2] & 0xFFFFFFFF) << 8;

uint d = data[3];

return a | b | c | d;

}

private byte[] SplitUIntToByte( uint data )

{

byte[] b = new byte[4];

b[0] = (byte) ((data & 0xFF000000) >> 24);

b[1] = (byte) ((data & 0×00FF0000) >> 16);

b[2] = (byte) ((data & 0×0000FF00) >> 8);

b[3] = (byte) (data & 0×000000FF) ;

return b;

}

// PUBLIC //

public LOKI()

{

/* initialize */sfn = new sfn_desc[17];

/* 101110111 */ sfn[0] = new sfn_desc(375, 31);

/* 101111011 */ sfn[1] = new sfn_desc(379, 31) ;

/* 110000111 */ sfn[2] = new sfn_desc(391, 31) ;

/* 110001011 */ sfn[3] = new sfn_desc(395, 31);

/* 110001101 */ sfn[4] = new sfn_desc(397, 31) ;

/* 110011111 */ sfn[5] = new sfn_desc(415, 31);

/* 110100011 */ sfn[6] = new sfn_desc(419, 31);

/* 110101001 */ sfn[7] = new sfn_desc(425, 31);

/* 110110001 */ sfn[8] = new sfn_desc(433, 31) ;

/* 110111101 */ sfn[9] = new sfn_desc(445, 31);

/* 111000011 */ sfn[10] = new sfn_desc(451, 31) ;

/* 111001111 */ sfn[11] = new sfn_desc(463, 31);

/* 111010111 */ sfn[12] = new sfn_desc(471, 31) ;

/* 111011101 */ sfn[13] = new sfn_desc(477, 31);

/* 111100111 */ sfn[14] = new sfn_desc(487, 31) ;

/* 111110011 */ sfn[15] = new sfn_desc( 499, 31 );

/* 000000000 */ sfn[16] = new sfn_desc(00, 00);

lctx = new loki_ctx();

}

public void SetLokiKey( byte[] key)

{

int i;

uint KL, KR;

KL = Get32BitFrom64Bit( key, 0 );

KR = Get32BitFrom64Bit( key, 1 );

for (i=0; i<ROUNDS; i+=4) { /* Generate the 16 subkeys */

lctx.loki_subkeys[i] = KL;

CircularShift( 12, KL );

lctx.loki_subkeys[i+1] = KL;

CircularShift( 13, KL );

lctx.loki_subkeys[i+2] = KR;

CircularShift( 12, KR );

lctx.loki_subkeys[i+3] = KR;

CircularShift( 13, KR );

}

}

public uint Get32BitFrom64Bit( byte[] data8byte , byte idx)

{

if (idx == 0)

{

byte[] b = new byte[4];

b[0] = data8byte[0];

b[1] = data8byte[1];

b[2] = data8byte[2];

b[3] = data8byte[3];

return ConcateByteToUInt( b );

}

else

{

byte[] b = new byte[4];

b[0] = data8byte[4];

b[1] = data8byte[5];

b[2] = data8byte[6];

b[3] = data8byte[7];

return ConcateByteToUInt( b );

}

}

public byte[] EncryptLoki(byte[] data){

byte[] tmp = new