참조 : Android Keystore System

안드로이드의 Keystore 시스템은 암호용 키 저장소로 디바이스에서 중요한 키 값을 추출해 내기 더 어렵도록 만들어준다. 키가 일단 Keystore에 들어가게 되면, 암호관련 operation을 통해서만 사용할 수 있게된다.

Keystore 시스템은 KeyChain API뿐만 아니라 Android Keystore 프로바이더를 통해 사용할 수 있으며, Android 4.3(API level 18)에서 처음 선보였다.

보안적 특징

안드로이드 Keystore 시스템은 승인되지 않은 접근(unauthorized use)에 대해 중요한 key material (e.g., iv 값)들을 보호한다.

첫째, 안드로이드 Keystore는 안드로이드 디바이스 밖에서의 승인되지 않은 key material 사용에 대해 key material 추출을 보호함으로써 승인되지 않은 접근에 대한 위협을 줄여준다.

둘째, 안드로이드 Keystore는 안드로이드 디바이스에서의 승인되지 않은 접근에 대해 키를 구체화(specify) 하고 앱 프로세스 바깥에서의 이들 제한을 강제함으로써 승인되지 않은 접근에 대한 위협을 줄여준다.

키 추출 방지

안드로이드 Keystore 키들의 key material들은 두가지 보안 수단에 의해 보호된다.

  • key material은 애플리케이션 프로세스에서 절대로 접근할 수 없다. 애플리케이션이 Keystore를 사용해 암호관련 operation을 수행할 때, 뒷단에서 시스템 프로세스를 통해 서명/확인등에 필요한 평문(plaintext)/암호문(cipher)/메시지(message)등이 공급된다. 앱 프로세스가 위협에 노출된다면, 공격자가 앱의 키를 사용할 수 있을진 모르나 key material까지 탈취하지는 못한다.
  • key material은 secure hardware(e.g., Trusted Execution Environment(TEE), Secure Element(SE))에 바인딩 돼 있을 수도 있다. 이 기능이 키에 대해 enable 되어있다면 해당 키에 대한 key material은 절대로 secure hardware 바깥으로 노출될 수 없다. 안드로이드 OS가 위협에 노출되거나 공격자가 시스템의 내부 저장소를 읽을수 있게 될지라도, 안드로이드 Keystore의 키를 추출할 수는 없다.

키 사용에 대한 인증처리

안드로이드에서 승인되지 않은 키 사용을 막기위해, 안드로이드 Keystore는 키를 생성하거나 외부에서 import 할 때, 해당 키들이 사용 될 때 구체화하도록 한다. 일단 키가 생성되거나 import 되면, 해당 키 사용에 대한 승인과정은 변경될 수 없다. 승인은 안드로이드 Keystore에 의해 키 사용때마다 강제된다.

키 사용 승인방식에 대해 아래와 같은 카테고리로 나누어 지원한다.

  • 암호화 : 키에서 사용될 수 있는 승인된 암호화 알고리듬, operation 또는 사용 목적(encrypt, decrypt, sign, verify), 패딩 scheme, 블록 모드, message digest 방식.
  • 인증 유효기간 : 해당키를 사용할 수 있는 유효기간을 지정.
  • 사용자 인증 : 키는 사용자가 최근에 인증 되었을 때만 사용하도록 제한.

추가적인 보안 수단으로써, key material에 대한 키는 secure hardware 내부에 있을 수 있다. 일부 키 사용 인증은 secure hardware에 의해 강제될 수 있으며, 이는 안드로이드 디바이스에 의존한다. 암호화와 사용자 인증 승인은 secure hardware에 의해 강제화 될 가능성이 있다. 단, 인증 유효기간은 secure hardware와는 관련이 없는데, 유효기간을 체크하는 독립된 secure real-time clock은 없기 때문이다.

Keychain 또는 안드로이드 Keystore에 대한 선택문제

시스템 범위의 자격 증명을 원한다면 KeyChain API를 사용하라. 앱이 KeyChain API를 통해 어떤 자격 증명 사용을 요청한다면 사용자는 system에서 제공하는 UI를 통해 앱에서 처리할 수 있는 설치된 자격 증명을 보여줘야 한다. 이것은 사용자 동의를 받은 같은 자격증명의 집합을 여러 앱들이 사용할수 있도록 한다.

