• Tidak ada hasil yang ditemukan

BAB 5: KESIMPULAN DAN SARAN

5.2. Saran

Adapun saran yang dapat diberikan penulis untuk pengembangan dan penelitian lebih lanjut adalah:

1. Performa algoritma kriptografi Advanced Encryption Standard (Rijndael) yang berjalan di platform Android masih dikategorikan lambat. Diharapkan kepada pihak pengembang mempelajari dokumentasi Android bagaimana cara meningkatkan performa aplikasi menjadi lebih baik.

2. Jumlah karakter pada naskah acak atau kunci publik terlalu panjang, sehingga harus dikirim melalui e-mail. Pada pengembangan selanjutnya, aplikasi ini diharapkan mampu meminimalkan jumlah karakter, sehingga dapat dikirim melalui SMS. 3. Setiap akan melakukan pengiriman, penerima harus membuat parameter publik

(persamaan kurva eliptik ∈ � dan titik acak ∈ � ) lalu mengirimkannya kepada pengirim. Maka pada pengembangan selanjutnya parameter publik tidak lagi dibuat setiap kali proses pengiriman, tetapi dipublikasikan melalui website.

4. Proses pengiriman naskah acak masih menunggu balasan pembuatan kunci publik dari penerima, yang seharusnya pengirim dapat mengirimkan pesannya langsung kepada penerima. Maka pada pengembangan selanjutnya, aplikasi ini tidak lagi melakukan proses pengiriman pesan tiga arah, yaitu pengirim mengirim permintaan kunci publik kepada penerima, kemudian penerima mengirim kunci publik yang diminta kepada pengirim, dan akhirnya pengirim dapat mengirimkan pesan acaknya kepada penerima. Tetapi, aplikasi mampu mengirimkan pesannya langsung kepada penerima (searah), di mana proses pengiriman permintaan dan pembuatan kunci publik dilakukan di belakang layar (do in background).

DAFTAR PUSTAKA

Cohen, H. & Frey, G. 2006. Elliptic and HyperElliptic Curve Cryptography. Series Editor Kenneth H. Rosen. Taylor & Francis Group: Boca Raton.

Daemen, J. & Rijmen, V. 2002. The Design of Rijndael: AES (Advanced Encryption Standard). Springer-Verlag: New York.

England, M. 2006. Elliptic curve cryptography. Skripsi. Heriot-Watt University. Gallier, J. 2014. Notes on Public Key Cryptography and Primality Testing Part 1:

Randomized algorithms Miller-Rabin and Solovay-Strassen tests. University of Pennsylvania: Philadelphia.

Hankerson, D., Menezes, A. & Vanstone, S. 2004. Guide to Elliptic Curve Cryptography. Springer-Verlag: New York.

Hoffstein, J., Pipher, J. & Silverman, J.H. 2008. An Introduction to Mathematical Cryptography. Springer: New York.

Husemoller, D. 2004. Elliptic Curves. 2nd Edition. Springer: New York. Jackson, W. 2013. Learn Android App Development. Apress: California.

Junior, W.D.B. 2008. Applications of Frobenius expansions in elliptic curve cryptography. Thesis. University of London.

Kromodimoeljo, S. 2010. Teori dan Aplikasi Kriptografi. SPK IT Consulting: Jakarta. Nurhasanah, R. 2010. Peningkatan keamanan data menggunakan algoritma Rijndael

pada audio steganografi berbasis MP3. Skripsi. Universitas Sumatera Utara. Paar, C., Pelzl, J. & Preneel, B. 2010. Understanding Cryptography. Springer: Germany. Purnama, D. 2011. Sistem keamanan data dengan algoritma kriptografi Rijndael dan

algoritma steganografi LSB. Skeripsi. Universitas Sumatera Utara.

Putra, E. 2013. Implementasi kriptografi kurva eliptik dengan algoritma ElGamal dan metode pembangkitan bilangan prima Rabin-Miller untuk pengamanan file teks. Skripsi. Universitas Sumatera Utara.

