-
[안드로이드 JAVA] 문자열을 SHA-256로 암호화하기 (AndroidKeyStore 이용)Programming/Android 2021. 2. 14. 22:20
[Android] SharedPreferences 암호화하기 (androidx.security 이용)
이전 글에서는 사용자 데이터를 간단하게 EncryptedSharedPreferences 를 이용하여 암호화하여 저장하였다.
이 방식은 AES256 알고리즘이라 양방향 암호화를 통하여 사용자 데이터를 관리할 수 있다는 장점이 있으나,
비밀번호와 같은 경우에는 개인정보보호법에 따라 무조건 일방향 암호화를 하도록 되어 있어 적용할 수 없다.
안드로이드에서는 일방향 암호화 클래스로 MessageDigest 를 가지고 있다.
사용법이 어렵지 않아 간단하게 구현할 수 있다.
String data = "value"; MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(data.getBytes("UTF-8")); byte[] bytes = md.digest(); String hash = String.format("%64x", new BigInteger(1, bytes)); >> hash : cd42404d52ad55ccfa9aca4adc828aa5800ad9d385a0671fbcbf724118320619
value 라는 문자열을 받아서 64글자의 해시값으로 바꾸어 준다.
value 라는 글자가 누구도 알아볼 수 없을 것 같은 문자들로 바뀌게 된 것이다.
위에서 "%64x" 는 64글자의 16진수(x)를 의미한다.
그러나,
이 방법은 매우 위험한 방법이다.
주어진 문자열을 단순하게 해시값으로 변경하는 방법이기 때문에,
모든 안드로이드 기기에서 항상 같은 문자열을 같은 해시값으로 바꾸어 준다.
해커들은 그동안 이 해시값을 모아서 Rainbow Table 이란 것을 만들어 놓았다.
인터넷에서 SHA-256 Rainbow Table 을 찾아서 위의 값을 입력하여보면
즉시, 원문인 value로 변경되는 것을 확인할 수 있다.
문자열 암호화에 MessageDigest를 사용하는 것은 추천하지 않는다.
문자열을 안전하게 일방향 암호화하는 방법으로 추천하는 것은
문자열을 특별한 암호화키를 이용하여 변환하는 것이다.
안드로이드에서는 안드로이드OS 영역에서 관리하는 AndroidKeyStore 가 있다.앱 영역과 분리된 공간에 관리되기 때문에 이 키를 추출하거나 가공/분석/사용하는 것은 불가능에 가깝다.여기에 특별한 암호화키를 만들어두면 문자열 암호화를 할 때마다 쉽게 적용할 수 있다.
우선, KeyPairGenerator 클래스로 암호화키를 하나 만든다.
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); kpg.initialize(new KeyGenParameterSpec.Builder("keyname", KeyProperties.PURPOSE_SIGN).setDigests(KeyProperties.DIGEST_SHA256).build()); kpg.generateKeyPair();
키 알고리즘으로는 ECDSA 를 사용하였고, keyname이란 alias로 저장된다.
용도에 따라 keyname을 다르게 지정하면 여러개의 키를 만들 수 있다.
이렇게 만들어진 암호화키는 KeyStore 클래스로 불러와 사용할 수 있다.
KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); PrivateKey privateKey = (PrivateKey) ks.getKey("keyname", null);
불러오고자 하는 암호화키는 keyname으로 지정하면 된다.
이제 이 암호화키를 사용하여 문자열을 SHA-256으로 암호화한다.
ECDSA 알고리즘은 전자서명용이므로 Signature 클래스를 이용하여 암호화한다.
String data = "value" Signature esign = Signature.getInstance("SHA256withECDSA"); esign.initSign(privateKey); esign.update(data.getBytes("UTF-8")); byte[] bytes = esign.sign(); String hash = String.format("%64x", new BigInteger(1, bytes)); >> hash : 3045022071894bfba27a26333e5a4952f0c3d244bbce58b0b597524b49bc8847a056d7cd022100e30c3f4504b178a8ba45a762c1992c64eb9c31f1080f2b6d957cef75778844b8
Signature 알고리즘으로는 SHA-256 with ECDSA 를 사용하였고, initSign에서 암호화키를 적용하였다.
암호화키를 이용하여 value 라는 문자열을 해시값으로 변경하였고,
이 암호화키는 안드로이드 기기마다 다르게 생성되기 때문에 같은 문자열이라고 해도 해시값은 모두 다르게 생성된다.
이렇게 변경된 해시값은 SHA-256 Rainbow Table에서는 절대 찾을 수 없다.
AndroidKeyStore에는 RSA, AES1, ECDSA, HMAC-SHA256, DES 이렇게 5가지 알고리즘으로 키를 생성할 수 있다.
용도에 맞게 암호화키를 생성하여 활용한다면
비밀번호와 같이 중요한 정보는 보다 안전하게 관리할 수 있을 것이다.
'Programming > Android' 카테고리의 다른 글
[안드로이드 JAVA] SharedPreferences 암호화하기 (androidx.security 이용) (3) 2021.02.13 [안드로이드 JAVA] String, int, float 등 기본형 상호변환하기 (0) 2012.10.18 [안드로이드 JAVA] 세 수를 비교해서 순서대로 출력하기 (0) 2012.10.18 [안드로이드 JAVA] 두 수를 비교해서 순서대로 출력하기 (0) 2012.10.18