안드로이드 내부에 여러 데이터를 저장하다 보면, 사용자가 쉽게 열어보지 못하도록 암호화해야 하는 상황이 생긴다. 그때 사용 할 수 있는 방법을 찾다가, AES 암호화를 사용하면 좋겠다는 생각이 들었다. 그래서 간단하게 class를 만들어 사용하던 도중, 안드로이드 4.2 젤리빈에서는 정상동작하지 못하고 뻗어버리는 상황에 봉착했다. 이를 해결하기 위해 이곳저곳 돌아다녀 완성한 class를 소개한다. class를 사용하기 전에 key를 우선 바꾸어주자. 실제로 사용하는 메소드는 제일 처음의 encrypt와 decrypt 뿐이다.
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
//참조한 문서 //http://stackoverflow.com/questions/13389870/android-4-2-broke-my-aes-encrypt-decrypt-code public class SimpleCrypto { private final static String HEX = "0123456789ABCDEF"; private final static int JELLY_BEAN_4_2 = 17; // 암호화에 사용할 키. 원하는 값으로 바꿔주자. private final static byte[] key = {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }; /** * AES 암호화 * @param seed 암호화에 사용할 seed * @param cleartext 암호화 할 문자열 * @return 암호화된 문자열 * @throws Exception 암호화 key 사이즈가 192bit 또는 128bit로 감소함. */ public static String encrypt(String seed, String cleartext) throws Exception { if (cleartext == null || cleartext == "") return null; byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, cleartext.getBytes()); String fromHex = toHex(result); String base64 = new String(Base64.encodeToString(fromHex.getBytes(), 0)); return base64; } /** * AES 복호화 * @param seed 복호화에 사용할 seed * @param encrypted 복호화 할 문자열 * @return 복호화한 문자열 * @throws Exception 암호화 key 사이즈가 192bit 또는 128bit로 감소함. */ public static String decrypt(String seed, String encrypted) throws Exception { if (encrypted == null || encrypted == "") return null; byte[] seedByte = seed.getBytes(); System.arraycopy(seedByte, 0, key, 0, ((seedByte.length String base64 = new String(Base64.decode(encrypted, 0)); byte[] rawKey = getRawKey(seedByte); byte[] enc = toByte(base64); byte[] result = decrypt(rawKey, enc); return new String(result); } public static byte[] encryptBytes(String seed, byte[] cleartext) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = encrypt(rawKey, cleartext); return result; } public static byte[] decryptBytes(String seed, byte[] encrypted) throws Exception { byte[] rawKey = getRawKey(seed.getBytes()); byte[] result = decrypt(rawKey, encrypted); return result; } private static byte[] getRawKey(byte[] seed) throws Exception { KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecureRandom sr = null; if (android.os.Build.VERSION.SDK_INT >= JELLY_BEAN_4_2) { sr = SecureRandom.getInstance("SHA1PRNG", "Crypto"); } else { sr = SecureRandom.getInstance("SHA1PRNG"); } sr.setSeed(seed); try { kgen.init(256, sr); // kgen.init(128, sr); } catch (Exception e) { // Log.w(LOG, "This device doesn't suppor 256bits, trying 192bits."); try { kgen.init(192, sr); } catch (Exception e1) { // Log.w(LOG, "This device doesn't suppor 192bits, trying 128bits."); kgen.init(128, sr); } } SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); return raw; } private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(clear); return encrypted; } private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception { SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] decrypted = cipher.doFinal(encrypted); return decrypted; } public static String toHex(String txt) { return toHex(txt.getBytes()); } public static String fromHex(String hex) { return new String(toByte(hex)); } public static byte[] toByte(String hexString) { int len = hexString.length()/2; byte[] result = new byte[len]; for (int i = 0; i result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue(); return result; } public static String toHex(byte[] buf) { if (buf == null) return ""; StringBuffer result = new StringBuffer(2*buf.length); for (int i = 0; i appendHex(result, buf[i]); } return result.toString(); } private static void appendHex(StringBuffer sb, byte b) { sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f)); } } |
이 소스코드의 대부분은 제가 작성한 코드가 아닌, 구글링의 결과물이며, 이를 사용해서 발생한 어떠한 일에도 저는 책임을 질 수 없습니다.