안녕하세요.
오늘은 안드로이드에서 keystore를 사용해서 안전하게 데이터를 보호하는 방법에 대해 알아보겠습니다.
1. keystore
https://developer.android.com/privacy-and-security/keystore?hl=ko
Android 키 저장소 시스템 | Security | Android Developers
Android 키 저장소 시스템 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Android 키 저장소 시스템을 사용하면 암호화 키를 컨테이너에 저장하여 기기에서 키
developer.android.com
Keystore는 안드로이드에서 제공하는 안전한 저장소입니다.
쉽게 말해, 중요한 비밀(예: 암호화 키, 인증서 등)을 스마트폰 내부의 안전한 공간에 보관해주는 금고 역할을 합니다.
만약 암호화 키를 그냥 앱 내부에 저장하면, 해커가 앱을 해킹해서 키를 빼낼 수 있습니다. 하지만 Keystore를 사용하면, 키가 외부로 노출되지 않고, 오직 Keystore만이 키를 사용해 암호화/복호화 작업을 할 수 있습니다.
키는 OS(운영체제)에서 관리하는 보안 영역에 저장되어, 일반 파일처럼 접근할 수 없습니다.
2. 암호화란?
암호화는 데이터를 다른 사람이 알아볼 수 없게 '암호문'으로 바꾸는 기술입니다.
예를 들어, 사용자의 비밀번호, 신용카드 번호 등 민감한 정보를 앱에 저장할 때 암호화를 사용합니다.
- 암호화 종류
- 대칭키 암호화: 하나의 키로 암호화와 복호화를 모두 함. (예: AES)
- 비대칭키 암호화: 공개키로 암호화, 개인키로 복호화. (예: RSA)
https://developer.android.com/privacy-and-security/cryptography?hl=ko
암호화 | App quality | Android Developers
Android의 암호화 기능을 알아보세요.
developer.android.com
3. Keystore를 사용한 AES 암호화 예제
이제 실제로 Keystore를 사용해 데이터를 암호화하고, 복호화하는 방법을 단계별로 알아보겠습니다.
Step 1: Keystore에 AES 키 생성하기
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import java.security.KeyStore
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
// Keystore에 저장할 키의 별칭(이름)
private const val KEY_ALIAS = "my_aes_key"
fun createAESKey() {
// 이미 키가 존재하면 새로 만들 필요 없음
val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
if (keyStore.containsAlias(KEY_ALIAS)) return
// 키 생성기 설정
val keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"
)
val keyGenParameterSpec = KeyGenParameterSpec.Builder(
KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM) // GCM 모드 사용
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setRandomizedEncryptionRequired(true)
.build()
keyGenerator.init(keyGenParameterSpec)
keyGenerator.generateKey() // 키 생성 및 Keystore에 저장
}
- KEY_ALIAS는 키를 찾을 때 사용할 별명입니다.
- KeyGenerator를 통해 AES 키를 생성하고, Keystore에 저장합니다.
- 이미 키가 있으면 생성을 건너뜁니다.
Step 2: 암호화 함수 만들기
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec
import android.util.Base64
// 암호화 함수
fun encryptData(plainText: String): Pair<String, String> {
// Keystore에서 키 가져오기
val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
val secretKey = keyStore.getKey(KEY_ALIAS, null) as SecretKey
// Cipher(암호화 엔진) 준비
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
// 암호화
val iv = cipher.iv // 초기화 벡터
val encryptedBytes = cipher.doFinal(plainText.toByteArray(Charsets.UTF_8))
// 결과를 Base64로 인코딩해서 반환 (문자열로 저장하기 위함)
val encryptedBase64 = Base64.encodeToString(encryptedBytes, Base64.DEFAULT)
val ivBase64 = Base64.encodeToString(iv, Base64.DEFAULT)
// 암호문과 IV를 반환 (IV는 복호화에 필요)
return Pair(encryptedBase64, ivBase64)
}
- Cipher는 암호화/복호화 엔진입니다.
- IV(초기화 벡터)는 암호화의 무작위성을 높여줍니다. 복호화 시 필요하므로 저장해야 합니다.
- 암호화된 데이터와 IV를 Base64로 인코딩하여 반환합니다.
Step 3: 복호화 함수 만들기
fun decryptData(encryptedBase64: String, ivBase64: String): String {
val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
val secretKey = keyStore.getKey(KEY_ALIAS, null) as SecretKey
// Base64로 인코딩된 암호문과 IV를 다시 바이트 배열로 변환
val encryptedBytes = Base64.decode(encryptedBase64, Base64.DEFAULT)
val iv = Base64.decode(ivBase64, Base64.DEFAULT)
// Cipher 준비 (복호화 모드)
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val spec = GCMParameterSpec(128, iv)
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec)
// 복호화
val decryptedBytes = cipher.doFinal(encryptedBytes)
return String(decryptedBytes, Charsets.UTF_8)
}
- 암호화 때 사용한 IV와 암호문을 받아 복호화합니다.
- 복호화된 바이트를 문자열로 변환해 반환합니다.
Step 4: 실제로 사용해보기
// 예시 사용법
createAESKey() // 앱 최초 실행 시 1회만 호출
val plainText = "안녕하세요, Monica!"
val (encrypted, iv) = encryptData(plainText)
println("암호문: $encrypted")
println("IV: $iv")
val decrypted = decryptData(encrypted, iv)
println("복호화 결과: $decrypted")
주의사항
- IV(초기화 벡터)는 암호문과 함께 안전하게 저장해야 복호화가 가능합니다.
- Keystore에 저장된 키는 앱을 삭제하면 같이 사라집니다
'안드로이드 코틀린' 카테고리의 다른 글
| [Kotlin][Android]Jetpack Compose LazyColumn 과 RecyclerView (0) | 2025.07.08 |
|---|---|
| [Kotlin][Android] Hilt 활용 예시 만들기 (2) | 2025.07.04 |
| [Kotlin][Android] 코루틴(Coroutine) 사용하기 (2) | 2025.06.26 |
| [Kotlin][Android] Timber 활용 예시 만들기 (0) | 2025.06.21 |
| [Kotlin][Android] DefaultLifecycleObserver 활용 예시 만들기 (3) | 2025.06.14 |