Sadikin, R. 2012. Komputer untuk Keamanan Jaringan. Andi Publisher: Yogyakarta. Smart, N. 2004. Cryptography: An introduction. 3rd Edition. University of Bristol:

SOURCE CODES

1) com.murez.crypto.Rijndael.java private final short[][] S_BOX = {

{ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76 },

{ 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0 },

{ 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15 },

{ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75 },

{ 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84 },

{ 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF },

{ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8 },

{ 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2 },

{ 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73 },

{ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB },

{ 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79 },

{ 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08 },

{ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A },

{ 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E },

{ 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF },

{ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 }

}, S_BOX_INVERSE = {

{ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB },

{ 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB },

{ 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E },

{ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25 },

{ 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92 },

{ 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84 },

{ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06 },

{ 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B },

{ 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73 },

{ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E },

{ 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B },

{ 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4 },

{ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F },

{ 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF },

{ 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61 },

{ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D }

};

private int[][] block, expandedKey = new int[120][4]; private int[] C;

private char[] defaultId = { 1 }; private int Nk, Nb = 8, Nr = 14, i, j; private String hex;

public Rijndael(String key) {

if(key == null || key.equals(""))

throw new UnsupportedOperationException("Define your key with spesific characters");

int[][][] blocks = Util.fillBlocks(Util.expand(key, null).toCharArray(), 8).getBlocks();

if(blocks.length > 1)

throw new UnsupportedOperationException("Key's too large"); Nk = blocks[0].length;

for(int i = 0, j; i < Nk; i++)

for(j = 0; j < 4; expandedKey[i][j] = blocks[0][i][j], j++); keySchedule();

}

public String encrypt(String message) {

Blocks b = Util.fillBlocks(Util.expand(message, defaultId).toCharArray(), Nb);

int[][][] blocks = b.getBlocks(); int i = 0, n;

n = blocks.length – 1;

C = Nb < 8? new int[] { 0, 1, 2, 3 } : new int[] { 0, 1, 3, 4 }; for(message = null; i < n; blocks[i] = encrypt(blocks[i++])); Nb = blocks[i].length;

if(b.getLeft() > 0)

blocks[i][Nb - 1][3] = Util.TAIL_MAP[b.getLeft() - 1]; blocks[i] = encrypt(blocks[i]);

return Util.unBlocked(blocks); }

public String decrypt(String cipher) {

int[][][] blocks = Util.fillBlocks(cipher.toCharArray(), Nb).getBlocks();

int i = 0, j, n; n = blocks.length – 1;

C = Nb < 8? new int[] { 0, 1, 2, 3 } : new int[] { 0, 1, 3, 4 }; for(cipher = null; i < n; blocks[i] = decrypt(blocks[i++])); boolean found = false;

Nb = blocks[i].length; blocks[i] = decrypt(blocks[i]); n = Util.TAIL_MAP.length; for(i = blocks[i][Nb - 1][3], j = 0; j < n; j++) if(i == Util.TAIL_MAP[j]) { found = true; j++; break; }

String message = Util.merge(new String(Util.unBlocked(blocks)), defaultId);

return found? message.substring(0, message.length() - j) : message; }

public final int[][] encrypt(int[][] message) { addRoundKey(message, 0);

for(int i = 1; i < Nr; i++)

message = addRoundKey(mixColumns(shiftRows(subBytes(message))), i); return addRoundKey(shiftRows(subBytes(message)), Nr);

}

public final int[][] decrypt(int[][] cipher) {

cipher = subBytesInverse(shiftRowsInverse(addRoundKey(cipher, Nr))); for(int i = Nr - 1; i > 0; i--) { addRoundKey(cipher, i); mixColumnsInverse(cipher); cipher = subBytesInverse(shiftRowsInverse(cipher)); } return addRoundKey(cipher, 0); }

