Implementasi Deskripsi Teks Menggunakan Algoritma Hill Chiper Pada Java

Table of Contents
Melanjutkan dari pembahasan sebelumnya tentang implementasi enkripsi teks menggunakan algoritma hill chiper, maka kali ini saya akan membahas mengenai implementasi deskripsi teks dengan algoritma yang sama, yaitu hill chiper. Alur deskripsi hill chiper dapat diilustrasikan seperti pada gambar 1 berikut : 
Gambar 1 Ilustrasi Deskripsi Hill Chiper (sumber : Hasugian, 2013)

Sebagaimana yang kita ketahui, bahwa enkripsi teks hill chiper menghasilkan bentuk chipertext. Oleh karenanya, proses deskripsi teks hill chiper bertujuan untuk merubah kembali chipertext menjadi bentuk plaintext. Bagaimana mendeskripsikan teks menggunakan hill chiper? Perlu teman-teman ingat bahwa kunci yang digunakan dalam proses enkripsi tetap digunakan untuk proses deskripsi. Sehingga proses enkripsi dan deskripsi hill chiper harus menggunakan kunci yang sama agar teks plaintext dapat utuh dan terbaca dengan jelas.

Secara matematis, proses deskripsi hill chiper dapat dihitung menggunakan rumus :
P = invers(K) * C
P = plaintext ;
invers(K) = invers matrik [Kunci] ;
C = chipertext ;

Sebagaimana pada pembahasan sebelumnya, matrik kunci yang saya gunakan berordo 2x2 yaitu {{5,6},{2,3}}. Dengan contoh plaintext MALANG, menghasilkan chipertext IYDWXS. Tugas kita adalah bagaimana mendeskripsikan chipertext IYDWXS agar berubah kembali ke plaintext MALANG menggunakan kunci matrik {{5,6},{2,3}} ? Saya ingatkan lagi, perhitungan enkripsi pada pembahasan sebelumnya menggunakan modulo 26 karena melibatkan pasangan huruf dan angka sebanyak 26 untuk proses konversi (lihat gambar 2). Oleh karenanya, perhitungan deskripsi nantinya juga tetap melibatkan modulo 26. Baiklah, tidak berpanjang lebar. Langsung ke implementasi perhitungan manual.

Gambar 2 Pasangan huruf dan angka untuk konversi

Tahap 1 : Mencari nilai invers matrik kunci
Langkah pertama adalah mencari invers matriks kunci menggunakan invers modulo determinan matriks kunci. 

maka determinan matrik [K] = (5*3)-(6-2) = 3

maka perhitungan invers modulo-nya adalah


3x =1 mod 26
3x =1 + 26k
x = (1+26k)/3 ; cari k = n sehingga hasil x adalah bilangan bulat

untuk k=0 maka  x=(1+26*0)/3= 1/3 (bukan bilangan bulat)
untuk k=1 maka x=(1+26*1)/3= 9    (bilangan bulat)
sehingga invers dari 3 mod 26 ekuivalen dengan 9 mod 26 yaitu 9

Nilai 9 diatas dinamakan sebagai nilai multiplikatif determinan yang berguna untuk memudahkan mencari nilai invers matrik terutama agar nilai invers matrik tidak bernilai pecahan. Selanjutnya, berhitungan masih berlanjut untuk mendapatkan nilai invers matrik.

Ketika berhitungan invers matrik diterapkan pada matrik kunci, maka didapatkan hasil invers matrik kunci adalah:



Catatan : Untuk modulo bilangan negatif dapat diperoleh dengan cara :
misal : -27 mod 26 = -n mod x, maka :
-n mod x = x-(n mod x)
-27 mod 26 = 26-(27 mod 26)
-27 mod 26 = 26-1
-27 mod 26 = 25

Tahap II : Transformasi Huruf ke Angka
Sebelum setiap huruf dalam chipertext dilakukan transformasi ke bentuk angka, terlebih dahulu dilakukan pemisahan huruf menjadi beberapa blok. Setiap blok terdiri dari 2 huruf. Hal ini dilakukan karena matrik kunci yang digunakan berordo 2.

chipertext adalah IYDWXS, jika dipisahkan menjadi 2 huruf per blok menjadi :
I Y 
D W 
X S

