sekuriti


Setelah sebelumnya saya tulis sedikit tentang mudahnya melakukan enkripsi, sekarang saya tertarik untuk mencoba enkripsi yang lain lagi karena saya juga penasaran. Jatuhlah pilihan saya di RSA…. kenapa RSA? Selain bisa untuk enkripsi, RSA juga bisa digunakan untuk digital signature.. Koq bisa ya? ya iyalah, masa ya iya dong. Alasan lainnya sih beberapa waktu yang lalu ada mahasiswa yang coba berkonsultasi tentang koding RSA di J2ME. Mau ngak mau saya coba cari tahu tentang RSA itu…

Menurut Rinaldi Munir, RSA adalah algoritma kunci publik yang paling populer. Kunci publik? Apa lagi tuh? Maksudnya sistem Kripto yang menggunakan dua kunci yang berbeda tapi merupakan pasangan untuk enkripsi dan dekripsinya. Misalnya x adalah kunci untuk enkripsi dan y adalah kunci untuk dekripsi. Disebut kunci publik karena ada satu kunci yaitu kunci x yang sengaja di publikasi agar setiap orang bisa mengenkripsi, sedangkan kunci y hanya dipegang oleh pemiliknya saja untuk mendekripsi. Tambahan lagi, kunci-kunci tersebut tidak bisa saling bertukar pasangan. Ngak bisa pindah ke lain hati katanya… v^^

Keamanan RSA terletak pada sulitnya memfaktorkan bilangan yang besar menjadi faktor-faktor prima. Selama belum ditemukan algoritma pemfaktoran yang efektif, selama itu pula keamanan RSA tetap terjamin. Kalo pingin lebih jelas secara matematis teorinya, temen-temen bisa unduh disini atau bisa liat di http://en.wikipedia.org/wiki/RSA.

Masih dalam platform J2ME, dan masih menggunakan library Bouncy Castle saya coba membangkitan pasangan kunci RSA dan melakukan enkripsi dan dekripsi.

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;
import javax.microedition.midlet.*;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.encodings.PKCS1Encoding;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.signers.PSSSigner;

/**
* @author Lenovo
*/
public class RSAMidlet extends MIDlet {
public void startApp() {
try {
System.out.println(“generator on”);

// plain message yang akan diproses
byte[] plain = “makhluk paling seksi”.getBytes();
byte[] keypair = generator();

// input stream pasangan kunci
ByteArrayInputStream bais = new ByteArrayInputStream(keypair);
DataInputStream dis = new DataInputStream(bais);

int modLen = dis.readInt();
int pubLen = dis.readInt();
int privLen = dis.readInt();
int pLen = dis.readInt();
int qLen = dis.readInt();
int dPLen = dis.readInt();
int dQLen = dis.readInt();
int qInvLen = dis.readInt();

byte[] modulo = new byte[modLen];
bais.read(modulo, 0, modLen);
byte[] pubExp = new byte[pubLen];
bais.read(pubExp, 0, pubLen);
byte[] privExp = new byte[privLen];
bais.read(privExp, 0, privLen);
byte[] p = new byte[pLen];
bais.read(p, 0, pLen);
byte[] q = new byte[qLen];
bais.read(q, 0, qLen);
byte[] dP = new byte[dPLen];
bais.read(dP, 0, dPLen);
byte[] dQ = new byte[dQLen];
bais.read(dQ, 0, dQLen);
byte[] qInv = new byte[qInvLen];
bais.read(qInv, 0, qInvLen);

dis.close();
bais.close();

// construct private key
RSAPrivateCrtKeyParameters privKey = constructPrivateKey(modulo, pubExp, privExp, p, q, dP, dQ, qInv);

// construct public key
RSAKeyParameters pubKey = constructPublicKey(modulo, pubExp);

byte[] cipher = rsaEncrypt(plain, pubKey);
System.out.println(“cipher: “+new String(cipher));

byte[] recovery = rsaDecrypt(cipher, privKey);
System.out.println(“recovery: “+new String(recovery));

} catch (IOException ex) {
ex.printStackTrace();
}

}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}

