One Way Hash Function
One-way hash function, H(M) beroperasi pada pesan M dengan panjang bebas, dan keluaran fungsi tersebut adalah hash-value h dengan panjang tetap.
h = H(M) , dimana h memiliki panjang m
Karakteristik yang harus dimiliki oleh One-way hash function agar fungsi tersebut menjadi satu arah
- Diberikan M, sehingga mudah untuk menghitung h
- Diberikan h, akan sangat sulit menemukan M sehingga H(M) = h
- Diberikan M, akan sangat sulit untuk menemukan pesan lain M’ , sehingga H(M) = H(M’)
Serangan terhadap One Way Hash Function
- Serangan pertama, Diberikan hash dari pesan H(M) maka kita dapat membuat pesan lain M’ , sehingga H(M) = H(M’)
- Serangan kedua, Dapat ditemukan dua pesan random sehingga H(M) = H(M’)
SHA 1
Fungsi hash SHA merupakan sekumpulan fungsi hash didesain oleh National Security Agency dan dipublikasikan oleh NIST sebagai U.S Federal Information Processing Standard (FIPS). SHA merupakan singkatan dari Secure Hash Algorithm. SHS (Secure Hash Standard) merupakan standar yang mendefinisikan SHA. Ada banyak versi SHA. SHA-0, SHA-1, SHA-2. Sedangkan untuk SHA-2 terbagi lagi menjadi SHA-224, SHA-256, SHA-384, and SHA-512. Di sini hanya akan dibahas mengenai SHA-1. SHA-1 menghasilkan 160 bit message diggest dari pesan yang panjangnya kurang dari 264 bit. SHA-1 hampir mirip dengan MD4 tetapi dengan beberapa perubahan.
Langkah-langkah dalam menghitung nilai hash adalah sebagai berikut :
- Message Padding
SHA-1 digunakan untuk menghitung message diggest dari pesan atau file data yang disediakan sebagai input. Pesan atau file dianggap sebagai kumpulan bit-bit. Panjang dari pesan adalah banyaknya bit didalam pesan (Pesan kosong memiliki panjang 0). Jika banyaknya bit di dalam pesan merupakan kelipatan 8, untuk memudahkan pembacaan dapat ditampilkan dalam format hexadecimal.
Tujuan dari message padding adalah membuat panjang total dari isi pesan menjadi kelipatan 512 bit. SHA-1 secara sekuensial memproses blok 512 bit ketika menghitung message diggest.