Selanjutnya dilakukan transformasi untuk mengubah huruf menjadi angka dengan patokan tabel konversi pada gambar 2, dimana huruf A berpasangan dengan angka 0, dan seterusnya hingga huruf Z yang berpasangan dengan angka 25. Hasil transformasi adalah :
I Y  = 8 24
D W = 3 22
X S = 23 18

Tahap III : Perhitungan Chipertext dengan Invers Matrik Kunci
Berdasarkan hasil pada tahap II, diperoleh chipertext yang telah ditransformasikan dalam bentuk angka. Yaitu :
Blok 1 = [8 24]
Blok 2 = [3 22]
Blok 3 = [23 18]

Ketiga blok chipertext tersebut masing-masingnya akan dikalikan dengan invers matrik kunci, hasilnya adalah

diperoleh hasil perhitungan sebanyak 3 blok, masing-masing blok adalah [12 0], [11 0], [13 6]

Tahap IV : Transformasi Angka ke Huruf untuk Hasil Deskripsi
Langkah terakhir adalah mentransformasikan kembali angka yang didapatkan melalui proses tahap III menjadi bentuk huruf dengan tetap berpatokan kepada tabel konversi pada gambar 2. Hasil transformasi ini secara otomatis akan menjadi hasil deskripsi teks.

[12 0] = [M A]
[11 0] = [L A]
[13 6] = [N G]

Jika blok tersebut dirangkai menjadi satu huruf, akan berbunyi MALANG. Mari kita teliti kembali serangkaian proses enkripsi dan deskripsi ini :
Plaintext : MALANG + ENKRIPSI = Chipertext IYDWXS
Chipertext IYDWXS + DESKRIPSI = Plaintext : MALANG

Jadi, dapat disimpulkan enkripsi dan deskripsi teks menggunakan hill chiper pada perhitungan manual berjalan dengan baik. Sekarang, tahap per tahap pada perhitungan manual saya rubah ke proses pemrograman menggunakan java. Berikut kode sumber untuk implementasi deskripsi teks hill chiper pada java menggunakan Chipertext IYDWXS dan kunci deskripsi {{5, 6}, {2, 3}}.

import javax.swing.JOptionPane;

/**
 *
 * @author CHARIS
 */
public class HillChiper_Deskripsi26 {

