From 2374e2e6e9eacb6f70f8d3bbf1a2aa74f3c6dc4b Mon Sep 17 00:00:00 2001 From: sys Date: Wed, 6 Oct 2021 19:11:54 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=ED=82=A4=EC=9B=8C=EB=93=9C=20=EA=B0=84?= =?UTF-8?q?=EB=8B=A8=ED=95=98=EA=B2=8C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Part 0 - Keyword List.md | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 008. KeyStore System and Security/Part 0 - Keyword List.md diff --git a/008. KeyStore System and Security/Part 0 - Keyword List.md b/008. KeyStore System and Security/Part 0 - Keyword List.md new file mode 100644 index 0000000..d9bce5d --- /dev/null +++ b/008. KeyStore System and Security/Part 0 - Keyword List.md @@ -0,0 +1,35 @@ +## Keystore System & Security + +## Security Basic + +* Encrypt/Decrypt (암호화 / 복호화) + * Encrypt: 암호화에서, 암호화는 정보를 인코등하는 프로세스이다. 일반 텍스트로 알려진 정보의 원래 표현을 암호문으로 알려진 대체 형식으로 변환한다. 이상적으로는 승인된 사람만이 암호문을 다시 평문으로 해독가능하며 원본 정보에 접근 가능하다. 그 자체로 간섭을 방지하는 것이 아니라 잠재적인 인터셉터가 이해할 수 있는 콘텐츠 자체를 거부한다. + * Decrypt: 암호화된 데이터를 사람이 읽고 이해할 수 있는 형태로 변환하는 프로세스이다. 텍스트를 수동으로 암호화를 해체하거나 원본 데이터를 암호화하는데 사용되는 키를 사용하여 복호화를 수행한다. + +* Symmetric Key (대칭키) + 대칭 키 암호에서는 암호화를 하는 측과 복호화를 하는 측이 같은 암호 키를 공유한다. 대부분의 대칭 키 암호는 공개 키 암호와 비교하여 계산 속도가 빠르다. 대칭 키 암호는 암호화하는 단위에 따라 Block Cipher 와 Stream Cipher 가 있다. + + * DES: 암호화 및 복호화 키가 동일하고 비대칭에 비해 속도가 빠르다. + * AES: DES를 대체한 암호 알고리즘이며 암호화와 복호화 과정에서 동일한 키를 사용한다. + + * Block Cipher: 한번에 텍스트를 블록 단위로 가져와서 암호화한다. 64 bit 또는 64 bit이상을 사용한다. 암호화의 복잡성은 간단하다. 복호화하는 과정이 어렵다. 스트림 방식보다 느리다. + * Stream Cipher: 한번에 텍스트를 1바이트 단위로 가져와서 암호화한다. 8 bit 를 사용한다. 암호화의 복잡성은 복잡하다. 복호화하는 과정이 쉽다. 블락 방식보다 빠르다. + +* Hash + 프로그램이나 파일이 원본 그대로인지를 확인하는 무결성 검사 등에 사용된다. + * MD5: 임의의 길이의 메시지(variable-length message)를 입력받아, 128비트짜리 고정 길이의 출력값을 낸다. 암호화 결함이 발견되어 보안 용도로 사용할 때에는 SHA와 같은 다른 알고리즘을 사용하는 것이 권장된다. + * sha-256: SHA(Secure Hash Algorithm) 알고리즘의 한 종류로서 어떤 길이의 값을 입력하더라도 256 bit 의 고정된 결과값을 반환한다. 단방향 암호화 방식이기 때문에 복호화가 불가능하다. 복호화를 하지 않아도 되기 때문에 속도가 빠르며, 비밀번호를 확인하는 용도등으로 사용 가능하다. + +* Checksum +우발적인 변경을 방지하기 위한것이다. 1 byte 가 변경되면 체크섬이 변경된다. 체크섬은 악의적인 변경으로부터 보호하기에는 안전하지 않다. 특정 체크섬으로 파일을 만드는 것은 매우 쉽다. + +* MAC : Message Authentication Code + MAC(메시지 인증코드) 또는 태그는 컴퓨터 사용자가 계정이나 포털에 액세스하기 위해 입력하는 보안 코드이다. 이 코드는 사용자가 보낸 메시지 또는 요청에 첨부된다. MAC 은 사용자 액세스 권한을 부여하기 위해 수신된 시스템에서 인식할 수 있어야 한다. + * HMAC(Hash-based MAC): 송신자, 수신자 공유된 비밀키를 가지면 송신자가 키와 메시지를 해시를 생성해서 메시지와 해시를 전송하면 수신자는 수신된 해시와 수신 받은 메시지를 통해 생성한 해시를 비교한다. + * CMAC(Cipher-based MAC): 누군가가 중간에서 메시지와 MAC을 가로채서, 메시지를 변조시키고, MAC도 다시 새롭게 만들어서 보낼 수 있다. 이런 경우에 수신자는 메시지의 MAC과 받은 MAC이 일치하므로 메시지가 변조된지 알 길이 없다. 이러한 단점을 보안한 것이 CMAC 이며, 메시지 암호화 과정에서 나온 결과물을 MAC으로 사용한다. + +* Asymmetric Key (비대칭키) + 비대칭암호화는 두 개의 별개의 관련 키를 사용한다. 하나의 키인 공개 키는 암호화에 사용되고 다른 하나인 개인 키는 복호화에 사용한다. 이름에서 알 수 있듯이 개인키는 인증된 수신자만 메시지를 해독할 수 있도록 비공개로 되어있다. + * Diffie-Hallman: 상대방의 공개키와 나의 개인키를 이용하여 계산을 하면 비밀키가 나온다. 이 비밀키를 사용해서 데이터를 암호화해서 보내고 복호화해서 해석한다. + * RSA: 공개키 암호 알고리즘의 하나로서 세계적으로 사실상의 표준이다. 인수분해 문제 해결의 높은 난이도를 이용해 암호화뿐만 아니라 전자 서명의 용도로도 사용된다. 모두에개 공개하는 공개키(Public key)와 공개해서는 안되는 개인키(Private Key) 로 구성된다. 공개키는 메시지를 암호화할때 사용하고, 개인키는 암호화된 메시지를 복호화할때 사용한다. + * ECC: 암호키 길이가 길어지면 보안 강도는 높아지지만 속도가 느려집니다. 하지만, ECC(Elliptic Curve Cryptography) 를 사용하면 짧은 키로도 동일한 암호 성능을 가지는데, 이는 컴퓨터 성능이 낮아도 암호 성능을 유지할 수 있다. 이러한 이유로 RSA를 대체할 차세대 공개키 암호기술로 부상하고 있다. From cbf5db616602ac07a67b857805faa97be5bed84a Mon Sep 17 00:00:00 2001 From: sys Date: Tue, 12 Oct 2021 23:51:11 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=EC=B6=9C=EC=B2=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Part 0 - Keyword List.md | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/008. KeyStore System and Security/Part 0 - Keyword List.md b/008. KeyStore System and Security/Part 0 - Keyword List.md index d9bce5d..d91c698 100644 --- a/008. KeyStore System and Security/Part 0 - Keyword List.md +++ b/008. KeyStore System and Security/Part 0 - Keyword List.md @@ -33,3 +33,39 @@ * Diffie-Hallman: 상대방의 공개키와 나의 개인키를 이용하여 계산을 하면 비밀키가 나온다. 이 비밀키를 사용해서 데이터를 암호화해서 보내고 복호화해서 해석한다. * RSA: 공개키 암호 알고리즘의 하나로서 세계적으로 사실상의 표준이다. 인수분해 문제 해결의 높은 난이도를 이용해 암호화뿐만 아니라 전자 서명의 용도로도 사용된다. 모두에개 공개하는 공개키(Public key)와 공개해서는 안되는 개인키(Private Key) 로 구성된다. 공개키는 메시지를 암호화할때 사용하고, 개인키는 암호화된 메시지를 복호화할때 사용한다. * ECC: 암호키 길이가 길어지면 보안 강도는 높아지지만 속도가 느려집니다. 하지만, ECC(Elliptic Curve Cryptography) 를 사용하면 짧은 키로도 동일한 암호 성능을 가지는데, 이는 컴퓨터 성능이 낮아도 암호 성능을 유지할 수 있다. 이러한 이유로 RSA를 대체할 차세대 공개키 암호기술로 부상하고 있다. + + + + + + + +https://en.wikipedia.org/wiki/Encryption + +[https://ko.wikipedia.org/wiki/%EB%8C%80%EC%B9%AD_%ED%82%A4_%EC%95%94%ED%98%B8](https://ko.wikipedia.org/wiki/대칭_키_암호) + +https://www.geeksforgeeks.org/difference-between-block-cipher-and-stream-cipher/ + +https://newbedev.com/checksum-vs-hash-differences-and-similarities + +https://findanyanswer.com/what-is-checksum-byte + +https://stackoverflow.com/questions/460576/hash-code-and-checksum-whats-the-difference + +https://bamdule.tistory.com/233 + +https://ddongwon.tistory.com/38 + +https://cheapsslsecurity.com/blog/what-is-asymmetric-encryption-understand-with-simple-examples/ + +https://www.crocus.co.kr/1233 + +[https://yjshin.tistory.com/entry/%EC%95%94%ED%98%B8%ED%95%99-%EB%8C%80%EC%B9%AD%ED%82%A4-%EC%95%94%ED%98%B8-DESData-Encryption-Standard](https://yjshin.tistory.com/entry/암호학-대칭키-암호-DESData-Encryption-Standard) + +https://www.crocus.co.kr/1230 + +[https://yjshin.tistory.com/entry/%EC%95%94%ED%98%B8%ED%95%99-%EB%B9%84%EB%8C%80%EC%B9%AD%ED%82%A4-%EC%95%94%ED%98%B8-RSA-%EC%95%94%ED%98%B8%EC%8B%9C%EC%8A%A4%ED%85%9C](https://yjshin.tistory.com/entry/암호학-비대칭키-암호-RSA-암호시스템) + +https://medium.com/humanscape-tech/blockchain-elliptic-curve-cryptography-ecc-49e6d7d9a50a + +https://developer-mac.tistory.com/83 From fce143f4d1338cae61ebe3652c041a51d1b4f01f Mon Sep 17 00:00:00 2001 From: sys Date: Tue, 12 Oct 2021 23:51:25 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=ED=8C=8C=ED=8A=B82=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Part 2 - Android Securty Crypto.md | 303 ++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 008. KeyStore System and Security/Part 2 - Android Securty Crypto.md diff --git a/008. KeyStore System and Security/Part 2 - Android Securty Crypto.md b/008. KeyStore System and Security/Part 2 - Android Securty Crypto.md new file mode 100644 index 0000000..1b04a4e --- /dev/null +++ b/008. KeyStore System and Security/Part 2 - Android Securty Crypto.md @@ -0,0 +1,303 @@ +### Android Security Crypto + +#### SharedPreferences + +저장하려는 키-값 컬렉션이 비교적 작은 경우 SharedPreferences API를 사용한다. SharedPreferences 객체는 키-값 쌍이 포함된 파일을 가리키며 키-값 쌍을 읽고 쓸 수 있는 간단한 메서드를 제공한다. SharedPreferences 파일은 프레임워크에서 관리하며 비공개이거나 공유일 수 있다. +다음과 같이 SharedPreferences 를 설정해서 사용할 수 있다. + +``` +val sharedPreferences = getSharedPreferences("filename", MODE_PRIVATE) + +val editor = sharedPreferences.edit() +editor.putString("name", "value") +editor.apply(); +val name = sharedPreferences.getString("name", "default") +Log.d("AndroidDeepDive", "$name") +``` + +SharedPreferences 에서 설정한 이름으로 xml 파일을 생성하고 위치는 다음과 같다. + +``` +/data/data/{package_name}/shared_prefs/{Name_of_preference}.xml +``` + +생성된 xml 은 다음과 같은 구조로 되어있다. + +``` + + + value + AndroidDeepDive + +``` + +민감한 데이터를 작업할때, SharedPreferences 가 데이터를 일반 텍스트로 저장한다는 점에서 눈에 띄지 않도록 민감한 데이터 암호화를 고려하는 것은 중요하다. + + + +#### EncryptedSharedPreferences + +SDK 23 이상에서 Android KeyStore 를 사용해서 암호화된 SharePrefereces 를 제공하는 EncryptedSharedPreferences를 사용할 수 있다. +EncryptedSharedPreferences 사용하기 위해 Dependency 를 추가한다. + +``` +dependencies { + implementation "androidx.security:security-crypto:1.1.0-alpha03" +} +``` + +다음과 같이 MasterKey Alias 를 생성하고, EncryptedSharedPreferences 를 생성해서 사용할 수 있다. + +``` +val masterKeyAlias = MasterKey.Builder(applicationContext) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() + +val sharedPreferences = EncryptedSharedPreferences.create( + applicationContext, + "filename", + masterKeyAlias, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM +) +val editor = sharedPreferences.edit() +editor.apply { + putString("name", "value") + putString("team", "AndroidDeepDive") +} +editor.apply() +val team = sharedPreferences.getString("team", "ADD") +Log.d("AndroidDeepDive", "$team") +``` + +SharedPreferences 에서 설정한 이름으로 xml 파일을 생성하고 위치는 다음과 같다. + +``` +/data/data/{package_name}/shared_prefs/{Name_of_preference}.xml +``` + +생성된 xml 은 다음과 같은 구조로 되어있으며, 기존 SharedPreferences 과 달리 Key와 Value 모두 암호화되어 어떤 Key 와 Value 로 구성되어 있는지 알 수 없다. + +``` + + AR0kWCC+wheaW5se/p3Yb2CO6nk0BccqRwKMxg8n3KEzl3NBd1sh5o4IXmZH8g== + 12a9016701bb6048ea6201847aa4aea20cff30a28d7b2348c25103f918f5ee017bcc75258196eb57da96a6a272ae0175d62b08602c3a64acb5e67b737d2ca8d8dc59f7d7703689e64e4004168655c13c6149e9858d917331c34ec7c2122ba89d1496c279504cd70e06122ed4a61a441efd4f852e876f04399a8b3b84e5b83ced488a0dd6bba662d71f2f1df959ef04a0341715fdca6d2ee720b47b8753e04fe249101be5616d4c3ba097828a1a44088191b0bc03123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e4165735369764b65791001188191b0bc032001 + AR0kWCAPa5U7x9s/8eAAW5HyqWL1bPr5jsEckeY91UIJox5q7SBSb8MaW/SxjBjLjpWobSjBFak= + 12880113126e04edc22f0b68588e44eaba4bfedf7c83c07457a852f35bba74ae209a935d41f96c1fa67997282784342a51c3c8a87f7a59bb945fc9218bda2964c1fadb88d8b9239242244c6ba6cd4204e3cde89720a8ed2563a37fc816e82e51a690e2218861e4e0f4874905c8d68012ac5979604ae80b8c737fe0fe44a45ba75635dae629e18956c968541a4408a0b091e901123c0a30747970652e676f6f676c65617069732e636f6d2f676f6f676c652e63727970746f2e74696e6b2e41657347636d4b6579100118a0b091e9012001 + +``` + + + +#### DataStore + +Jetpack DataStore 는 key-value 쌍 또는 object 타입을 protocal buffers 와 함께 저장할 수 있는 데이터 저장 솔루션이다. DataStore 는 코틀린 coroutines 과 Flow 를 사용해서 비동기적이고 일관된 트랜잭션 방식으로 저장한다. SharedPreferences 의 단점을 극복하고 대체할 것이다. DataStore 는 작고 단순한 데이터 세트에 이상적이며 부분 업데이트 또는 참조 무결성은 지원하지 않는다. +DataStore 에는 Preferences DataStore 와 Proto DataStore 두가지 종류가 있다. + +- Preferences DataStore + SharedPreferences 와 마찬가지로 키를 사용해서 데이터를 저장하고 액세스한다. 스키마를 정의하거나 키가 올바른 타입으로 액세스되도록 할 수 있는 방법이 없다. + +Preferences DataStore 사용하기 위해 Dependency 를 추가한다. + +``` +dependencies { + implementation "androidx.datastore:datastore-preferences:1.0.0" +} +``` + +아래와 같이 이름을 설정해서 최상위 레벨에 DataStore 선언한다. + +``` +private val Context.dataStore: DataStore by preferencesDataStore(name = "DataStoreSample") +``` + +DataStore 에 접근할 key 를 설정해서 데이터를 저장하고 flow 를 통해 가져오도록 아래와 같이 작성한다. + +``` +val counter = intPreferencesKey("counter") +val exampleCounterFlow: Flow = dataStore.data + .catch { exception -> + if (exception is IOException) { + emit(emptyPreferences()) + } else { + throw exception + } + } + .map { preferences -> + preferences[counter] ?: 0 + } +binding.button.setOnClickListener { + GlobalScope.launch { + incrementCounter() + } +} +GlobalScope.launch { + exampleCounterFlow.collect { + Log.d("AndroidDeepDive", "Count = $it") + } +} +suspend fun incrementCounter() { + val counter = intPreferencesKey("counter") + + dataStore.edit { preferences -> + val currentCounterValue = preferences[counter] ?: 0 + preferences[counter] = currentCounterValue + 1 + } +} +``` + + + +- Proto DataStore + 사용자 정의 데이터 유형의 인스턴스로 데이터를 저장한다. Protocol buffers 를 사용해서 스키마를 정의해야 한다. Protobufs 를 사용하면 강력한 형식 데이터를 유지할 수 있다. XML 및 다른 유사한 데이터 포맷보다 빠르고 작고 단순하고 덜 모호하다. + +Proto DataStore 사용하기 위해 Dependency 를 추가한다. + +``` +plugins { + id "com.google.protobuf" version "0.8.17" +} +dependencies { + implementation "androidx.datastore:datastore-core:1.0.0" + implementation "com.google.protobuf:protobuf-javalite:3.14.0" +} +protobuf { + protoc { + artifact = "com.google.protobuf:protoc:3.14.0" + } + + generateProtoTasks { + all().each { task -> + task.builtins { + java { + option 'lite' + } + } + } + } +} +``` + +app/src/main/proto/ 디렉토리의 proto 파일에 미리 정의된 스키마를 생성해야 한다. 아래와 같이 app/src/main/proto 에 user.proto 라는 파일을 생성한다. proto 스키마 정의에 대한 자세한 내용은 [protobuf language guide](https://developers.google.com/protocol-buffers/docs/proto3) 를 참조한다. + +``` +syntax = "proto3"; + +option java_package = "com.passionvirus.keystore"; +option java_multiple_files = true; + +message UserSettings { + enum BgColor { + COLOR_WHITE = 0; + COLOR_BLACK = 1; + } + BgColor bgColor = 1; +} +``` + +user.proto 파일을 생성후에 gradle 프로젝트를 리빌드하면 app/build/generated/source/proto/ 아래에 UserSettings.java 파일이 자동으로 생성되는것을 볼 수 있다. + +Serializer를 구현하는 클래스 만든다. 여기서 T 는 proto 파일에 정의된 형식이다. 여기서는 UserSettings 타입이다. serializer 는 데이터 유형을 읽고 쓰는 방법을 DataStore 에 알려준다. 아래와 같이 코드를 작성할 수 있다. + +``` +object ProtoSettingsSerializer : Serializer { + override suspend fun readFrom(input: InputStream): UserSettings { + try { + return UserSettings.parseFrom(input) + } catch (ex: InvalidProtocolBufferException) { + throw CorruptionException("Cannot read proto.", ex) + } + } + + override suspend fun writeTo(t: UserSettings, output: OutputStream) { + t.writeTo(output) + } + + override val defaultValue: UserSettings + get() = TODO("Not yet implemented") +} +``` + +아래와 같이 이름을 설정해서 최상위 레벨에 Proto DataStore 선언한다. + +``` +private val Context.dataStore: DataStore by dataStore(fileName = "user_settings.pb", serializer = ProtoSettingsSerializer) +``` + +DataStore 에 데이터를 저장하고 flow 를 통해 가져오도록 아래와 같이 작성한다. + +``` +val userSettingsFlow: Flow = dataStore.data.catch { ex -> + if (ex is IOException) { + emit(UserSettings.getDefaultInstance()) + } else { + throw ex + } +} +GlobalScope.launch { + userSettingsFlow.collect { + when(it.bgColor) { + UserSettings.BgColor.COLOR_WHITE -> binding.main.setBackgroundColor( + ContextCompat.getColor( + this@MainActivity, + android.R.color.white + ) + ) + UserSettings.BgColor.COLOR_BLACK -> binding.main.setBackgroundColor( + ContextCompat.getColor( + this@MainActivity, + android.R.color.black + ) + ) + } + } +} +suspend fun updateColor(bgColor: UserSettings.BgColor) { + dataStore.updateData { userSetting -> + userSetting.toBuilder().setBgColor(bgColor).build() + } +} +``` + + + +#### Google Tink Library + +Tink 는 암호화 및 보안 엔진니어가 작성한 오픈소스 암호화 라이브러이다. Tink의 안전하고 간단한 API 는 유저 중심 설계, 신중한 구현 및 코드 리뷰, 광범위한 테스트를 통해 일반적인 위험을 줄인다. +Tink 는 암호화에 배경 지식이 없는 사용자가 일반적인 암호화작업을 안전하게 구현할 수 있도록 도와준다. + +Tink 를 사용해야 하는 이유 + +- 사용하기 쉽다 + +암호화는 제대로하기 어렵다. Tink 를 사용하면 단 몇 줄의 코드로 암호화하거나 서명할 수 있으며 내장된 보안 보장으로 위험을 회피할수 있다. + +- 안전성 + +Tink는 BoringSSL 및 Java Cryptography Architecture와 같은 잘 알려진 라이브러리 위에 보안 보호 기능을 추가하고 이를 인터페이스에 바로 표시하므로 감시자와 도구가 신속하게 격차를 찾을 수 있다. 또한 Tink 는 잠재적으로 위험한 API 를 분리하여 모니터링 할 수 있다. + +- 호환성 + +Tink 암호문은 기존 암호화 라이브러리와 호환된다. 또한 Tink 는 Amazon KMS, Google Cloud KMS, Android Keystore, and iOS Keychain 에서 키의 암호화 및 저장을 지원한다. + + + + + + + +https://striban.tistory.com/66 + +https://medium.com/androiddevelopers/data-encryption-on-android-with-jetpack-security-e4cb0b2d2a9 + +https://wise4rmgodadmob.medium.com/data-encryption-on-android-with-jetpack-security-78a230f2366 + +https://newbedev.com/how-to-check-if-sharedpreferences-file-exists-or-not + +https://developer.android.com/training/data-storage/shared-preferences + +https://proandroiddev.com/welcome-datastore-good-bye-sharedpreferences-fdeb831a1e58 + +https://youngest-programming.tistory.com/369 + +https://developers.google.com/tink \ No newline at end of file From 46e41c1927d3028b294da6b9507fc511e1f67ed8 Mon Sep 17 00:00:00 2001 From: sys Date: Tue, 12 Oct 2021 23:52:19 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=ED=8C=8C=ED=8A=B8=201=20=EA=B0=84=EB=8B=A8?= =?UTF-8?q?=ED=95=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Part 1 - What is KeyStore System?.md | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 008. KeyStore System and Security/Part 1 - What is KeyStore System?.md diff --git a/008. KeyStore System and Security/Part 1 - What is KeyStore System?.md b/008. KeyStore System and Security/Part 1 - What is KeyStore System?.md new file mode 100644 index 0000000..1cc3cd7 --- /dev/null +++ b/008. KeyStore System and Security/Part 1 - What is KeyStore System?.md @@ -0,0 +1,155 @@ +## Android Keystore + +Android Keystore 시스템을 사용하면 암호화 키를 컨테이너에 저장하여 기기에서 키를 추출하기 어렵게 할 수 있다. 키 저장소에 키가 저장되면, 키 자료는 내보낼 수 없는 상태로 유지하면서 키를 암호화 작업에 사용할 수 있다. 이 시스템에서는 키 사용 시기와 사용 방법을 제한하는 기능도 제공한다. 예를 들어 키 사용을 위해 사용자 인증을 요구하거나, 특정 암호화 모드에서만 키를 사용하도록 제한할 수 있다. Keystore 시스템은 Android 4.0(API 수준 14)에서 도입된 KeyChain API에서 사용한다. Android 4.3(API 수준 18)에서 도입된 Android Keystore 제공자 기능 및 Jetpack의 일부로 제공되는 보안 라이브러리에서도 사용한다. + +### 보안기능 + +* 추출차단: Android Keystore는 애플리케이션 프로세스와 Android 기기 전체에서 키 자료의 추출을 차단하여 Android 기기 외부에서 키 자료의 무단 사용을 줄인다. + +* 키 사용 승인: Android Keystore는 앱에서 승인된 키 사용처를 지정하도록 하여 앱 프로세스 외부에 적용하는 방식으로 Android 기기에서 키 자료의 무단 사용을 줄인다. + +### 키체인 또는 Android Keystore provider + +시스템 수준의 사용자 인증 정보를 원하는 경우 KeyChain API를 사용한다. 앱에서 KeyChain API를 통해 사용자 인증 정보 사용을 요청하는 경우 사용자는 설치된 사용자 인증 정보 중 앱이 액세스할 수 있는 사용자 인증 정보를 시스템 제공 UI를 통해 선택한다. 이렇게 하면 사용자 동의를 받아 여러 앱이 동일한 사용자 인증 정보 집합을 사용할 수 있다. +개별 앱이 전용으로 액세스할 수 있는 고유한 사용자 인증 정보를 저장할 수 있게 하려면 Android Keystore 제공자를 사용한다. Android Keystore 제공자를 통해 앱에서 전용으로 사용할 수 있는 사용자 인증 정보를 관리할 수 있을 뿐만 아니라 KeyChain API가 시스템 수준의 사용자 인증 정보에 제공하는 것과 동일한 보안 이점을 얻을 수 있다. 이 방법은 사용자 인증 정보를 선택하기 위한 사용자 상호작용이 필요 없다. + +* Dependency 를 추가 + security-crypto 1.1.0-alpha01 이상부터 사용할 수 있다. + + implementation "androidx.security:security-crypto:1.1.0-alpha03" + +* 새 비공개 키 생성 + 새 PrivateKey를 생성하려면 자체 서명 인증서에 포함될 초기 X.509 속성도 지정해야 한다. + + val mainKey = MasterKey.Builder(applicationContext) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() + + // KeyPairGenerator 는 MinSDK 23+ + val kpg: KeyPairGenerator = KeyPairGenerator.getInstance( + KeyProperties.KEY_ALGORITHM_EC, + "AndroidKeyStore" + ) + val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder( + "keystoreAlias", + KeyProperties.PURPOSE_SIGN // or KeyProperties.PURPOSE_VERIFY + ).run { + setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) + build() + } + + kpg.initialize(parameterSpec) + + val kp = kpg.generateKeyPair() + +* 안전하게 암호화된 키 가져오기 + Android 9(API 수준 28) 이상에서는 ASN.1로 인코딩된 키 형식을 사용하여 암호화된 키를 Keystore로 안전하게 가져올 수 있다. + + KeyDescription ::= SEQUENCE { + keyFormat INTEGER, + authorizationList AuthorizationList + } + + SecureKeyWrapper ::= SEQUENCE { + wrapperFormatVersion INTEGER, + encryptedTransportKey OCTET_STRING, + initializationVector OCTET_STRING, + keyDescription KeyDescription, + secureKey OCTET_STRING, + tag OCTET_STRING + } + +* 키 저장소 항목 작업 + + val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply { + load(null) + } + val aliases: Enumeration = ks.aliases() + +* 데이터 서명 및 확인 + + // 데이터 서명 + val alias = "AndroidDeepDive" + var privateKey : PrivateKey? = null + + val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").*apply *{** + **load(null) + }** + + **if (ks.containsAlias(alias)) { + Log.d("AndroidDeepDive", "Alias exist already") + val entry: KeyStore.Entry = ks.getEntry(alias, null) + if (entry is KeyStore.PrivateKeyEntry) { + privateKey = entry.*privateKey + *} + } + else { + Log.d("AndroidDeepDive", "Alias not exist") + val kpg: KeyPairGenerator = KeyPairGenerator.getInstance( + KeyProperties.*KEY_ALGORITHM_EC*, + "AndroidKeyStore" + ) + + val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder( + alias, + KeyProperties.*PURPOSE_SIGN *// or KeyProperties.PURPOSE_VERIFY + // KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY + ).*run *{ + setDigests( + KeyProperties.*DIGEST_SHA256*, + KeyProperties.*DIGEST_SHA512 + *) + build() + }** + + **kpg.initialize(parameterSpec) + + val kp = kpg.generateKeyPair() + privateKey = kp.*private + *} + + val data = "blahblah".*toByteArray*(Charset.defaultCharset()) + val signature: ByteArray = Signature.getInstance("SHA256withECDSA").*run ***{ + **initSign(privateKey) + update(data) + sign() + **}** + + // 데이터 확인 + val entry = ks.getEntry(alias, null) as? KeyStore.PrivateKeyEntry + if (entry != null) { + val valid: Boolean = Signature.getInstance("SHA256withECDSA").*run *{** + **initVerify(entry.*certificate*) + update(data2) + verify(signature) + }** + + **Log.d("AndroidDeepDive", "signature: $valid") + } + else { + Log.w("AndroidDeepDive", "Not an instance of a PrivateKeyEntry") + } + + + +## Trusted Execution Environment(TEE) + +TEE 는 메인 프로세세의 보안 영역이다. 내부에 로드된 코드와 데이터가 기밀성과 무결성과 관련하여 보호되도록 보장한다. 격리된 실행 환경인 TEE 는 격리된 실행, TEE 로실행되는 어플리케이션의 무결성과 같은 보안 기능을 제공한다. 일반적으로 TEE 는 rich OS 보다 디바이스에서 실행되는 신뢰할 수 있는 응용프로그램에 대해 더 높은 수준의 보안을 제공하고 SE(secure element) 보다 더 많은 기능을 제공하는 실행 공간을 제공한다. + +A **trusted execution environment** (**TEE**) is a secure area of a [main processor](https://en.wikipedia.org/wiki/Central_processing_unit). It guarantees code and data loaded inside to be protected with respect to confidentiality and integrity[[*clarification needed](https://en.wikipedia.org/wiki/Wikipedia:Please_clarify)*].[[1]](https://en.wikipedia.org/wiki/Trusted_execution_environment#cite_note-oulpita.com-1) A TEE as an isolated execution environment provides security features such as isolated execution, integrity of applications executing with the TEE, along with confidentiality of their assets.[[2]](https://en.wikipedia.org/wiki/Trusted_execution_environment#cite_note-2) In general terms, the TEE offers an execution space that provides a higher level of security for trusted applications running on the device than a rich operating system (OS) and more functionality than a ‘secure element’ (SE). + +TEE(신뢰할 수 있는 실행 환경)는 주 프로세서의 보안 영역입니다. 내부에 로드된 코드와 데이터가 기밀성과 무결성과 관련하여 보호되도록 보장합니다[설명 필요].[1] 격리된 실행 환경인 TEE는 자산의 기밀성과 함께 격리된 실행, TEE로 실행되는 애플리케이션의 무결성과 같은 보안 기능을 제공합니다.[2] 일반적으로 TEE는 풍부한 운영 체제(OS)보다 장치에서 실행되는 신뢰할 수 있는 응용 프로그램에 대해 더 높은 수준의 보안을 제공하고 ‘보안 요소’(SE)보다 더 많은 기능을 제공하는 실행 공간을 제공합니다. + + + + + +https://developer.android.com/training/articles/keystore?hl=ko + +https://source.android.com/security/keystore?hl=ko + +https://en.wikipedia.org/wiki/Trusted_execution_environment + +https://linsoo.pe.kr/archives/28119 + +https://linsoo.pe.kr/archives/28144 \ No newline at end of file From 9a0d7373b0cd4f26ab8a0f43c4dc139e9ad23d06 Mon Sep 17 00:00:00 2001 From: sys Date: Wed, 27 Oct 2021 19:32:05 +0900 Subject: [PATCH 5/5] part 3 --- .../Part 3 - Hiding strings.md | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 008. KeyStore System and Security/Part 3 - Hiding strings.md diff --git a/008. KeyStore System and Security/Part 3 - Hiding strings.md b/008. KeyStore System and Security/Part 3 - Hiding strings.md new file mode 100644 index 0000000..ff258d4 --- /dev/null +++ b/008. KeyStore System and Security/Part 3 - Hiding strings.md @@ -0,0 +1,56 @@ +## Hiding strings + +앱에서 비밀번호나 API 키 등의 민감한 정보를 사용할 수 있다. 다음과 같이 일반적인 정보를 숨기기 위한 전략이 있다. + +### Hard Cording + +다음과 같이 소스 코드내에 숨길수 있다. + + class AndroidDeepDive **{ + private val groupName = "ADD" + private val groupGithub = "https://github.com/AndroidDeepDive" + } + +AptTool 을 사용해서 디컴파일할 수 있으며, 그 결과, classes(숫자).dex 형태의 소스파일에서 dex2jar 를 사용해서 dex 파일을 jar 파일로 변환한다. JD GUI 툴을 통해서 소스 코드에서 해당 내역을 확인할 수 있다. + +### App Data + +XML 리소스에 숨길수도 있다. + + AndroidDeepDive + https://github.com/AndroidDeepDive + +[strings](https://en.wikipedia.org/wiki/Strings_(Unix)) 을 이용해서 검색을 할 수 있다. strings 를 이용하면 smash-and-grab style API 키를 탐색하여 도용하기 쉽다. + +### Build Config + +Android Gradle 플러그인의 BuildConfig에서 숨길수도 있다. + + // build.gradle + buildTypes { + debug { + minifyEnabled true + buildConfigField "String", "groupName", "\"${groupName}\"" + buildConfigField "String", "groupGithub", "\"${groupGithub}\"" + } + } + + + + // gradle.properties + groupName=ADD + groupGithub=https://github.com/AndroidDeepDive + +버전 관리 시스템에 비밀이 노출될 위험을 최소화할 수 있는 장점이 있긴 하지만 BuildConfig 코드로 방출되기 때문에 쉽게 노출될 수 있다. + +### Native C/C++ JNI + +데이터를 Java 에서 네이티브 라이브러리로 옮기는 전략으로 여러 계층의 복잡서을 추가하기 때문에 리버스 엔지니어링 시도를 방해하는데 더 효과적인 전략중 하나이다. 하지만 여전히 완벽한 방법은 아니며, strings 을 통해 문자열에 취약점을 발견할 수 있다. + + + + + +[https://rammic.github.io/2015/07/28/hiding-secrets-in-android-apps/](https://rammic.github.io/2015/07/28/hiding-secrets-in-android-apps/) + +[https://medium.com/google-developer-experts/a-follow-up-on-how-to-store-tokens-securely-in-android-e84ac5f15f17](https://medium.com/google-developer-experts/a-follow-up-on-how-to-store-tokens-securely-in-android-e84ac5f15f17) \ No newline at end of file