이와 달리 개별 앱들이 자신만의 자격 증명을 사용하고, 그것만 접근이 가능한 앱을 만들기 위해선 안드로이드 Keystore 프로바이더를 사용하라.

안드로이드 Keystore 프로바이더 사용하기

기능을 사용하기위해, 표준 KeyStoreKeyPairGenerator 또는 KeyGenerator 클래스를 “AndroidKeyStore” 프로바이더를 통해 사용하면 된다.

새로운 private key 생성하기

새로운 PrivateKey 를 생성이 필요할 경우 아래와 같이 KeyPairGenerator 와 KeyPairGeneratorSpec 를 사용하여 생성할 수 있다.

/*
 * Generate a new EC key pair entry in the Android Keystore by
 * using the KeyPairGenerator API. The private key can only be
 * used for signing or verification and only with SHA-256 or
 * SHA-512 as the message digest.
 */
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
        KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
kpg.initialize(new KeyGenParameterSpec.Builder(
        alias,
        KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
        .setDigests(KeyProperties.DIGEST_SHA256,
            KeyProperties.DIGEST_SHA512)
        .build());

KeyPair kp = kpg.generateKeyPair();

새로운 secret key 생성하기

새로운 키 생성이 필요할 경우 아래와 같이 KeyPairGenerator 와 KeyPairGeneratorSpec 를 사용하여 생성할 수 있다.

Keystore 엔트리로 작업하기

“AndroidKeyStore” 프로바이더를 표준 KeyStore API를 통해 사용하면 된다.

엔트리 리스팅

aliases() 메서드를 사용하여 Keystore의 리스트를 로드한다.

/*
 * Load the Android KeyStore instance using the the
 * "AndroidKeyStore" provider to list out what entries are
 * currently stored.
 */
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
Enumeration<String> aliases = ks.aliases();

데이터 서명 및 서명된 데이터 검증

Keystore로부터 KeyStore.Entry 를 fetching하여 Signature API를 사용하여 데이터를 사이닝한다. sign() 메서드를 사용한다.

/*
 * Use a PrivateKey in the KeyStore to create a signature over
 * some data.
 */
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry(alias, null);
if (!(entry instanceof PrivateKeyEntry)) {
    Log.w(TAG, "Not an instance of a PrivateKeyEntry");
    return null;
}
Signature s = Signature.getInstance("SHA256withECDSA");
s.initSign(((PrivateKeyEntry) entry).getPrivateKey());
s.update(data);
byte[] signature = s.sign();

비슷하게, 데이터 검증도 verify(byte[]) 를 통해 검증하면 된다.

/*
 * Verify a signature previously made by a PrivateKey in our
 * KeyStore. This uses the X.509 certificate attached to our
 * private key in the KeyStore to validate a previously
 * generated signature.
 */
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry(alias, null);
if (!(entry instanceof PrivateKeyEntry)) {
    Log.w(TAG, "Not an instance of a PrivateKeyEntry");
    return false;
}
Signature s = Signature.getInstance("SHA256withECDSA");
s.initVerify(((PrivateKeyEntry) entry).getCertificate());
s.update(data);
boolean valid = s.verify(signature);

키 사용에 대한 사용자 인증 요구

“AndroidKeyStore”에 키를 생성 및 import 할때 인증을 받아야만 해당 키를 사용할 수 있도록 명시할 수 있다. 인증은 락스크린 자격 증명(패턴, pin, 지문 등)을 통해 수행할 수 있다.

지원 알고리즘

Cipher

Algorithm API Levels Notes
AES/CBC/NoPadding 23+
AES/CBC/PKCS7Padding 23+
AES/CTR/NoPadding 23+
AES/ECB/NoPadding 23+
AES/ECB/PKCS7Padding 23+
AES/GCM/NoPadding 23+ Only 12-byte long IVs supported.
RSA/ECB/NoPadding 18+
RSA/ECB/PKCS1Padding 18+
RSA/ECB/OAEPWithSHA-1AndMGF1Padding 23+
RSA/ECB/OAEPWithSHA-224AndMGF1Padding 23+
RSA/ECB/OAEPWithSHA-256AndMGF1Padding 23+
RSA/ECB/OAEPWithSHA-384AndMGF1Padding 23+
RSA/ECB/OAEPWithSHA-512AndMGF1Padding 23+
RSA/ECB/OAEPPadding 23+

KeyGenerator

Algorithm API Levels Notes
AES 23+ Supported sizes: 128, 192, 256
HmacSHA1 23+
  • Supported sizes: 8–1024 (inclusive), must be multiple of 8
  • Default size: 160
HmacSHA224 23+
  • Supported sizes: 8–1024 (inclusive), must be multiple of 8
  • Default size: 224
HmacSHA256 23+
  • Supported sizes: 8–1024 (inclusive), must be multiple of 8
  • Default size: 256
HmacSHA384 23+
  • Supported sizes: 8–1024 (inclusive), must be multiple of 8
  • Default size: 384
HmacSHA512 23+
  • Supported sizes: 8–1024 (inclusive), must be multiple of 8
  • Default size: 512

KeyFactory

Algorithm API Levels Notes
EC 23+ Supported key specs: KeyInfo (private key only),  ECPublicKeySpec (public key only), X509EncodedKeySpec (public key only)
RSA 23+ Supported key specs:  KeyInfo(private key only), RSAPublicKeySpec (public key only), X509EncodedKeySpec (public key only)

KeyStore

KeyPairGenerator 와 KeyGenerator 로써 같은 키 타입을 제공한다.

KeyPairGenerator

Algorithm API Levels Notes
DSA 19–22
EC 23+
  • Supported sizes: 224, 256, 384, 521
  • Supported named curves: P-224 (secp224r1), P-256 (aka secp256r1 and prime256v1), P-384 (aka secp384r1), P-521 (aka secp521r1)

API Level 23 이전 버전에서, 타원곡선 암호화(EC)를 사용하려면 KeyPairGenerator에서 알고리듬을 “RSA”로 초기화한다.

그리고 setKeyType(String) 메서드를 통해 KeyPairGeneratorSpec을 “EC”로 초기화 하면 EC를 쓸 수 있다.

EC의 named curve 지정 메서드는 따로 존재하지 않으며 키 사이즈에 따라 자동적으로 선택된다.

RSA 18+
  • Supported sizes: 512, 768, 1024, 2048, 3072, 4096
  • Supported public exponents: 3, 65537
  • Default public exponent: 65537

Mac(Message Authentication Code)

Algorithm API Levels Notes
HmacSHA1 23+
HmacSHA224 23+
HmacSHA256 23+
HmacSHA384 23+
HmacSHA512 23+

Signature

Algorithm API Levels Notes
MD5withRSA 18+
NONEwithECDSA 23+
NONEwithRSA 18+
SHA1withDSA 19–22
SHA1withECDSA 19+
SHA1withRSA 18+
SHA1withRSA/PSS 23+
SHA224withDSA 20–22
SHA224withECDSA 20+
SHA224withRSA 20+
SHA224withRSA/PSS 23+
SHA256withDSA 19–22
SHA256withECDSA 19+
SHA256withRSA 18+
SHA256withRSA/PSS 23+
SHA384withDSA 19–22
SHA384withECDSA 19+
SHA384withRSA 18+
SHA384withRSA/PSS 23+
SHA512withDSA 19–22
SHA512withECDSA 19+
SHA512withRSA 18+
SHA512withRSA/PSS 23+

SecretKeyFactory

Algorithm API Levels Notes
AES 23+ Supported key specs: KeyInfo
HmacSHA1 23+ Supported key specs: KeyInfo
HmacSHA224 23+ Supported key specs: KeyInfo
HmacSHA256 23+ Supported key specs: KeyInfo
HmacSHA384 23+ Supported key specs: KeyInfo
HmacSHA512 23+ Supported key specs: KeyInfo