    static String[] abjad = {"A", "B", "C", "D", "E", "F", "G", "H",
        "I", "J", "K", "L", "M", "N", "O", "P", "Q",
        "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};

    static int[] angka = {0, 1, 2, 3, 4,
        5, 6, 7, 8, 9,
        10, 11, 12, 13, 14,
        15, 16, 17, 18, 19,
        20, 21, 22, 23, 24, 25
    };

    static int modulo = 26;
    static int[][] matrikInvers = new int[2][2];
    static String Hasil_AbjadKeAngka[][];
    static String[] Hasil_pisahkanTeks;
    static String hasilHitungKunci[][];
    static String totalHasilDeskrip = "";

    public int hitungInvers(int[][] matriks) {
        int determinan = (matriks[0][0] * matriks[1][1]) - (matriks[0][1] * matriks[1][0]);
        System.out.println("Determinan = " + determinan);
        if (determinan == 0) {
            System.out.println("Matrik tidak memiliki invers");
        } else if (determinan < 0) {
            JOptionPane.showMessageDialog(null, "Kunci Tidak Memenuhi Syarat");
        } else {

            int d = matriks[1][1];
            int c = -(matriks[1][0]);
            int b = -(matriks[0][1]);
            int a = (matriks[0][0]);

            matrikInvers[0][0] = d;
            matrikInvers[0][1] = b;
            matrikInvers[1][0] = c;
            matrikInvers[1][1] = a;

            int MultiplikatifDet = 0;
            for (MultiplikatifDet = 0; MultiplikatifDet < 1000; MultiplikatifDet++) {
                if ((determinan * MultiplikatifDet) % modulo == 1 % modulo && determinan > 0) {
                    MultiplikatifDet = MultiplikatifDet;
                    System.out.println("MultiPlikatif = " + MultiplikatifDet);
                    break;
                }
            }

            for (int i = 0; i < matrikInvers.length; i++) {
                for (int j = 0; j < matrikInvers[0].length; j++) {
                    if (matrikInvers[i][j] < 0) {
                        matrikInvers[i][j] = modulo - (Math.abs(matrikInvers[i][j]) % modulo);
                    } else {
                        matrikInvers[i][j] = matrikInvers[i][j] % modulo;
                    }
                    matrikInvers[i][j] = matrikInvers[i][j] * MultiplikatifDet;
                    matrikInvers[i][j] = matrikInvers[i][j] % modulo;
                }
            }
        }
        return determinan;
    }

    static void nilaiInversMatrik() {
        System.out.println("========== NILAI INVERS MATRIKS ==========");
        for (int i = 0; i < matrikInvers.length; i++) {
            for (int j = 0; j < matrikInvers[0].length; j++) {
                System.out.print(matrikInvers[i][j] + " ");
            }
            System.out.println("");
        }
    }

    static String pisahkanTeks(String text) {

        String teksnya = text;
        if (teksnya.length() % 2 == 0) {
            teksnya = text;
        } else {
            teksnya = text + ".";
        }
        assert teksnya.length() % 2 == 0;
        System.out.println("Jumlah Huruf : " + teksnya.length());
        Hasil_pisahkanTeks = new String[teksnya.length() / 2];
        System.out.println("========== MEMBAGI TIAP 2 HURUF ==========");
        for (int index = 0; index < Hasil_pisahkanTeks.length; index++) {
            Hasil_pisahkanTeks[index] = teksnya.substring(index * 2, index * 2 + 2);
            System.out.println(Hasil_pisahkanTeks[index]);
        }
        return teksnya;
    }

    String[][] AbjadKeAngka(String[] text) {
        Hasil_AbjadKeAngka = new String[text.length][2];

        for (int i = 0; i < text.length; i++) {
            String char1 = text[i].substring(0, 1);
            String char2 = text[i].substring(1);

            for (int j = 0; j < abjad.length; j++) {
                if (char1.equals(abjad[j])) {
                    char1 = String.valueOf(angka[j]);
                }
                if (char2.equals(abjad[j])) {
                    char2 = String.valueOf(angka[j]);
                }
            }

            if (Hasil_AbjadKeAngka[i][0] == null) {
                Hasil_AbjadKeAngka[i][0] = char1;
                //System.out.print(hasilKonversi[i][0] + " ");
                if (Hasil_AbjadKeAngka[i][1] == null) {
                    Hasil_AbjadKeAngka[i][1] = char2;
                }
            }
        }
        System.out.println("========== TRANSFORMASI HURUF KE ANGKA ==========");
        for (int n = 0; n < Hasil_AbjadKeAngka.length; n++) {
            for (int p = 0; p < Hasil_AbjadKeAngka[0].length; p++) {
                System.out.print(Hasil_AbjadKeAngka[n][p] + " ");
            }
            System.out.println("");
        }

        return Hasil_AbjadKeAngka;
    }

    static String[][] perhitunganKunci(String[][] angka, int[][] kunci) {
        int kunciK0B0 = kunci[0][0];
        int kunciK0B1 = kunci[0][1];
        int kunciK1B0 = kunci[1][0];
        int kunciK1B1 = kunci[1][1];

        hasilHitungKunci = new String[angka.length][2];

        System.out.println("========== HASIL PERHITUNGAN KUNCI ==========");
        for (int n = 0; n < angka.length; n++) {
            int konvert = Integer.parseInt(angka[n][0]);
            int konvert1 = Integer.parseInt(angka[n][1]);
            int hasil = (kunciK0B0 * konvert) + (kunciK0B1 * konvert1);
            int hasil1 = (kunciK1B0 * konvert) + (kunciK1B1 * konvert1);
            hasil = hasil % modulo;
            hasil1 = hasil1 % modulo;

            if (hasilHitungKunci[n][0] == null) {
                hasilHitungKunci[n][0] = String.valueOf(hasil);
                if (hasilHitungKunci[n][1] == null) {
                    hasilHitungKunci[n][1] = String.valueOf(hasil1);
                }
            }
        }

        for (int i = 0; i < hasilHitungKunci.length; i++) {
            for (int j = 0; j < hasilHitungKunci[0].length; j++) {
                System.out.print(hasilHitungKunci[i][j] + " ");
            }
            System.out.println("");
        }
        return hasilHitungKunci;
    }

    String AngkaKeAbjad(String[][] hasilHitungKunci) {

        String hasilDeskrip = "";

        System.out.println("========== HASIL DESKRIPSI ==========");
        totalHasilDeskrip = "";
        for (int i = 0; i < hasilHitungKunci.length; i++) {
            for (int j = 0; j < hasilHitungKunci[0].length; j++) {
                for (int k = 0; k < angka.length; k++) {
                    if (hasilHitungKunci[i][j].equals(String.valueOf(angka[k]))) {
                        hasilDeskrip = abjad[k];
                        totalHasilDeskrip = totalHasilDeskrip + hasilDeskrip;
                    }
                }
            }
        }

        System.out.println(totalHasilDeskrip);
        return totalHasilDeskrip;
    }

    public String hitungDeskripsi(String text, int[][] kunci) {

        HillChiper_Deskripsi26 yuk = new HillChiper_Deskripsi26();
        yuk.hitungInvers(kunci);
        yuk.pisahkanTeks(text);
        yuk.AbjadKeAngka(Hasil_pisahkanTeks);
        yuk.nilaiInversMatrik();
        yuk.perhitunganKunci(Hasil_AbjadKeAngka, matrikInvers);
        yuk.AngkaKeAbjad(hasilHitungKunci);
        return totalHasilDeskrip;
    }

    public static void main(String[] args) {
        HillChiper_Deskripsi26 hill = new HillChiper_Deskripsi26();
        String a = "IYDWXS";
        System.out.println("Chipertext : " + a);
        int kunci[][] = {{5, 6}, {2, 3}};
        hill.hitungDeskripsi(a, kunci);
    }
}

Ketika program diatas dijalankan, hasil yang diperoleh sama persis dengan perhitungan manual.

Gambar 3 Hasil Deskripsi dengan Program Java

























Catatan : Deskripsi hill chiper sebagaimana yang telah dijabarkan diatas tentu berjalan dengan baik asal chipertext yang diberikan sesuai dengan tabel konversi pada gambar 2, yaitu chipertext terdiri atas huruf kapital dengan jumlah karakter bernilai genap. Contoh : chipertext IYDWXS, terdiri atas huruf kapital dengan jumlah karakter 6 (genap).

Namun, andaikata input chipertext adalah :
  1. Huruf dengan jumlah karakter ganjil, misal : gLSFQdijDv, 9 huruf (ganjil) 
  2. Terdiri dari kombinasi huruf besar maupun kecil, misal : FxcwWS
  3. Memiliki tanda baca titik maupun spasi, misal : FxcwWS azGVZRiWSPV
Berdasarkan tambahan jenis chipertext diatas, tentu jika diimplementasikan menggunakan tabel konversi pada gambar 2 tidak akan bisa, dan menghasilkan chiper text yang tidak akurat. Solusinya adalah dengan merubah tabel konversi sehingga memperbanyak jumlah pasangan konversi. Contoh penambahan pasangan konversi adalah pada gambar 4 berikut, yaitu penambahan pada simbol titik (.) berpasangan dengan angka 26, dan simbol spasi (" ") pada angka 27.
Gambar 4 Penambahan Pasangan Konversi

Contoh implementasi enkripsi dan deskripsi hill chiper menggunakan plaintext dan chipertext huruf kecil, huruf kapital, simbol titik dan spasi terdapat pada gambar 5 dan gambar 6 berikut.

Gambar 5 Proses Enkripsi Teks

Gambar 6 Proses Deskripsi Teks

Semoga penjelasan ringkas tentang deskripsi hill chiper ini bermanfaat bagi teman-teman, silakan hubungi saya via email maupun WhatApp jika ada hal-hal yang perlu didiskusikan. Pun jika ingin mendapatkan Program + GUInya. 

Referensi : 
  • Enkripsi dan Deskripsi menggunakan Hill Chiper, pandiangan-m.blogspot.co.id diakses tanggal 14 Agustus 2016
  • Hasugian, Abdul Halim. 2013. Implementasi Algoritma Hill Chiper dalam Penyandian Data. Pelita Informatika Budi Darma, Volume : IV, Nomor: 2, Agustus 2013 ISSN : 2301-9425 
Lihat juga demo program Enkripsi dan Deskripsi menggunakan Algoritma Hill Chiper di Channel Youtube Informatika Kita

1 comment

Terima kasih telah mampir di blog kami. Jika ingin menghubungi penulis, silakan kirim pesan via email di kitainformatika@gmail.com atau via WA di 087750503014. Jika mood penulis lagi baik, biasanya fast respon.
Comment Author Avatar
June 21, 2018 at 3:42 PM Delete
sarap asli perhitungan inverse matrix to mod nya gmna bro ? ane cmn butuh itu doang ni biar bisa memahami hill chiper