private final int[][] mixColumns(int[][] state) { for(block = new int[Nb][4], i = 0; i < Nb; i++)

for(j = 0; j < 4; j++) {

block[i][j] = Math.galoisFieldsMultiply(state[i][j], 2) ^ Math.galoisFieldsMultiply(state[i][(j + 1) % 4], 3) ^ state[i][(j + 2) % 4] ^ state[i][(j + 3) % 4];

return block; }

private final int[][] mixColumnsInverse(int[][] state) { for(block = new int[Nb][4], i = 0; i < Nb; i++)

for(j = 0; j < 4; j++) { block[i][j] = Math.galoisFieldsMultiply(state[i][j], 14) ^ Math.galoisFieldsMultiply(state[i][(j + 1) % 4], 11) ^ Math.galoisFieldsMultiply(state[i][(j + 2) % 4], 13) ^ Math.galoisFieldsMultiply(state[i][(j + 3) % 4], 9) } return block; }

private final int[][] shiftRows(int[][] state) { for(block = new int[Nb][4], i = 0; i < Nb; i++)

for(j = 0; j < 4; block[i][j] = state[(i + C[j]) % Nb][j], j++); return block;

}

private final int[][] shiftRowsInverse(int[][] state) { for(block = new int[Nb][4], i = 0; i < Nb; i++)

for(j = 0; j < 4; block[(i + C[j]) % Nb][j] = state[i][j], j++); return block;

}

private final int[][] subBytes(int[][] state) { for(i = 0; i < Nb; i++) for(j = 0; j < 4; j++) { if((hex = Integer.toHexString(state[i][j])).length() < 2) hex = '0' + hex; state[i][j] = S_BOX[Util.parseInt(hex.charAt(0))] [Util.parseInt(hex.charAt(1))]; } return state; }

private final int[][] subBytesInverse(int[][] state) { for(i = 0; i < Nb; i++) for(j = 0; j < 4; j++) { if((hex = Integer.toHexString(state[i][j])).length() < 2) hex = '0' + hex; state[i][j] = S_BOX_INVERSE[Util.parseInt(hex.charAt(0))] [Util.parseInt(hex.charAt(1))]; return state; }

private final int[][] addRoundKey(int[][] state, int start) { for(i = 0; i < Nb; i++)

for(j = 0; j < 4; j++)

return state; }

private final void keySchedule() {

final int[] ROUND_COEFFICIENT = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5 };

int n = Nk * (Nk == 4? 30 : Nk == 6? 20 : 15); for(i = Nk; i < n; i++) {

if(i % Nk == 0) {

expandedKey[i][0] = subBytes(expandedKey[i - 1][1], false) ^ ROUND_COEFFICIENT[(i / Nk) - 1];

for(j = 1; j < 4; j++)

expandedKey[i][j] = subBytes(expandedKey[i - 1][(j + 1) % 4], false);

}

else if(Nk == 8 && i % Nk == 4) { for(j = 0; j < 4; j++)

expandedKey[i][j] = subBytes(expandedKey[i - 1][j], false); }

else

for(j = 0; j < 4; j++)

expandedKey[i][j] = expandedKey[i - 1][j]; for(j = 0; j < 4; j++)

expandedKey[i][j] = expandedKey[i - Nk][j] ^ expandedKey[i][j]; }

}

private final int subBytes(int value, boolean inverse) { if((hex = Integer.toHexString(value)).length() < 2) hex = '0' + hex; if(inverse) return S_BOX_INVERSE[Util.parseInt(hex.charAt(0))] [Util.parseInt(hex.charAt(1))]; return S_BOX[Util.parseInt(hex.charAt(0))] [Util.parseInt(hex.charAt(1))]; } 2) com.murez.util.Math.java

private final static BigInteger TWO = BigInteger.valueOf(2);

public final static BigInteger fastPow(BigInteger coefficient, BigInteger exponent, BigInteger modulus) {

if(exponent.compareTo(BigInteger.ZERO) < 0)

exponent = modulus.subtract(exponent.abs().mod(modulus) .add(BigInteger.ONE));

BigInteger result = BigInteger.ONE;

for(; exponent.compareTo(BigInteger.ZERO) > 0; exponent = exponent .divide(TWO)) {

result = result.multiply(coefficient).mod(modulus); coefficient = coefficient.pow(2).mod(modulus);

}

return result; }

