Steganografi menggunakan Least Significant Bit (LSB) pada Java

Steganografi merupakan tehnik atau salah satu metode menyembunyikan pesan pada suatu media berupa gambar, audio maupun video sehingga pesan tersebut tidak dapat dibaca oleh pihak lain selain pemberi dan penerima pesan. Steganography berasal dari bahasa yunani yaitu steganos yang berarti tersembunyi dan graphein yang berarti menulis.

Sedangkan cryptografi merupakan tehnik menyamarkan pesan dengan cara mengacak atau merubahnya kedalam bentuk tertentu.

Media

Adapun media-media yang dapat dipakai dalam menyembunyikan pesan (steganografi) adalah:

  • Format image : bitmap (bmp), gif, pcx, jpeg, dll.
  • Format audio : wav, voc, mp3, dll.
  • Format video : avi, mpeg dll
  • Format lain : teks file, html, pdf, dll.

Metode

Sedangkan metode steganografi terdiri dari:

  • Least Significant Bit (LSB)
  • Algorithem and Transformation
  • Redundant Pattren Encoding
  • Spread Spectrum Methode
  • Steganalisis and Stegosystem

Pesan yang tersimpan pada sebuah media penympanan sebelum disimpan atau disembunyikan dapat di encrypt terlebih dahulu menggunakan algoritma encryption seperti ciphertext viginare, ciphertext caisar, MD5, RSA dll. Sehingga pesan menjadi benar-benar rahasia karena menggabungkan kedua metode yaitu Cryptografi dan Steganografi.

Pada kesempatan kali ini, sedikit akan mengulas mengenai bagaimana menyembunyikan pesan atau Steganografi menggunakan Least Significant Bit (LSB) dengan metode encripsi menggunakan algoritma Ciphertext Viginare pada media penyimpanan berupa gambar / image. Bahasa pemrograman yang digunakan kali ini adalah menggunakan bahasa pemrograman Java.

OK langsung aja berikut penjelasan singkat mengenai Steganografi Menggunakan Least significant Bit (LSB):

1. Class Image_Filter.java

Class ini digunakan untuk menyaring media penyimpanan yang akan dipakai, dalam hal ini gambar yang dapat digunakan adalah gambar yang berextensi .jpg dan .png

[code lang=”java”]
package stegano.gun;

/*
*Import List
*/
import java.io.*;

/*
*Image_Filter Class
*/
public class Image_Filter extends javax.swing.filechooser.FileFilter
{

protected boolean isImageFile(String ext)
{
return (ext.equals(“jpg”)||ext.equals(“png”));
}

public boolean accept(File f)
{
if (f.isDirectory())
{
return true;
}

String extension = getExtension(f);
if (extension.equals(“jpg”)||extension.equals(“png”))
{
return true;
}
return false;
}

public String getDescription()
{
return “Supported Image Files”;
}

protected static String getExtension(File f)
{
String s = f.getName();
int i = s.lastIndexOf(‘.’);
if (i > 0 && i < s.length() – 1)
return s.substring(i+1).toLowerCase();
return “”;
}
}
[/code]

2. Class ViginareCipher.java
Class ini digunakan untuk meng-encrypt text yang akan disimpan ke dalam media penyimpanan.

[code lang=”java”]

package stegano.gun;

import java.util.Vector;

