안드로이드 앱을 만들어 배포하면 일단 내부 구조나 저장된 값들은 털릴수 있다는걸 알고 시작해야 함. 그래서 요즘은 신경 좀 쓰는 개발자라면 내부 저장되는 값들중에 중요값은 암호화 해서 저장함. 근데 그 키를 또 어디에 저장하는가 도 문제가 되는데 안드로이드에서는 Android Keystrore라고 기기 내부에 키를 안전하게 저장할 수 있는 공간이 있음 여기에 저장하는것을 테스트 해보고 간단하게 정리해서 올림.
var secretKey : SecretKey? = null var alias = "linsoo.pe.kr" var ks : KeyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
secretKey는 Keystore 내부에 생성된 키를 저장할 변수이고 alias는 키스토어에서 키를 생성하거나 불러올때 사용되는 별칭임.
if (ks.containsAlias(alias)) { //키가 존재할경우 val secretKeyEntry = ks.getEntry(alias, null) as KeyStore.SecretKeyEntry secretKey = secretKeyEntry.secretKey } else{ //키가 없을경우 val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") val parameterSpec = KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT ).run { setBlockModes(KeyProperties.BLOCK_MODE_CBC) setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) setDigests(KeyProperties.DIGEST_SHA256) setUserAuthenticationRequired(false) build() } keyGenerator.init(parameterSpec) secretKey = keyGenerator.generateKey() }
키가 존재할경우엔 alias를 사용해서 해당 키 값을 읽어오면 되고 키가 없을경우엔 키를 생성해서 내부에 저장한다.
이전에 “Kotlin에서 AES 사용하기” 글에서 썼듯이 AES 암호화 옵션값을 여기서 지정할 수 있으니 기기 호환성 생각해서 적당한 암호화를 선택하면 됨.
var iv = ByteArray(16) var text = "우리나라 만세" //암호화 하는 부분 val cipher_enc = Cipher.getInstance("AES/CBC/PKCS7Padding") cipher_enc.init(Cipher.ENCRYPT_MODE, secretKey) iv = cipher_enc.iv val byteEncryptedText = cipher_enc.doFinal(text.toByteArray()) //복호화 하는 부분 val cipher_dec = Cipher.getInstance("AES/CBC/PKCS7Padding") cipher_dec.init(Cipher.DECRYPT_MODE, secretKey, IvParameterSpec(iv)) val byteDecryptedText = cipher_dec.doFinal(byteEncryptedText) Log.d("linsoo","원본 : "+text) Log.d("linsoo", "암호화 : "+ String(Base64.encode(byteEncryptedText, Base64.DEFAULT))) Log.d("linsoo", "복호화 : "+ String(byteDecryptedText))
키 생성이 완료되면 기존에 AES 사용하듯이 암호화와 복호화를 사용하면 된다.
기존 AES 암호화 복호화와 한가지 다른점이라면 암호화 할때 IV(초기화 벡터) 값을 임의로 지정할수 없고 랜덤하게 자동 생성되는것을 써야 한다.
cipher_enc.init(Cipher.ENCRYPT_MODE, secretKey, IvParameterSpec(iv))
만약 위 코드 처럼 인코딩 할때 IV를 집어 넣으면 아래와 같은 Caller-provided IV not permitted 에러 메세지를 보게 된다.
답글 남기기