public final static Legendre squareModulo(Legendre legendre) { BigInteger a = legendre.getValue().abs();

int n=0, i = legendre.getValue().compareTo(BigInteger.ZERO) < 0? -1 : 1; if(a.compareTo(legendre.getModulus()) > 0)

a = a.mod(legendre.getModulus());

for(; a.mod(TWO).equals(BigInteger.ZERO) && a.compareTo(TWO) > 0; n++) a = a.divide(TWO);

if(n > 0) {

if(quadraticReciprocity(new Legendre(TWO, legendre.getModulus())) .equals(Legendre.MIN_ONE)) if(n % 2 == 1) i *= -1; } if(a.equals(BigInteger.ONE)) { if(BigInteger.valueOf(i).multiply(a).equals(BigInteger.ONE)) return Legendre.ONE; return Legendre.MIN_ONE; }

Legendre R = quadraticReciprocity(new Legendre(a, legendre.getModulus())); a = R.getValue().multiply(BigInteger.valueOf(i)); if(a.equals(BigInteger.ONE)) return Legendre.ONE; else if(a.equals(BigInteger.valueOf(-1))) return Legendre.MIN_ONE;

return squareModulo(new Legendre(a, R.getModulus())); }

private final static Legendre quadraticReciprocity(Legendre legendre) { BigInteger a = legendre.getValue().abs(), tmp = BigInteger.valueOf(4); if(!a.equals(TWO) && !legendre.getValue()

.equals(BigInteger.valueOf(-1))) {

if(a.mod(TWO).equals(BigInteger.ZERO) || legendre.getModulus() .mod(TWO).equals(BigInteger.ZERO))

throw new ArithmeticException("Let two integers that are odd."); } if(legendre.getValue().equals(BigInteger.valueOf(-1))) { if((tmp = legendre.getModulus().mod(tmp)).equals(BigInteger.ONE)) return Legendre.ONE; else if(tmp.equals(BigInteger.valueOf(3))) return Legendre.MIN_ONE; } if(a.equals(TWO)) { if((tmp = legendre.getModulus().mod(BigInteger.valueOf(8))) .equals(BigInteger.ONE) || tmp.equals(BigInteger.valueOf(7)))

return Legendre.ONE;

else if(tmp.equals(BigInteger.valueOf(3)) || tmp .equals(BigInteger.valueOf(5)))

return Legendre.MIN_ONE; }

if(a.mod(tmp = BigInteger.valueOf(4)).equals(BigInteger.valueOf(3)) && legendre.getModulus().mod(tmp).equals(BigInteger.valueOf(3)))

return new Legendre(legendre.getModulus().negate(), a);

if(a.mod(tmp).equals(BigInteger.ONE) || legendre.getModulus().mod(tmp) .equals(BigInteger.ONE))

return new Legendre(legendre.getModulus(), a); return null;

}

public final static int galoisFieldsMultiply(int x, int y) { int result = 0;

boolean b;

for(byte i = 0; i < 8; i++) {

result = ((y & 0x1) > 0)? result ^ x : result; b = ((x & 0x80) > 0); x = ((x << 1) & 0xFE); if(b) x = x ^ 0x1b; y = ((y >> 1) & 0x7F); } return result; } 3) com.murez.util.EllipticCurve.java private BigInteger A, B, Fp;

public EllipticCurve(BigInteger A, BigInteger B, BigInteger Fp) {

if(BigInteger.valueOf(4).multiply(A.pow(3)).add(BigInteger.valueOf(27) .multiply(B.pow(2))).mod(Fp).equals(BigInteger.ZERO))

throw new ArithmeticException("Value of A or B element of Fp is not satisfied.");

this.A = A; this.B = B; this.Fp = Fp; }