public RSAKeyParameters constructPublicKey(
byte[] modulo,
byte[] pubExp)
{
BigInteger n = new BigInteger(modulo);
BigInteger e = new BigInteger(pubExp);
return (new RSAKeyParameters(false, n, e));
}

public RSAPrivateCrtKeyParameters constructPrivateKey(
byte[] modulo,
byte[] pubExp,
byte[] privExp,
byte[] pByte,
byte[] qByte,
byte[] dPByte,
byte[] dQByte,
byte[] qInvByte)
{
BigInteger n = new BigInteger(modulo);
BigInteger e = new BigInteger(pubExp);
BigInteger d = new BigInteger(privExp);
BigInteger p = new BigInteger(pByte);
BigInteger q = new BigInteger(qByte);
BigInteger dP = new BigInteger(dPByte);
BigInteger dQ = new BigInteger(dQByte);
BigInteger qInv = new BigInteger(qInvByte);

return (new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
}

public byte[] rsaEncrypt(
byte[] inputByte,
RSAKeyParameters publicKey)
{
byte[] sesKeyCipher = null;
try {
AsymmetricBlockCipher rsaEngine = new PKCS1Encoding(new RSAEngine());
rsaEngine.init(true, publicKey);
System.out.println(“enkripsi berjalan…”);
System.out.println(“input encrypt length: “+inputByte.length);
sesKeyCipher = rsaEngine.processBlock(inputByte, 0, inputByte.length);
} catch (InvalidCipherTextException ex) {
ex.printStackTrace();
}
return sesKeyCipher;
}

public byte[] rsaDecrypt(
byte[] inputByte,
RSAPrivateCrtKeyParameters privateKey)
{
byte[] sesKeyPlain = null;
try {
AsymmetricBlockCipher rsaEngine = new PKCS1Encoding(new RSAEngine());
rsaEngine.init(false, privateKey);
System.out.println(“dekripsi berjalan…”);
System.out.println(“input decrypt length: “+inputByte.length);
sesKeyPlain = rsaEngine.processBlock(inputByte, 0, inputByte.length);
} catch (InvalidCipherTextException ex) {
ex.printStackTrace();
}
return sesKeyPlain;
}

public byte[] getSignature(
byte[] inputByte,
RSAPrivateCrtKeyParameters privateKey)
{
byte[] signatureByte = null;
try {
MD5Digest md5Engine = new MD5Digest();
RSAEngine rsaEngine = new RSAEngine();
PSSSigner signer = new PSSSigner(rsaEngine, md5Engine, 64);
signer.init(true, privateKey);
signer.update(inputByte, 0, inputByte.length);
signatureByte = signer.generateSignature();
} catch (DataLengthException ex) {
ex.printStackTrace();
} catch (CryptoException ex) {
ex.printStackTrace();
}
return signatureByte;
}

public boolean verifySignature(
byte[] inputByte,
byte[] signature,
RSAKeyParameters publicKey)
{
MD5Digest md5Engine = new MD5Digest();
RSAEngine rsaEngine = new RSAEngine();
PSSSigner signer = new PSSSigner(rsaEngine, md5Engine, 64);
signer.init(false, publicKey);
signer.update(inputByte, 0, inputByte.length);

return signer.verifySignature(signature);
}

public byte[] generator() {
BigInteger exp = new BigInteger(“11″, 16);
SecureRandom srand = new SecureRandom();
RSAKeyGenerationParameters params = new RSAKeyGenerationParameters(exp, srand, 1024, 80);
RSAKeyPairGenerator rsaKeyPairGen = new RSAKeyPairGenerator();
rsaKeyPairGen.init(params);
AsymmetricCipherKeyPair keyPair = rsaKeyPairGen.generateKeyPair();

// tampung hasil generate
RSAPrivateCrtKeyParameters rsaPrivateKey = (RSAPrivateCrtKeyParameters) keyPair.getPrivate();

// private key
byte[] modulo = rsaPrivateKey.getModulus().toByteArray();
byte[] pubExp = rsaPrivateKey.getPublicExponent().toByteArray();
byte[] privExp = rsaPrivateKey.getExponent().toByteArray();
byte[] p = rsaPrivateKey.getP().toByteArray();
byte[] q = rsaPrivateKey.getQ().toByteArray();
byte[] dP = rsaPrivateKey.getDP().toByteArray();
byte[] dQ = rsaPrivateKey.getDQ().toByteArray();
byte[] qInv = rsaPrivateKey.getQInv().toByteArray();

ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
try {
dos.writeInt(modulo.length);
dos.writeInt(pubExp.length);
dos.writeInt(privExp.length);
dos.writeInt(p.length);
dos.writeInt(q.length);
dos.writeInt(dP.length);
dos.writeInt(dQ.length);
dos.writeInt(qInv.length);

baos.write(modulo, 0, modulo.length);
baos.write(pubExp, 0, pubExp.length);
baos.write(privExp, 0, privExp.length);
baos.write(p, 0, p.length);
baos.write(q, 0, q.length);
baos.write(dP, 0, dP.length);
baos.write(dQ, 0, dQ.length);
baos.write(qInv, 0, qInv.length);

dos.close();
baos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return baos.toByteArray();
}
}

Kalo ngak ada error, output yang dihasilkan akan seperti ini:

generator on
enkripsi berjalan…
input encrypt length: 20
cipher: †³~²÷çvÂù[õ?†ÍÐ? (karakter aneh yang ngak bisa dipaste ke WP….)

dekripsi berjalan…
input decrypt length: 128
recovery: makhluk paling seksi

Karena platform yang dipake adalah J2ME, maka jangan heran kalo proses pembangkitan kuncinya makan waktu lama. Dengan begitu tidak direkomendasikan melakukan pembangkitan di ponsel…

Dalam source code saya sertakan method untuk signature dan verifikasi. Mungkin temen-temen pembaca penasaran seperti apa bentuknya signature dan verifikasi itu sih… ya silahkan dicoba saja, ngak sulit koq.

Pagi-pagi datang ke kantor mau mafia war dulu ahh… eh ternyata pas mau login, di block Facebooknya… ohh tidakk.

Dulu juga pernah banyak pengeblokan, tapi itu dulu karena koneksi dikantor Cuma 2 MB dibagi berjamaah. Sedangkan kondisi sekarang, koneksi kantor sudah pindah provider dengan kapasitas 12 MB tapi kenapa facebook diblok juga ya? Emang makan bandwidth terlalu besar ya?

Atau takut karyawannya jadi ngak kerja??? Jadi sedih… (ngak sedih juga sih, biar dramatis aja)

mozilla

Seperti biasa, saya coba bertanya sama mbah gugel. Setelah mencerna cukup lama jawaban yang agak berkelat-kelit, saya putuskan untuk mencoba solusi add-on proksinya firefox… yupe FoxyProxy. Buat yang belum punya FoxyProxy bisa tanya mbah gugel dengan keyword foxy proxy, atau bisa download di sini.

foxyproxy

Cara pakenya gimana?

Cukup ikutin tutorial dari link ini aja. Setidaknya cukup jelas bagi saya… audio visual koq.

tutorFoxy

Salah satu isi tutorialnya adalah cari list proxy server. Jadi saya tinggal cari proxy server yang dukung facebook aja deh.. Dan saya lebih refer dari link ini saja karena sudah terbukti. Hehe…

Proxylist

Setelah itu saya coba buka lagi Facebook-nya, dan ternyata…

facebookbisa

Kalo diperhatikan, di pojok kanan bawah akan ada icon FoxyProxy beserta proxy server yang sedang dipakai. Tapi jangan senang dulu, perlu diketahui ngak semua IP proxy yang ada di list proxy server bisa digunakan untuk login https.  Jadi… selamat berburu deh.

Suatu kali pernah saya mengalami kesulitan ketika ingin menggunakan library Bouncy Castle untuk membuat aplikasi sekuriti (secure xxx, secure qqq, secure zzz, dst). Library Bouncy Castle ini dirilis oleh Legionare of Bouncy Castle yang menyediakan library untuk lingkungan pemrograman java, baik itu J2SE maupun J2ME. Mungkin pembaca yang lain juga pernah merasakan kesulitan yang sama. Buat yang belum punya bisa dunlod free dengan lisensi GPL disini.

Aplikasi yang saya buat menggunakan bahasa java pada lingkungan J2ME. Ceritanya aplikasi tersebut akan diimplementasikan pada ponsel yang sudah mendukung Java MIDP dan CLDC.

MIDP tuh apa ya?

Mungkin ada temen-temen pembaca yang belum tau. Kalo mau tahu jawabannya, coba deh tanya aja sama mbah Google. :-D Dengan senang hati mbah Google akan kasih jawabannya, bahkan dapet tambahan bonus jawaban tentang CLDC.

Jadi buat aplikasi apa?

Oh iya, aplikasinya sih bebas… bisa SMS, Email, MMS, Chat, Blutooth application, atau apa saja tergantung kebutuhan dan kemampuan. Cuma intinya adalah bagaimana data yang di transmisi terlindung alias ngak kebaca sama orang lain yang ngak berhak.

Apa pentingnya sih ngacak-ngacak data kaya gitu?

Kalo ditanya begitu ya… jawabnya simple aja sih. Apa pentingnya sih yang kita kirimin? Kalo temen-temen pembaca merasa cuma orang biasa aja, mungkin emang ngak penting-penting amat. Tapi kalo temen-temen pembaca ada yang berprofesi sebagai koruptor, playboy, gembong narkoba, mucikari, gigolo atau produser film porno, kayanya itu bisa jadi penting deh. (mohon mangap kalo yang dicontohkan koq profesi ancur..piss).

Kali ini saya coba gunakan algoritma enkripsi IDEA, kenapa? Biar mudah aja, karena memang saya sudah implementasi algoritma tersebut dan tidak ada kendala. Algoritma lain bisa saja dan pakenya pun sama mudahnya dengan IDEA.

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.IDEAEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;

/**
* @author Lenovo
*/
public class IDEAMidlet extends MIDlet {
public void startApp() {
byte[] plainbyte = “nilai plain”.getBytes();
byte[] realKey = “nilai key”.getBytes();

try {
// Enkripsi
BufferedBlockCipher cipherEngine = new PaddedBufferedBlockCipher(new CBCBlockCipher(new IDEAEngine()));
cipherEngine.init(true, new KeyParameter(realKey));
byte[] cipherbyte = new byte[cipherEngine.getOutputSize(plainbyte.length)];
int cipherteksLength = cipherEngine.processBytes(plainbyte, 0, plainbyte.length, cipherbyte, 0);
cipherEngine.doFinal(cipherbyte, cipherteksLength);
System.out.println(“Ciphernya: ” + new String(cipherbyte));

// Dekripsi
cipherEngine.init(false, new KeyParameter(realKey));
byte[] recovery = new byte[cipherEngine.getOutputSize(cipherbyte.length)];
int plainteksLength = cipherEngine.processBytes(cipherbyte, 0, cipherbyte.length, recovery, 0);
cipherEngine.doFinal(recovery, plainteksLength);
System.out.println(“Recoverynya: ” + new String(recovery).trim());

} catch (DataLengthException ex) {
ex.printStackTrace();
} catch (IllegalStateException ex) {
ex.printStackTrace();
} catch (InvalidCipherTextException ex) {
ex.printStackTrace();
}
}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}
}

Kalo tidak ada error dan kawan-kawannya, maka output yang dihasilkan akan seperti berikut:

Ciphernya: œY:(ÑðøÙ?¨Ë}ÐÒ?£
Recoverynya: nilai plain

Mudah khan, penasaran mau coba algoritma yang lain..? Silahkan, selamat belajar.

Suatu ketika saya membuka halaman Detik.com tertanggal 16 April 2008. Diberitakan bahwa pakar keamanan komputer Budi Rahardjo mengatakan:

“Biasanya yang penting webnya jalan dulu, baru kemudian memikirkan masalah sekuriti lalu yang ketiga performa,” ujarnya kepada detikINET yang dihubungi via telepon, Rabu (16/4/2008).

Peryataan Pak Budi ini terkait dengan pertanyaan banyaknya situs-situs pemerintah yang di deface. Bahkan saking banyaknya, deface-mendeface situs sudah seperti jamur diantara tumpukan kayu lapuk. Tapi bukan ini yang saya soroti, karena memang saya tidak pandai dalam hal deface-mendeface. Tetapi yang saya soroti adalah masalah pernyataannya bahwa: Sekuriti nomor dua.

Sebelumnya saya pernah mengirim sebuah tulisan dalam sebuah lomba karya tulis ilmiah (meskipun tidak tembus final..:-D). Disitu saya sempat mengatakan bahwa “Security is number two”. Bukan ingin ikut-ikut Pak Budi, tapi memang hal ini sempat saya amati dan saya tanyakan ke beberapa user aplikasi sekuriti. Bahkan dalam suatu kunjungan ke UGM, pihak kampus sempat mengatakan bahwa penggunaan portal di kampus tersebut juga tidak menomor satukan sekuriti.

Untuk saya yang bekerja di lingkungan instansi yang “katanya” mengurusi masalah sekuriti nasional, hal ini tidaklah terlalu mengejutkan. Bahkan sempat saya merasa setuju akan hal tersebut. Karena memang kebanyakan aplikasi sekuriti kurang bisa mengadopsi keinginan user dalam hal kemudahan penggunaan. Selama ini yang tertanam di benak banyak pengguna sekuriti adalah, sekuriti sama dengan keruwetan… Semakin secure suatu sistem atau aplikasi, maka semakin rumit prosedurnya dan semakin sulit digunakan. Terutama oleh orang-orang awam yang tidak mengerti dan tidak mau tahu masalah sekuriti (red: tidak mau repot). Belum lagi masalah ketidak-nyamanan yang timbul.

Contoh kasus begini: Misalkan sebuah ponsel memiliki fitur secure call. Yang harus dilakukan oleh user adalah mencari kontak yang akan dihubungi, kemudian tekan call. Sebenarnya proses ini adalah proses penggunaan yang sama dengan penggunaan ponsel seperti biasanya. Namun setelah ponsel yang dihubungi merespon, maka yang dilakukan user selanjutnya adalah menunggu (yang tentunya tidak sama dengan dengan ponsel biasanya). Karena dalam komunikasi secure biasanya harus ada sinkronisasi kunci enkripsi, verifikasi identitas user dan enkripsi. Kalau hal itu dilakukan dalam layer aplikasi, tentu delay timenya akan sangat lama, mungkin sekitar 9-15 detik (perkiraan: dengan asumsi kunci yang digunakan sekitar 1024 bit). Belum lagi komunikasinya yang juga pasti akan delay karena juga ada proses enkripsinya (perkiraan: dengan bit yang lebih kecil sekitar 128 bit). Padahal kebanyakan manusia (baca: pejabat) itu paling benci dengan yang namanya menunggu (banyak juga yang lebih suka menggunakan jalan pintas…). Kalau proses diatas dilakukan pada layer fisikal, delaynya mungkin bisa berkurang setengahnya.

Pandangan saya mungkin agak berbeda dengan Pak Budi, kalau Pak Budi melihat dalam konteks sekuriti sebuah situs, saya melihat dalam konteks kemudahan dalam sekuriti. Tapi mungkin kami sepakat dalam satu hal: Sekuriti is number two. At least untuk saat ini… Mungkin yang lain punya pendapat yang berbeda??