public class VigenereCipher {
private static final char[] alphnum = {
‘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’, ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’,
‘@’,’?’,’#’,’-‘,’+’,’!’,’$’,’%’,’&’,’*’,'(‘,’)’,’_’,’+’,’=’,
‘.’,’,’,’;’,’:’,'”‘,’\”,’}’,'{‘,’\\’,’/’,’^’,'<‘,’>’,'[‘,’]’,
‘^’,’|’,’`’,’~’
};

private static final int dim = alphnum.length;
private char[][] vgnrSquare = new char[alphnum.length][alphnum.length];
private Vector<Character> alphnumv = new Vector<Character>();

public VigenereCipher() {
init();

/* copy contents of alphum array to alphnumv vector to exploit indexOf method */
for(int i = 0; i < dim; i++) {
alphnumv.add(alphnum[i]);
}

print();
}

/**
* Initializes the contents of the Vigenere Square using the given alphanumeric set.
*/
public void init() {
/* Fill up the upper left triangle */
for(int i = 0; i < dim; i++) {
for(int j = i; j < dim; j++) {
if(i == 0) {
vgnrSquare[i][j] = alphnum[j];
} else {
vgnrSquare[i][j-i] = alphnum[j];
}
}
}

/* Fill up the remaining cells */
for(int i = 1; i < dim; i++) {
int k = 0; // always start from the first element of the set

for(int j = dim-i; j < dim; j++) {
vgnrSquare[i][j] = alphnum[k];
k++;
}
}
}

/**
* Encrypts the given plaintext using the specified key.
* @param plaintext the text to be encrypted
* @param key the encryption key
*/
public String encrypt(String plaintext, String key) {
if(keyHasSpace(key) || key.length() == 0) {
System.out.println(“\nKey cannot contain a space!\n”);
return null;
} else if(plaintext.length() == 0) {
System.out.println(“\nNothing to encrypt!\n”);
return null;
} else {
char[] ciphertext = new char[plaintext.length()];
key = generateKey(plaintext, key); // update key

for(int i = 0; i < ciphertext.length; i++) {
int row = alphnumv.indexOf(Character.toUpperCase(key.charAt(i)));
int col = alphnumv.indexOf(Character.toUpperCase(plaintext.charAt(i)));

if(plaintext.charAt(i) == ‘ ‘) {
ciphertext[i] = ‘ ‘;
} else if(plaintext.charAt(i) == ‘\n’) {
ciphertext[i] = ‘\n’;
} else if(plaintext.charAt(i) == ‘\t’) {
ciphertext[i] = ‘\t’;
} else{
ciphertext[i] = vgnrSquare[row][col]; // encryption

/* retain case
if(Character.isLowerCase(plaintext.charAt(i))) {
ciphertext[i] = Character.toLowerCase(ciphertext[i]);
}*/
}
}

System.out.println(“\nPlaintext: ” + plaintext);
System.out.println(“Key: ” + key);
return (new String(ciphertext));
}
}

/**
* Decrypts the given ciphertext using the specified key.
* @param ciphertext the text to be decrypted
* @param key the decryption key
*/
public String decrypt(String ciphertext, String key) {
if(keyHasSpace(key) || key.length() == 0) {
System.out.println(“\nKey cannot contain a space!\n”);
return null;
} else if(ciphertext.length() == 0) {
System.out.println(“\nNothing to decrypt!\n”);
return null;
} else {

char[] plaintext = new char[ciphertext.length()];
key = generateKey(ciphertext, key); // update key

for(int i = 0; i < plaintext.length; i++) {
int row = alphnumv.indexOf(Character.toUpperCase(key.charAt(i)));
int col = alphnumv.indexOf(Character.toUpperCase(ciphertext.charAt(i)));

if(ciphertext.charAt(i) == ‘ ‘) {
plaintext[i] = ‘ ‘;
} else if(ciphertext.charAt(i) == ‘\n’) {
plaintext[i] = ‘\n’;
} else if(ciphertext.charAt(i) == ‘\t’) {
plaintext[i] = ‘\t’;
}else{
int x = (col – row) % dim; // decryption algebraic approach

if(x >= 0) {
plaintext[i] = alphnumv.elementAt(x).toString().charAt(0);
} else {
plaintext[i] = alphnumv.elementAt(dim+x).toString().charAt(0);
}

/* retain case
if(Character.isLowerCase(ciphertext.charAt(i))) {*/
plaintext[i] = Character.toLowerCase(plaintext[i]);
//}
}
}

System.out.println(“\nCiphertext: ” + ciphertext);
System.out.println(“Key: ” + key);
return (new String(plaintext));
}
}

/**
* Generates the repeating key.
* @param text the plaintext/ciphertext which serves as the basis for the key’s length
* @param key the initial, non-repeating key
* @return newKey – the new (repeating) key
*/
public String generateKey(String text, String key) {
char[] newKey = new char[text.length()];
int repeatFlag = 0;

for(int i = 0; i < newKey.length; i++) {
if(text.charAt(i) == ‘ ‘) {
newKey[i] = ‘ ‘;
} else {
newKey[i] = key.charAt(repeatFlag);

if(repeatFlag+1 == key.length()) {
repeatFlag = 0;
} else {
repeatFlag++;
}
}
}

return new String(newKey);
}

/**
* Checks whether the inputted key contains a space.
* @param key the key to be scanned
* @return answer – boolean value
*/
public boolean keyHasSpace(String key) {
boolean answer = false;

for(int i = 0; i < key.length(); i++) {
if(key.charAt(i) == ‘ ‘) {
answer = true;
break;
}
}

return answer;
}

/**
* Prints the Vigenere Square.
*/
public void print() {
System.out.println();

for(int i = 0; i < dim; i++) {
for(int j = 0; j < dim; j++) {
System.out.print(vgnrSquare[i][j] + ” “);

if(j == dim-1) {
System.out.println();
}
}
}
}

}
[/code]

3. Class Steganography.java
Class ini digunakan untuk menyisipkan pesan pada gambar menggunakan metode Least Significant Bit (LSB)

[code lang=”java”]
package stegano.gun;

import java.io.File;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.awt.image.DataBufferByte;

import javax.imageio.ImageIO;
import javax.swing.JOptionPane;

public class Steganography
{

public Steganography()
{
}

public String encrypt(String text, String key){
char[] karakter=text.toCharArray();
String cipherText=””;
for(int j=0;j<karakter.length;j++){
key+=j+2;
}
for(int i=0;i<karakter.length;i++){
cipherText+=(char)(((128+(karakter[i])+(key.charAt(i)))%128));
}
return cipherText;
}

public String Decrypt(String text, String key1){

char[] karakter=text.toCharArray();
String cipherText=””;
for(int j=0;j<karakter.length;j++){
key1+=j+2;
}
for(int i=0;i<karakter.length;i++){
cipherText+=(char)(((128+(karakter[i])-(key1.charAt(i)))%128));

}
return cipherText;
}

public boolean encode(String path, String original, String ext1, String stegan, String message)
{
String file_name = image_path(path,original,ext1);
BufferedImage image_orig = getImage(file_name);

//user space is not necessary for Encrypting
BufferedImage image = user_space(image_orig);
image = add_text(image,message);

return(setImage(image,new File(image_path(path,stegan,”png”)),”png”));
}

public String decode(String path, String name)
{
byte[] decode;
try
{
//user space is necessary for decrypting
BufferedImage image = user_space(getImage(image_path(path,name,”png”)));
decode = decode_text(get_byte_data(image));
return(new String(decode));
}
catch(Exception e)
{
JOptionPane.showMessageDialog(null,
“Tidak ada pesan yang tersembunyi di dalam gambar yang dipilih”,”Error”,
JOptionPane.ERROR_MESSAGE);
return “”;
}
}

private String image_path(String path, String name, String ext)
{
return path + “/” + name + “.” + ext;
}

private BufferedImage getImage(String f)
{
BufferedImage image = null;
File file = new File(f);

try
{
image = ImageIO.read(file);
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null,
“Gambar Tidak dapat Dibaca!”,”Error”,JOptionPane.ERROR_MESSAGE);
}
return image;
}
private boolean setImage(BufferedImage image, File file, String ext)
{
try
{
file.delete(); //delete resources used by the File
ImageIO.write(image,ext,file);
return true;
}
catch(Exception e)
{
JOptionPane.showMessageDialog(null,
“Gambar Tidak dapat Disimpan!”,”Error”,JOptionPane.ERROR_MESSAGE);
return false;
}
}

private BufferedImage add_text(BufferedImage image, String text)
{
//convert all items to byte arrays: image, message, message length
byte img[] = get_byte_data(image);
byte msg[] = text.getBytes();
byte len[] = bit_conversion(msg.length);
try
{
encode_text(img, len, 0); //0 first positiong
encode_text(img, msg, 32); //4 bytes of space for length: 4bytes*8bit = 32 bits
}
catch(Exception e)
{
JOptionPane.showMessageDialog(null,
“Target File cannot hold message!”, “Error”,JOptionPane.ERROR_MESSAGE);
}
return image;
}

private BufferedImage user_space(BufferedImage image)
{
//create new_img with the attributes of image
BufferedImage new_img = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D graphics = new_img.createGraphics();
graphics.drawRenderedImage(image, null);
graphics.dispose(); //release all allocated memory for this image
return new_img;
}

private byte[] get_byte_data(BufferedImage image)
{
WritableRaster raster = image.getRaster();
DataBufferByte buffer = (DataBufferByte)raster.getDataBuffer();
return buffer.getData();
}
private byte[] bit_conversion(int i)
{
//originally integers (ints) cast into bytes
//byte byte7 = (byte)((i & 0xFF00000000000000L) >>> 56);
//byte byte6 = (byte)((i & 0x00FF000000000000L) >>> 48);
//byte byte5 = (byte)((i & 0x0000FF0000000000L) >>> 40);
//byte byte4 = (byte)((i & 0x000000FF00000000L) >>> 32);

//only using 4 bytes
byte byte3 = (byte)((i & 0xFF000000) >>> 24); //0
byte byte2 = (byte)((i & 0x00FF0000) >>> 16); //0
byte byte1 = (byte)((i & 0x0000FF00) >>> 8 ); //0
byte byte0 = (byte)((i & 0x000000FF) );
//{0,0,0,byte0} is equivalent, since all shifts >=8 will be 0
return(new byte[]{byte3,byte2,byte1,byte0});
}

private byte[] encode_text(byte[] image, byte[] addition, int offset)
{
//check that the data + offset will fit in the image
if(addition.length + offset > image.length)
{
throw new IllegalArgumentException(“File not long enough!”);
}
//loop through each addition byte
for(int i=0; i<addition.length; ++i)
{
//loop through the 8 bits of each byte
int add = addition[i];
for(int bit=7; bit>=0; –bit, ++offset) //ensure the new offset value carries on through both loops
{
//assign an integer to b, shifted by bit spaces AND 1
//a single bit of the current byte
int b = (add >>> bit) & 1;
//assign the bit by taking: [(previous byte value) AND 0xfe] OR bit to add
//changes the last bit of the byte in the image to be the bit of addition
image[offset] = (byte)((image[offset] & 0xFE) | b );
}
}
return image;
}

private byte[] decode_text(byte[] image)
{
int length = 0;
int offset = 32;
//loop through 32 bytes of data to determine text length
for(int i=0; i<32; ++i) //i=24 will also work, as only the 4th byte contains real data
{
length = (length << 1) | (image[i] & 1);
}

byte[] result = new byte[length];

//loop through each byte of text
for(int b=0; b<result.length; ++b )
{
//loop through each bit within a byte of text
for(int i=0; i<8; ++i, ++offset)
{
//assign bit: [(new byte value) << 1] OR [(text byte) AND 1]
result[b] = (byte)((result[b] << 1) | (image[offset] & 1));
}
}
return result;
}
}
[/code]

4. Desain Halaman Encode dan Halaman Decode
Berikut Desain Halaman Encode:
encode

Berikut Desain Halaman Decode:
decode

Hasil Uji Coba Encode :
hasil1

Uji Coba Decode:
hasil2

Download Aplikasi Steganografi versi 1.0 (JSteg v1.0)

Related Post

Uninstall USB Driver yang tidak terpakai menggunak... Setiap kali kita pasang Universal Serial Bus (USB) baik berupa USB Printer Cable, USB Flash Drive maupun USB dalam bentuk lainnya maka secara otomatis...
Java 8: Penggunaan Date Time dan Calender pada Jav... Pada tuturial kali ini, menjelaskan penggunaan Date Time pada Java yang menggunakan API java.until.Date dan java.until.Calender. Sebagai seorang progr...
Project : Sistem Informasi Quiz Online System berb... Model pengembangan sistem yang digunakan dalam proses pengembangan perangkat lunak quiz online system ini adalah Classic Life Cycle atau sering disebu...
Aplikasi Rumah Makan / Restaurant (MSIDRumahMakan ... Aplikasi Rumah Makan / Restaurant (MSIDRumahMakan v1.0) merupakan aplikasi/perangkat lunak yang digunakan untuk keperluan administrasi Rumah Makan, Ba...
Java 8 : Membandingkan Tanggal pada Java Membandingkan tanggal pada java sangatlah mudah dengan catatan telah memahami tutorial sebelumnya tentang penggunaan API Date Time dan Calender. Berik...
Aplikasi Minimarket Pro v2.3 (Java Aplication) Salah satu apilasi yang kami kembangkan sendiri adalah Aplikasi minimarket v2.3. Aplikasi Minimarket Pro v2.3 merupakan aplikasi untuk toko grosir, mi...
JavaFX Tutorial : Membuat Grafik Line Chart Membuat grafik Line Chart pada javaFX tidaklah sesulit yang dibayangkan. Berikut beberapa contoh Line Chart pada JavaFX. Baca Juga : Bagaimana meng...
Download XAMPP Terbaru untuk Windows, Linux, MAC O... XAMPP singkatan dari X Apache MySQL PHP dan Perl merupakan aplikasi Devlopment yang dikembangkan oleh Apache Friends sebuah organisasi yang didirikan ...
Aplikasi Manajemen Hotel (MSIDHotel V2.0) Aplikasi MSIDHotel v2.0 merupakan Aplikasi manajemen hotel atau bungalows untuk manajemen tamu hotel mulai dari proses reservasi sampai proses check o...
Manipulasi File pada Java Untuk melakukan manipulasi File pada Java menggunakan class java.io.File mulai dari membuat file, menghapus file, cek permision sebuah file, cek meta ...

12 tanggapan untuk “Steganografi menggunakan Least Significant Bit (LSB) pada Java

  1. Rian Ardianto Balas

    bang please minta source code nya yg lengkap beserta file java netbeans nya ke ra2321998@gmail.com buat bahan belajar saya soalnya kasus tugasnya serupa cuma beda metode .. klo sprti prlu dibeli dll bleh silahkan hub aja sya ke WA 089638686707 nnti dibicarakan lebih lanjut bang ok

  2. Riz Balas

    terimakasih programnya berjalan dengan lancar, apakah format file txt nya bisa dirubah jadi file dokumen ga mas ? semisal docx, xlsx, pdf dll itu source codenya diganti gimana ya?

  3. sam Balas

    Mas, bisa minta tolong dishare untuk source code dari fungsi-fungsi buttonnya?
    Terimakasih banyak

  4. amin Balas

    mas seandainya klau untuk menyembunyikan folder yg berisikan data di audio,dan pada saat di decode bisa gak mas folder tersebut di simpan kembali.dan audio yg berisikann data di hapus.
    “kluarga java”

  5. Na'diena Balas

    trimakasih artikel nya, izin copas ya buat tugas kampus.hehehehehe

  6. oni Balas

    sya coba di netbeans kog gak bisa yah? boleh minta project.nya g gan?

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

four × 2 =