public static EllipticCurve generate(int securityLevel) { int A, B, p, min_point = 999999, max_bit;

switch(securityLevel) { case ECElGamal.LEVEL_CHEAP: max_bit = 134; break; case ECElGamal.LEVEL_LOW: max_bit = 320; break; case ECElGamal.LEVEL_NORMAL: max_bit = 448; break;

case ECElGamal.LEVEL_HIGH: max_bit = 704; break; case ECElGamal.LEVEL_TOP_SECRET: max_bit = 1280; break; case ECElGamal.LEVEL_AMAZING: max_bit = 2560; break;

default: throw new UnsupportedOperationException("Get security level from ECElGamal's static field.");

}

while((p = new java.util.Random().nextInt(max_bit)) < securityLevel); while((A = new java.util.Random().nextInt()) < min_point);

while((B = new java.util.Random().nextInt()) < min_point);

return new EllipticCurve(BigInteger.valueOf(A), BigInteger.valueOf(B), Math.getProbablePrime(p));

}

public BigInteger getA() { return A; } public BigInteger getB() { return B; } public BigInteger getField() { return Fp; } public String toString() {

return "A = " + A + ", B = " + B + ", Fp = " + Fp; }

4) com.murez.util.ECPoint.java

public static final ECPoint O = new ECPoint(); private BigInteger x, y;

private boolean isInfinity;

private ECPoint() { isInfinity = true; } public ECPoint(BigInteger x, BigInteger y) {

this.x = x; this.y = y; }

