굳이 안드로이드에 국한 되는건 아니고 JAVA쪽에 더 가까운데
메모&금전 캘린더를 쓰는 어느님께서 비밀번호를 설정할 수 있게 해 주세요 라고 해서 하다보니 여기까지 왔다.
내부 파일에 간단히 비밀번호만 저장하면 되기는 한데 왠지 비밀번호를 암호화 해서 저장하고 싶은 생각이 들었다.
처음에는 자체제작 암호화 프로그램을 만들었는데... 키값을 지정해서 byte 계산해서 지지고 볶고..
근데 이게 문제가 있었던 것이다...
프리퍼런스나 내부파일을 만들든 string으로 저장을 해야 하는데
byte -> string -> byte를 하면 개똥이 된다는 것이다.
로그를 찍어 보면 육안으로는 동일하게 보이지만
실제로 byte연산이 들어가면 제대로 안 풀린다는게 확인이 된다. 제대로가 아니라 아예 안 된다.
그래서 열심히 구글구글구구글 하다 보니 삽질하고 있었구나... 라는걸 깨닭았다.
저질스럽게 키값 하나 찝어서 byte 연산할 필요가 없이 자바에서 제공해 주는 암호화 모듈을 쓰면 되는 것을....
보안에 관심이 없으니 이럴 법도 하긴 한데 암튼 이번에 재밌는 걸 알게 되어서 포스팅~
암호화 프로세스가 포함이 되긴 했지만 핵심은 암복호화가 아니라
암호화된 byte값을 string으로 저장을 하고 string을 불러와서 다시 byte로 만든 다음에 복호화를 하는게 핵심이다.
근데 아이큐가 딸려서 그런지... 소스를 봐도 핵심부분은 몇줄 되지도 않는데 이해가 잘 안 된다.. 슬픈일이다 -_-;;
안드로이드 스니팻스에서 줏어와서 주석 좀 달고 내가 쓸 꺼로 각색했음.
이것 외에도 몇가지 있는데 얘들은 간단한거 보다는 뭔가 심층적인걸 좋아 하는거 같음 ㅇ.ㅇa
원문 출처:
http://www.androidsnippets.com/encrypt-decrypt-between-android-and-php
package com.kei.simplesecure;
import java.security.InvalidKeyException;
import java.security.Key;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class SimpleSecure extends Activity {
EditText ev_input;;
TextView tv_incr;
TextView tv_decr;
private static String algorithm = "DESede";
private static Key key = null;
private static Cipher cipher = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ev_input = (EditText)findViewById(R.id.et_input);
tv_incr = (TextView)findViewById(R.id.tv_incr);
tv_decr = (TextView)findViewById(R.id.tv_decr);
findViewById(R.id.btn_trans).setOnClickListener(mClickListener);
String enc_val = ev_input.getText().toString();
String getEnc = doEnc(enc_val); // 암호화
String getDec = doDec(getEnc); // 복호화
tv_incr.setText(getEnc);
tv_decr.setText(getDec);
}
private static void setUp() throws Exception {
key = KeyGenerator.getInstance(algorithm).generateKey(); // 키 값 생성
cipher = Cipher.getInstance(algorithm);
}
// 암호화 호출
private String doEnc(String enc_val){
try {
setUp();
} catch (Exception e) {
e.printStackTrace();
}
byte[] encryptionBytes = null;
String input = enc_val;
Log.i("Entered: ", input);
try {
encryptionBytes = encrypt(input);
// 로그를 찍어 볼때는 new string 해도 상관 없다.
Log.i("encryptionBytes: ", new String(encryptionBytes));
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
// byte를 new string으로 저장을 하면 다시 byte로 변환 할때 빙구 됨. -ㅅ-
// 그래서 Hex String으로 변환해서 저장 해야 함.
return bytesToHex(encryptionBytes);
}
// 복호화 호출
private String doDec(String strEnc){
// Hex String으로 저장이 되었으므로 다시 byte로 변환을 한다.
byte[] strEncToByte = hexToBytes(strEnc);
String Recovered = "";
try {
Log.i("Recovered(strEncToByte): ", decrypt(strEncToByte));
Recovered = decrypt(strEncToByte);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return Recovered;
}
// 암호화
private static byte[] encrypt(String input) throws InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] inputBytes = input.getBytes();
return cipher.doFinal(inputBytes);
}
// 복호화
private static String decrypt(byte[] encryptionBytes) throws InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException {
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] recoveredBytes = cipher.doFinal(encryptionBytes);
String recovered = new String(recoveredBytes);
return recovered;
}
// byte -> hex string
public static String bytesToHex(byte[] data)
{
if (data==null) {
return null;
}
int len = data.length;
String str = "";
// 0x는 16진수를 나타낸다.
// 0xff는 10진수로 치면 255
// 1111 1111 => 128 + 64 + 32 +16 + 8 + 4 + 2 + 1 = 255
for (int i=0; i<len; i++) {
if ((data[i]&0xFF)<16) { // 2자리 포맷 맞춰주기
str = str + "0" + Integer.toHexString(data[i]&0xFF);
} else {
str = str + Integer.toHexString(data[i]&0xFF);
}
}
return str;
}
// hex string -> byte
public static byte[] hexToBytes(String str) {
if (str==null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i=0; i<len; i++) {
// 16진수 이므로 숫자 변환시 radix를 명시 한다.
buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
}
return buffer;
}
}
// 변신 버튼
Button.OnClickListener mClickListener = new Button.OnClickListener() {
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_trans:
String enc_val = ev_input.getText().toString();
String getEnc = doEnc(enc_val);
String getDec = doDec(getEnc);
tv_incr.setText(getEnc);
tv_decr.setText(getDec);
break;
}
}
};
}
고대로 퍼가면 저주 할 꺼임.....-_-+
댓글