|
|
Pada message padding, tambahkan satu buah “1” , diikuti oleh m buah “0” diikuti oleh 64 bit integer pada akhir pesan untuk menghasilkan pesan dengan panjang 512 * n. 64 bit integer tersebut adalah panjang dari pesan asli sebelum message padding.
Misalkan pesan dengan panjang L < 26. Sebelum pesan menjadi input SHA-1, dilakukan message padding sebagai berikut
Misal pesan aslinya (L = 40) adalah :
01100001 01100010 01100011 01100100 01100101 (biner)
61 62 63 64 65 (hex)
Tambahkan “1” pada akhir pesan
01100001 01100010 01100011 01100100 01100101 1
Karena L = 40, maka hasilnya menjadi = 41, sehingga diperlukan “0” sebanyak
448 – 41 = 407 buah.
01100001 01100010 01100011 01100100 01100101 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Dalam hexadecimal hasilnya adalah
61626364 65800000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Tambahkan 64 bit representasi dari panjang pesan asli. Untuk L = 40, maka representasi dari 64 bit panjang pesan adalah
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00101000 (biner)
00000000 00000028 (hexa)
Maka, setelah ditambahkan hasilnya :
(dalam biner)
01100001 01100010 01100011 01100100 01100101 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00101000
(dalam hexa)
61626364 65800000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000028
Hasil dari message padding adalah n 512-bit block (n * 16 word) , untuk suatu n > 0.
Padded message disimbolkan dengan M(1), M(2), …, M(n)
- Fungsi dan Konstanta yang Digunakan
Serentetan fungsi logic f(0), f(1), f(2), .. ,f(79) digunakan dalam SHA-1. Setiap f(t) , 0 ≤ t ≤ 79 beroperasi pada 32bit word B, C, D dan menghasilkan 32bit word sebagai output.
f( t; B,C,D) didefinisikan sebagai berikut. Untuk word B,C,D :
f(t;B,C,D) = (B AND C) OR ((NOT B) AND D) ( 0 <= t <= 19)
f(t;B,C,D) = B XOR C XOR D (20 <= t <= 39)
f(t;B,C,D) = (B AND C) OR (B AND D) OR (C AND D) (40 <= t <= 59)
f(t;B,C,D) = B XOR C XOR D (60 <= t <= 79)
Serentetan konstanta K(0), K(1), K(2), … , K(79) digunakan dalam SHA-1.
Dalam hexadecimal konstanta tersebut adalah :
K(t) = 5A827999 ( 0 <= t <= 19)
K(t) = 6ED9EBA1 (20 <= t <= 39)
K(t) = 8F1BBCDC (40 <= t <= 59)
K(t) = CA62C1D6 (60 <= t <= 79)
Selain itu juga digunakan fungsi Circular Left Shift. Circular left shift S^n(X) , dimana X adalah 32 bit word dan n adalah bilangan integer dengan 0 ≤ n < 32.
S^n(X) = (X << n) OR (X >> 32-n)
Contoh: Misalkan X = 11010000 01010000 11100000 00001010 , dan n = 5
Maka
X << 5 = 00001010 00011100 00000001 01000000
X >> 27 = 00000000 00000000 00000000 00011010
————————————————————— (OR)
S^5(X) = 00001010 00011100 00000001 01011010
- Menghitung Message Diggest
Message diggest dihitung menggunakan hasil message padding. Komputasi menggunakan dua jenis buffer, setiap jenis buffer tediri dari 5 buah 32-bit word. 5 buah 32-bit word buffer pertama dilabeli dengan A, B, C, D, E. Sedangkan buffer kedua dilabeli H0, H1, H2, H3, H4. Terdapat sebuah sekuen 80 word 32-bit, yang dilabeli W(0), W(1), W(2), …, W(79) dan juga sebuah word buffer yang dilabeli dengan TEMP. Untuk men-generate message diggest, block-block 16 word M(1) M(2) M(3) … M(n) hasil message diggest diproses secara berurutan. Setiap pemrosesan M(i) membutuhkan 80 langkah.
Sebelum memproses apapun, untuk pertama kali, H diinisialisasi sebagai berikut:
H0 = 67452301
H1 = EFCDAB89
H2 = 98BADCFE
H3 = 10325476
H4 = C3D2E1F0
Selanjutnya lakukan komputasi dari M(1), M(2), … , M(n). Untuk setiap M(i), lakukan langkah langkah sebagai berikut ini :
Step 1 |
Divide M(i) into 16 words W(0), W(1), … , W(15), where W(0) is the left-most word. |
Step 2 |
For t = 16 to 79 do W(t) = S^1( W(t-3) XOR W(t-8) XOR W(t-14) XOR W(t-16) ) |
Step 3 |
Let A = H0, B = H1, C = H2, D = H3, E = H4 |
Step 4 |
For t = 0 to 79 do TEMP = S^5(A) + f(t;B,C,D) + E + W(t) + K(t); E = D; D = C; C = S^30(B); B = A; A = TEMP; |
Step 5 |
H0 = H0 + A; H1 = H1 + B; H2 = H2 + C; H3 = H3 + D; H4 = H4 + E; |
Setelah memproses M(n), message diggest adalah 160-bit string yang direpresentasikan oleh 5 word
H0 H1 H2 H3 H4
Screenshot Program