public static ECPoint getRandPoint(EllipticCurve E) { ECPoint P = ECPoint.O;

BigInteger x = BigInteger.ONE, y, p = E.getField(),

exp = p.add(BigInteger.ONE).divide(BigInteger.valueOf(4)); for(; x.compareTo(p) < 0; x = x.add(BigInteger.ONE)) {

if((y = x.pow(3).add(x.multiply(E.getA())).add(E.getB()).mod(p)) .compareTo(BigInteger.ZERO) > 0) {

if(Math.squareModulo(new Legendre(y, p)).equals(Legendre.ONE)) { P = new ECPoint(x, Math.fastPow(y, exp, p));

break; }

return P.sum(BigInteger.valueOf(new java.util.Random().nextInt()).abs(), E);

}

public ECPoint sum(ECPoint P, EllipticCurve E) { if(this.equals(O)) return P; if(P.equals(O)) return this; if(P.equals(negate(this))) return O;

BigInteger slope = null, p = E.getField(), A = E.getA(); try { if(this.equals(P)) slope = x.pow(2).multiply(BigInteger.valueOf(3)).add(A).mod(p) .multiply(y.multiply(BigInteger.valueOf(2)).modInverse(p)) .mod(p); else slope = P.getY().subtract(y).mod(p).multiply(P.getX().subtract(x) .modInverse(p)).mod(p); } catch(ArithmeticException e) { return O; } BigInteger X = slope.pow(2).subtract(x.add(P.getX())).mod(p);

return new ECPoint(X, slope.multiply(x.subtract(X)).subtract(y).mod(p)); }

public ECPoint sum(BigInteger n, EllipticCurve E) { if(n.compareTo(BigInteger.ONE) < 1)

throw new ArithmeticException("Choose n > 1"); ECPoint P = this, Q = ECPoint.O;

while(n.compareTo(BigInteger.ZERO) > 0) { if(n.mod(BigInteger.valueOf(2)).equals(BigInteger.ONE)) Q = Q.sum(P, E); P = P.sum(P, E); n = n.divide(BigInteger.valueOf(2)); } return Q; }

public ECPoint sub(ECPoint P, EllipticCurve E) {

return sum(new ECPoint(P.getX(), P.getY().negate()), E); }

public static final ECPoint negate(ECPoint P) { return new ECPoint(P.getX(), P.getY().negate()); }

public BigInteger getX() { if(isInfinity) return null; return x;

public BigInteger getY() { if(isInfinity) return null; return y;

}

public String toString() { if(this.equals(O))

return "Infinity";

else return "(" + x + ", " + y + ")"; }

5) com.murez.crypto.ECElGamal.java public static final int

LEVEL_CHEAP = 128, LEVEL_LOW = 256, LEVEL_NORMAL = 384, LEVEL_HIGH = 512, LEVEL_TOP_SECRET = 960, LEVEL_AMAZING = 2048; private EllipticCurve E; private ECPoint P;

public ECElGamal(EllipticCurve ellipticCurve, ECPoint point) { E = ellipticCurve;

P = point; }

public String encrypt(String message, ECPoint publicKey) { message += message.length() % 2 == 1? (char) 0 : ""; ECPoint[] M = new ECPoint[message.length() / 2]; for(int i = 0, j = 0; i < message.length(); j++)

M[j] = new ECPoint(BigInteger.valueOf(message.charAt(i++)), BigInteger.valueOf(message.charAt(i++)));

return new com.murez.util.Convert().toString(encrypt(M, publicKey)); }

public String decrypt(String cipher, BigInteger privateKey) {

ECPoint[] M = decrypt(new com.murez.util.Convert().toPoints(cipher), privateKey);

String message = ""; int i = 0;

for(; i < M.length; i++)

message += String.valueOf((char) M[i].getX().intValue()) + (char) M[i].getY().intValue();

return message.charAt((i = message.length()) - 1) == 0? message.substring(0, i - 1) : message;

}

private ECPoint[][] encrypt(ECPoint[] M, ECPoint Q) { ECPoint[][] C = new ECPoint[M.length][2];

for(int i = 0; i < M.length; i++) {

k = Math.abs(new java.util.Random().nextLong());

C[i] = new ECPoint[] { P.sum(BigInteger.valueOf(k), E), M[i].sum(Q.sum(BigInteger.valueOf(k), E), E) };

}

return C; }

private ECPoint[] decrypt(ECPoint[][] C, BigInteger n) { ECPoint[] M = new ECPoint[C.length];

for(int i = 0; i < C.length; i++)

M[i] = C[i][1].sub(C[i][0].sum(n, E), E); return M;

}

6) com.zain.key.CryptoService.java

public final static int REQUEST_CODE_NOTIFICATION = 2805;

private final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1"); private NotificationCompat.Builder notif;

private String _redelivery = "redelivery"; private boolean isEncryption;

public CryptoService() { super("CryptoService"); }

public int onStartCommand(Intent intent, int flags, int startId) { isEncryption = intent.getBooleanExtra(getString(R.string.

_encryption_service), false); if(flags == START_FLAG_REDELIVERY)

intent.putExtra(_redelivery, true);

super.onStartCommand(intent, flags, startId); return START_REDELIVER_INTENT;

}

protected void onHandleIntent(Intent intent) {

String publicDir = android.os.Environment.getExternalStorageDirectory() .getAbsolutePath() + "/" + getString(R.string.dir_ciphers);

File f = new File(intent.getStringExtra(getString(R.string._desc))); NotificationManager notifMgr = (NotificationManager)

getSystemService(android.content.Context.NOTIFICATION_SERVICE); notif = new NotificationCompat.Builder(this)

.setSmallIcon(R.drawable.ic_ongoing) .setContentTitle(getString(isEncryption? R.string.encrypting_file : R.string.decrypting_file)).setContentText(f.getName()) .setTicker(getString(isEncryption? R.string.encrypting_file : R.string.decrypting_file) + ": " + f.getName()).setOngoing(true) .setWhen(0); if(isEncryption)

encrypt(notifMgr, intent, f, new File(publicDir + "/" + com.zain.util.File.divide(f.getName())[0] +

else decrypt(notifMgr, intent, f, getOriginalExtension(f)); notifMgr.cancel(1);

notif = notif.setProgress(0, 0,

false).setSmallIcon(R.drawable.ic_done).setContentTitle(getString(isEn cryption? R.string.encryption_was_successful : R.string

.decryption_was_successful)).setContentInfo(null).setTicker(null) .setOngoing(false).setVibrate(new long[] { 0, 500 }) .setAutoCancel(true); notifMgr.notify(0, notif.build()); if(intent.getBooleanExtra(_redelivery, false)) { intent.putExtra(_redelivery, false); stopSelf(); } }

public void onTaskRemoved(Intent rootIntent) {

android.widget.Toast.makeText(this, isEncryption?

R.string.encryption_is_restarting : R.string.decryption_is_restarting, android.widget.Toast.LENGTH_SHORT).show();

}

private void encrypt(NotificationManager notifMgr, Intent intent, File source, File target) {

int j = 0, i = getResources().getInteger(R.integer.default_char_length); int[][][] blocks;

char[] chars = new char[i]; long size = source.length() / i;

Rijndael aes = new Rijndael(intent.getStringExtra(getString( R.string._key)));

if(!intent.getBooleanExtra(_redelivery, false)) save(source.getAbsolutePath());

try {

InputStreamReader reader = new InputStreamReader(new FileInputStream(source), DEFAULT_CHARSET);

OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(target), DEFAULT_CHARSET);

aes.setShift(new int[] { 0, 1, 3, 4 }); for(target = null; j < size; j++) {

reader.read(chars);

blocks = fillBlocks(chars, 8); for(i = 0; i < blocks.length; i++)

blocks[i] = aes.encrypt(blocks[i]); writer.write(unBlocked(blocks));

notifMgr.notify(1, notif.setProgress((int) size, j, false) .setContentInfo((int) ((Double.valueOf(j) / size) * 100) + "%").build());

}

if((size = source.length() % chars.length) > 0) {

reader.read(chars = new char[(int) (size - (size % 32))]); blocks = fillBlocks(chars, 8);

for(source = null, i = 0; i < blocks.length; i++) blocks[i] = aes.encrypt(blocks[i]);

writer.write(unBlocked(blocks)); if((size %= 32) > 0) {

i = size <= 16? 4 : size > 16 && size <= 24? 6 : 8; if(i <= 6) {

aes.setShift(new int[] { 0, 1, 2, 3 }); aes.setBlockLength(i);

}

reader.read(chars = new char[(int) size]); int[][] block = fillBlock(chars, i); if((size = (4 * i) - size) > 0)

block[i - 1][3] = (char) Rijndael.Util .TAIL_MAP[(int) (size - 1)]; writer.write(unBlocked(aes.encrypt(block))); } } reader.close(); writer.close(); } catch(IOException e) { Log.e(getString(R.string.log_io_error), e.getMessage()); } android.support.v4.app.TaskStackBuilder stackBuilder = android.support.v4.app.TaskStackBuilder.create(this); intent = new Intent(this, MainActivity.class);

intent.putExtra(getString(R.string._launch_from_notif), true); stackBuilder.addParentStack(MainActivity.class); stackBuilder.addNextIntent(intent); notif = notif.setContentIntent(stackBuilder. getPendingIntent(CryptoService.REQUEST_CODE_NOTIFICATION, android.app.PendingIntent.FLAG_UPDATE_CURRENT)); }

private void decrypt(NotificationManager notifMgr, Intent intent, File source, File target) {

int i = 2, j = 0; int[][][] blocks;

String[] tmp = com.zain.util.File.divide(target.getName()); for(; target.exists(); )

target = new File(target.getParent() + "/" + tmp[0] + " (" + i++ + ")" + tmp[1]);

tmp = new String[] { null, null }; char[] chars = new char[i =

getResources().getInteger(R.integer.default_char_length)]; long size = source.length() / i;

Rijndael aes = new Rijndael(intent.getStringExtra( getString(R.string._key)));

try {

InputStreamReader reader = new InputStreamReader(new FileInputStream(source), DEFAULT_CHARSET);

OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(target), DEFAULT_CHARSET);

aes.setShift(new int[] { 0, 1, 3, 4 }); for(target = nullj < size; j++) {

reader.read(chars);

blocks = fillBlocks(chars, 8); for(i = 0; i < blocks.length; i++)

blocks[i] = aes.decrypt(blocks[i]); writer.write(unBlocked(blocks));

notifMgr.notify(1, notif.setProgress((int) size, j, false). setContentInfo((int) ((Double.valueOf(j) / size) * 100) + "%").build());

}

if((size = source.length() % chars.length) > 0) { if((i = (int) (size % 32)) == 0)

i = 32;

reader.read(chars = new char[(int) (size - i)]);

for(source = null, blocks = fillBlocks(chars, 8), i = 0; i < blocks.length; blocks[i] = aes.decrypt(blocks[i++])); writer.write(unBlocked(blocks));

if((i = (size %= 32) == 16? 4 : size == 24? 6 : 8) <= 6) { aes.setShift(new int[] { 0, 1, 2, 3 });

aes.setBlockLength(i); }

reader.read(chars = new char[4 * i]);

int[][] block = aes.decrypt(fillBlock(chars, i)); boolean found = false;

size = block[i - 1][3];

for(i = 0; i < Rijndael.Util.TAIL_MAP.length; i++) if(size == Rijndael.Util.TAIL_MAP[i]) {

found = true; i++; break; }

tmp[0] = new String(unBlocked(block));

writer.write(found? tmp[0].substring(0, tmp[0].length() - i) : tmp[0]); } reader.close(); writer.close(); } catch(IOException e) { Log.e(getString(R.string.log_io_error), e.getMessage()); } }

private File getOriginalExtension(File zainFile) { File f = null;

String[] columns = { History.FILENAME };

TopSecretOpenHelper dbHelper = new TopSecretOpenHelper(this); android.database.Cursor c = dbHelper.getReadableDatabase()

.query(History.TABLE_NAME, columns, columns[0] + " LIKE ?", new String[] { "%" + com.zain.util.File.divide(zainFile.getName())[0] + "%" }, null, null, null);

if(c.moveToFirst())

f = new File(c.getString(c.getColumnIndex(columns[0]))); c.close(); dbHelper.close();

return f; }

private void save(String filename) {

ContentValues values = new ContentValues(); values.put(History.FILENAME, filename); values.put(History.DATE,

java.text.DateFormat.getDateTimeInstance().format(new Date())); values.put(History.STATUS, true);

TopSecretOpenHelper dbHelper = new TopSecretOpenHelper(this);

dbHelper.getWritableDatabase().insert(History.TABLE_NAME, null, values); dbHelper.close();

}

private int[][][] fillBlocks(char[] chars, int Nb) {

int[][][] blocks = new int[chars.length / (4 * Nb)][Nb][4]; for(int i = 0, j, k, n = 0; i < blocks.length; i++)

for(j = 0; j < Nb; j++)

for(k = 0; k < 4; blocks[i][j][k++] = chars[n++]); return blocks;

}

private int[][] fillBlock(char[] chars, int Nb) { int[][] block = new int[Nb][4];

for(int i = 0, j = -1; i < chars.length; i++) block[i % 4 == 0? ++j : j][i % 4] = chars[i]; return block;

}

private char[] unBlocked(int[][][] blocks) {

char[] chars = new char[blocks.length * blocks[0].length * 4]; for(int i = 0, j, k, n = 0; i < blocks.length; i++)

for(j = 0; j < blocks[i].length; j++)

for(k = 0; k < 4; chars[n++] = (char) blocks[i][j][k++]); return chars;

}

private String unBlocked(int[][] block) { String chars = new String();

for(int i = 0, j; i < block.length; i++)

for(j = 0; j < 4; chars += (char) block[i][j++]); return chars;

CURRICULUM VITAE

Data Pribadi

Nama : Muhammad Reza Nasution

Tempat, Tanggal Lahir : Galang, 3 Februari 1992 Tinggi/ Berat Badan : 170 cm/ 60 kg

Agama : Islam

Kewarganegaraan : Indonesia

Alamat Sekarang : Jl. Petumbukan No. 76 Jaharun B Dusun 1, Galang Alamat Orang Tua : Jl. Petumbukan No. 76 Jaharun B Dusun 1, Galang

No. Telepon : 082274668329

E-mail : murez.nasution@gmail.com

Riwayat Pendidikan

[ − ] : S1 Ilmu Komputer Universitas Sumatera Utara, Medan

[ − ] : SMA Negeri 1 Lubuk Pakam

[ − ] : SMP Negeri 2 Lubuk Pakam

[ − ] : SD Negeri 104283 Galang

Keahlian

Bahasa : Indonesia, Inggris

Pemrograman : Java, C#, C++, PHP

Development : Web, Desktop Apps, Android Apps

Pengalaman Organisasi

Dokumen terkait