Source Code Program
File : SHA1.cs (Berisi Class SHA1) |
using System;
using System.Collections.Generic;
using System.Text;
namespace IlkompSHA1 {
public class SHA1 {
// private private uint f( int t, uint B, uint C, uint D )
{
if(t >= 0 && t <= 19)
{
return (B & C) | ((~B) & D);
}
else if (t >= 20 && t <= 39)
{
return (B ^ C ^ D);
}
else if (t >= 40 && t <= 59)
{
return (B & C) | (B & D) | (C & D);
}
else {
return (B ^ C ^ D);
}
}
private uint K( int t )
{
if (t >= 0 && t <= 19)
{
return 0x5A827999 ;
}
else if (t >= 20 && t <= 39)
{
return 0x6ED9EBA1;
}
else if (t >= 40 && t <= 59)
{
return 0x8F1BBCDC;
}
else {
return 0xCA62C1D6;
}
}
private void ProcessMessageBlock()
{
int t; // Loop counter uint temp; // Temporary word value uint[] W = new uint[80]; // Word sequence uint A, B, C, D, E; // Word buffers for (t = 0; t < 16; t++)
{
W[t] = ((uint)Message_Block[t * 4]) << 24;
W[t] |= ((uint)Message_Block[t * 4 + 1]) << 16;
W[t] |= ((uint)Message_Block[t * 4 + 2]) << 8;
W[t] |= ((uint)Message_Block[t * 4 + 3]);
}
for (t = 16; t < 80; t++)
{
W[t] = CircularShift(1, W[t–3] ^ W[t–8] ^ W[t–14] ^ W[t–16]);
}
A = H[0];
B = H[1];
C = H[2];
D = H[3];
E = H[4];
for (t = 0; t < 80; t++)
{
temp = CircularShift(5, A) + f(t,B,C,D) + E + W[t] + K(t);
E = D;
D = C;
C = CircularShift(30, B);
B = A;
A = temp;
}
H[0] = (H[0] + A) ;
H[1] = (H[1] + B) ;
H[2] = (H[2] + C) ;
H[3] = (H[3] + D) ;
H[4] = (H[4] + E) ;
Message_Block_Index = 0;
}
private void PadMessage()
{
if (Message_Block_Index > 55)
{
Message_Block[Message_Block_Index++] = 0x80;
while (Message_Block_Index < 64)
{
Message_Block[Message_Block_Index++] = 0;
}
ProcessMessageBlock();
while (Message_Block_Index < 56)
{
Message_Block[Message_Block_Index++] = 0;
}
}
else
{
Message_Block[Message_Block_Index++] = 0x80;
while (Message_Block_Index < 56)
{
Message_Block[Message_Block_Index++] = 0;
}
}
Message_Block[56] = (byte)((Length_High >> 24) );
Message_Block[57] = (byte)((Length_High >> 16) );
Message_Block[58] = (byte)((Length_High >> 8) );
Message_Block[59] = (byte)((Length_High) );
Message_Block[60] = (byte)((Length_Low >> 24) );
Message_Block[61] = (byte)((Length_Low >> 16) );
Message_Block[62] = (byte)((Length_Low >> 8) );
Message_Block[63] = (byte)((Length_Low) );
ProcessMessageBlock();
}
// Performs a circular left shift operation private UInt32 CircularShift(int bits, UInt32 word)
{
return (word << bits) | (word >> (32 – bits));
}
private UInt32[] H = new UInt32[5]; // Message digest buffers private UInt32 Length_Low; // Message length in bits private UInt32 Length_High; // Message length in bits private byte[] Message_Block = new byte[64] // 512-bit message blocks private int Message_Block_Index; // Index into message block array private bool Computed; // Is the digest computed? private bool Corrupted; // Is the message digest corruped? public SHA1()
{
this.Reset();
}
public void Reset()
{
Length_Low = 0;
Length_High = 0;
Message_Block_Index = 0;
H[0] = 0x67452301;
H[1] = 0xEFCDAB89;
H[2] = 0x98BADCFE;
H[3] = 0x10325476;
H[4] = 0xC3D2E1F0;
Computed = false;
Corrupted = false;
}
public bool Result(ref UInt32[] message_digest_array)
{
int i; // Counter if (Corrupted)
{
return false;
}
if (!Computed)
{
PadMessage();
Computed = true;
}
for (i = 0; i < 5; i++)
{
message_digest_array[i] = H[i];
}
return true;
}
public void Input(Byte[] message_array, UInt32 length)
{
if (length <= 0)
{
return;
}
if (Computed || Corrupted)
{
Corrupted = true;
return;
}
int i = 0;
int j = 0;
while ((length > 0) && !Corrupted)
{
i = Message_Block_Index++;
Message_Block[i] = (byte)(message_array[j] & 0xFF);
Length_Low += 8;
if (Length_Low == 0)
{
Length_High++;
if (Length_High == 0)
{
Corrupted = true; // Message is too long }
}
if (Message_Block_Index == 64)
{
ProcessMessageBlock();
}
j = j + 1;
length = length – 1;
}
}
public void Input(byte message_element)
{
byte[] tmp = { message_element };
Input(tmp, 1);
}
}
}
|
File : Form1.cs (Berisi method dari Tampilan GUI ketika di click) |
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.VisualBasic;
// created by BayuPRN namespace IlkompSHA1 {
public partial class MainForm : Form {
public MainForm()
{
InitializeComponent();
}
private void bFile_Click(object sender, EventArgs e)
{
DialogResult d = OpenDialog.ShowDialog();
if (d == DialogResult.OK || d == DialogResult.Yes)
{
String fn = OpenDialog.FileName;
MyFileIO fio = new MyFileIO(fn);
if (fio.FileExists())
{
txtFile.Text = fn;
byte[] bindata = new byte[1];
fio.LoadFile(ref bindata);
SHA1 sha = new SHA1();
sha.Reset();
int i;
for (i = 0; i <= bindata.Length – 1; i++)
{
sha.Input(bindata[i]);
}
uint[] message_diggest = new uint[5];
if (!sha.Result(ref message_diggest))
{
txtHasil.Text = “File tidak dapat diakses!”;
}
else
{
txtHasil.Text = String.Format (“{0}-{1}-{2}-{3}-{4}”,
Conversion.Hex(message_diggest[0]),
Conversion.Hex(message_diggest[1]),
Conversion.Hex(message_diggest[2]),
Conversion.Hex(message_diggest[3]),
Conversion.Hex(message_diggest[4]));
}
}
else
{
MessageBox.Show(“File tidak dapat diakses atau file tidak ada.”, “:: SHA1 Error”, MessageBoxButtons.OK);
}
}
}
}
}
|
File : MyFileIO.cs (Berisi class untuk mengakses/membaca isi file) |
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace IlkompSHA1 {
public class MyFileIO {
private String fn;
public MyFileIO( String fileName )
{
fn = fileName;
}
public bool FileExists()
{
if(File.Exists(fn)){
return true;
} else {
return false;
}
}
public bool LoadFile(ref byte[] BinData)
{
FileStream fs;
try
{
fs = new FileStream( fn, FileMode.Open );
BinData = new byte[fs.Length ];
fs.Read( BinData, 0, (int)fs.Length );
fs.Close();
return true;
}catch(Exception ex){
return false;
}
}
}
}
|
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 IlkompSHA1.exe Untuk menjalankan di linux, melalui console jalankan perintah $> mono IlkompSHA1.exe Jika ingin mengkompilasi ulang source code di Windows, ketikkan $> msbuild IlkompSHA1.sln Jika ingin mengkompilasi ulang source code di Linux, ketikkan $> xbuild IlkompSHA1.sln |
2 responses to “Penerapan Algoritma HASH SHA1 menggunakan C# .NET”