Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
123 changes: 123 additions & 0 deletions 008. KeyStore System and Security/namhoonkim_01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# KeyStore System and Security Part 0 : Keyword List

### Encrypt/Decrypt (암호화 / 복호화)

암호학은 정보를 보호하기 위해서 언어학적 방법론과 수학적 방법론을 다루는 학문이다.

이 암호학의 최종 목표가 바로 암호화이다.

암호화를 통해 보호해야할 데이터(혹은 메시지)가 있다고 할때, 이를 **Plaintext(평문)** 이라고 한다.

이 평문을 암호화 알고리즘을 이용해 변환한 것을 **Ciphertext(암호문)** 라고 한다.

이때 평문을 암호문으로 변환화는 과정을 **Encryption(암호화)** 라고 하며, 반대로 암호문을 평문으로 변환하는 과정을 **Decryption(복호화)** 라고 한다.

### Symmetric Key (대칭키)

대칭키 암호는 다른 말로 **비밀키** 암호라고도 한다.

대칭키 암호는 암호화와 복호화를 수행하는 키가 동일한 암호를 말한다.

**Kerkhoffs's principle (커코프 원칙)**

커코프 원칙이란 암호 시스템의 안정성은 암호화 알고리즘이 아니라 암호키의 비밀에만 의존해야한다는 법칙을 말한다.

만약 여러 사람이 사용하는 시스템에서 대칭키를 사용한다면 모든 사람은 같은 알고리즘을 쓰고 있을 것이고, 비밀성을 유지하는 것이 어려워지므로, 암호화 알고리즘의 비밀성이 주는 안정성은 의미가 없어진다.

따라서 암호 시스템의 안정성은 알고리즘이 아닌 키의 비밀성에 의존해야 한다.

#### Block Cipher

대칭키를 이용한 암호화 방법 중 **Block cipher(블록 암호)** 라는 개념이 존재한다.

이는 암호문을 생성하기 위해 암호화에 사용되는 키와 알고리즘이 데이터 블록 단위로 적용되는 방식이다.

이러한 방식을 사용하는 이유는 평문을 일정한 길이의 블록으로 분할하여 전치와 치환을 반복함으로서 키에 대한 정보를 유추할 수 없도록 하는 데 있다.

#### 대칭키 암호의 종류
**DES : Data Encryption Standard**
- 64-bit 단위의 블록 암호로 56-bit 길이의 대칭키를 사용한다.
- 한때 미국 표준 블록 암호 알고리즘이었으나, 안정성에 문제가 있어 AES로 표준이 교체되었다.
- 현재 신규 암호화를 진행할때에는 **절대로 사용해서는 안되는 알고리즘** 이다.

**AES : Advanced Encryption Standard**
- 현재 미국 표준 블록 암호 알고리즘이다.
- 가장 유명한 알고리즘으로 당연하겠지만 가장 긴 블록 길이인 AES-256이 권장된다.

### Hash(해시)

해시 함수는 임의의 크기를 가진 데이텉 입력 받아 고정된 크기의 결과값을 출력하는 함수이다.

해시는 암호학뿐만 아니라 여러 분야에서 사용되며, **단방향성** 이라는 특성과 **충돌** 이라는 특성이 있다.

단방향성이란 입력값으로 결과값을 계산하기는 쉽지만, 결과값을 가지고 입력값을 유추하기 어려운 특성을 말한다.

즉 원문 메시지로 해시값을 생성하는 것은 쉽지만, 해시값을 통해 원문 메시지를 유추하는 것은 어렵다.

충돌이란, 입력값이 다르더라도 동일한 결과값이 생성될 수 있는 특성을 말한다.

해시 자체가 고정된 크기의 결과값을 출력해주기때문에, 표현할 수 있는 값이 한정되어있기때문에 발생하는 것이다.

#### MessageDigest

흔히 줄여서 MD라고도 하며, MD5 알고리즘이 가장 유명하다.

다만 MD5도 취약점이 있으므로 최소 SHA-256을 쓰는 것이 권장된다.

#### Checksum (체크섬)

해시 함수는 일반적으로 데이터의 체크섬을 생성하기 위해서 사용한다.

이 체크섬은 내려받은 파일이 정상인지 아닌지 판단하기 위하여 사용한다.

### MAC : Message Authentication Code(메시지 인증 코드)

메시지 인증 코드는 말 그대로 메시지를 인증할 때 쓰이는 값을 말한다.

MAC값을 이용해 메시지의 데이터에 대한 인증을 물론 무결성을 증명한다.

다만, MAC을 중간자가 탈취하는 경우 메시지를 변조하고 이를 통해 새로운 MAC을 만들어 보낼 수도 있기에 취약점이 존재한다.

이를 방지하기 위해 다양한 MAC들이 존재한다.

#### CMAC :Cipher-based Message Authentication Code

CMAC은 메시지를 암호화하는 과정에서 주어진 값을 MAC으로 사용한다.

다만, 메시지에 대한 암호화를 무조건 수행해야 한다는 단점이 있다.

#### HMAC : Hash-based Authentication Function

HMAC은 메시지에 대한 암호화없이 MAC을 얻는 방법 중 하나이다.

키와 메시지를 합친 뒤 해시하여 얻어지는 값을 MAC으로 사용하는 방법인데, 이 또한 데이터를 주고 받는 양쪽에 사전 공유된 비밀키가 있어야 한다.

### Asymmetric Key (비대칭키)

비대칭키 암호화는 대칭키 암호화과 달리 키가 한 쌍이다.

이 키는 **Public Key(공개키)** 와 **Private Key(개인키)** 로 구분되며 이를 이용한 암호화를 비대칭키 암호화 혹은 공개키 암호화라고 한다.

비대칭키 암호화 또한 취약점이 없는 것은 아니나, 계산 복잡도에 매우 많은 시간을 요구하게끔 만들어졌으며 같은 키를 공유하는 대칭키 암호화에 비해 키 관리가 상대적으로 편하다는 장점이 있다.

데이터를 공개키로 암호화하고, 암호화된 메시지는 개인키로 복호화하는 방식으므로 복호화를 위해선 무조건 개인키를 가지고 있어야 한다.

**Diffie-Hallman key exchange**

디피헬먼 키 교환은 비대칭키 암호화의 키를 교환하는 방법을 뜻한다.

이산대수 연산을 기반으로 송신자와 수신자간의 비밀키를 공유하며, 지수 키 교환이라고도 불린다.

#### RSA : Ronald-Shamir-Adleman

세계적으로 가장 많이 쓰이는 공개키 암호화 방식이다.

큰 정수를 소인수 분해하기 어렵다는 수학적 법칙하에 만들어진 알고리즘이지만, 수학적 구조 안에 존재하는 알고리즘의 태생상 많은 유형의 공격이 가능하기때문에 이를 방어하기 위해 인코딩을 하거나, 암호화 스킴등의 기법이 추가로 요구 된다.

#### ECC : Elliptic Curves Cryptography

타원 곡선 알고리즘 기반의 공개키 암호화 방식이다.

평면 상의 주어진 특정한 점에 대한 무작위 타원 곡선의 이산 로그를 찾는 데 많은 시간이 소요됨을 이용해 만들어졌다.

RSA보다 짧은 키를 가지고 구현이 가능하지만, 배경 지식이 어느 정도 요구되고 구현하기가 어렵다는 단점이 존재한다.
42 changes: 42 additions & 0 deletions 008. KeyStore System and Security/namhoonkim_02.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Part 1 : What is KeyStore System?
- KeyStore 소개 및 동작 원리
- Tusted Executon Environment

### Android KeyStore Diagram

![Android KeyStore Diagram](./img/0a705587-5f56-1dda-815f-7b7e972e77cd.png)

### Android KeyStore의 보안

Android KeyStore에 저장되는 key들의 구성요소는 아래와 같은 수단으로 보호된다.

1. Application 프로세스 레벨에서 Key Material의 접근은 전면 차단되며, System Process를 통해서만 siging등의 작업을 진행할 수 있다.
2. Plaintext, Cipher, message 등은 System Process를 통해서만 접근하여 받을 수 있다.

### Hardware 기반의 KeyStore

Android의 KeyStore는 필수적으로 하드웨어 기반으로만 구현된다.

하드웨어를 통한 보안 기능은 ARM TrustZone을 통해 진행되며, RSA, ECDSA, AES, HMAC Key들은 전부 하드웨어 기반의 TrustZone에 저장된다.

개발자는 TrustZone에 관련된 API를 사용하여 현재 Key가 신뢰할만한 하드웨어 장치에 저장되어있는 지 확인할 수 있으며, 지문 인증과 같은 사용자 본인의 인증없이는 특정 데이터를 Decrypt할 수 없게 구현할 수 있다.

### TEE

![TEE](./img/0a7056be-5f56-1b2b-815f-9ad40cf930c3.png)

Android의 Key는 **TEE**(Tusted Executon Environment : 신뢰할 수 있는 실행환경)에서 바인딩되어 있으며 바인딩되어 있는 상태의 Key는 보안처리된 하드웨어 밖으로 절대 추출되지 않는다.

이 TEE는 디바이스의 메인 프로세서에 따로 할당되어 있는 영역으로 데이터의 무결성을 보장해주며, 보안 영역의 분리를 통해 해킹, 멀웨어, 루트 권한 접근으로부터 보호받을 수 있게 된다.


#### (1) 시간적 유효성 승인

GateKeeper/Fingerprint Daemon을 통해 생성한 AuthToken에 기록된 마지막 TimeStamp를 통해 시간적 유효성을 확인 후 승인한다.

#### (2) 암호화/사용자 인증 승인

Hardware 레벨에서 검증할 수 있는 수단을 통해 암호화 및 사용자 인증을 승인 한다.

* Android 7.0부터 모든 기기는 TrustZone을 탑재하며, 기기 자체에 해당 TrustZone에 접근할 수 있는 고유 Key를 지닌다.
* 위의 고유한 Key를 가지지 않으면 모든 접근은 차단된다.
9 changes: 9 additions & 0 deletions 008. KeyStore System and Security/namhoonkim_03.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# KeyStore System and Security Part 2 : Android Securty Crypto

### SharedPreferences

### EncryptedSharedPreferences

### DataStore

### Google Tink Library
61 changes: 61 additions & 0 deletions 008. KeyStore System and Security/namhoonkim_04.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# KeyStore System and Security Part 3 : Hiding strings

Android 앱을 개발하다보면 특정 key를 포함해서 배포하는 경우가 있다.

APK 파일의 특성상 기본적인 압축해제부터 디컴파일까지, 다양한 수단으로 기기의 바이너리 코드에 접근할 수 있는데,

이떄 포함된 key값이 노출될 우려가 있다.

어떻게하면 key를 숨길 수 있을까?

완벽한 보안은 없지만, 최선을 다해서 숨겨보자.

### 1. Hide in the `strings.xml`

제일 먼저 문자열을 보관하는 리소스 파일인 `strings.xml`에 숨겨보자.

아래와 같은 파일 구조로 작성이 되는 경우로 볼 수 있는데

```xml
<resources>
<string name="key">value</string>
</resources>
```

value의 일부를 알고 있는 경우, 디컴파일할 것도 없이 `grep` 명령어만 이용해도 추출할 수 있다.

디컴파일을 하게 되는 경우 `strings.xml` 파일에 원형 그대로 노출된다.

따라서 이 방법은 **패키징만 되어있을 뿐**, 보안 관점에서는 매우 나쁜 방법이다.

> jadx 예시 추가 필요

### 2. Hide in the `*.kt` (or `*.java`)

소스 코드에 숨긴다고 하여도 결국 리소스 파일과 똑같이 관리되고, 리터럴 문자열은 난독화 대상이 아니기 때문에 마찬가지로 `grep` 명령어로 추출이 가능하다.

리터럴 문자열이 아닌 별도의 `ByteArray`로 문자를 쪼개서 저장하더라도 컴파일러의 최적화로 인해 이또한 추출이 가능하다.

즉 1번과 2번 방법은 모두 보안에 신경 썼다고 말하기 어려운 방법이며, 바꾸어 말하면

숨겨야할 key(혹은 문자열)은 1번과 2번 방법으로 처리해선 안된다고도 해석할 수 있다.

### 3. Hide in the `BuildConfig.java`

`build.gradle`과 `gradle.properties`에 숨겨보는 건 어떨까?

이 또한 컴파일 후 1번, 2번 케이스와 동일해지므로 쓰면 안되는 방법이다.

### 4. Hide in the Proguard

Proguard 혹은 R8의 난독화 기능을 믿고 소스코드에 숨겨보는 건 어떨까?

key를 포함시켰다는 건, 어딘가에 해당 key를 사용하기 떄문일 것이다.

즉, key를 사용하는 메서드나 클래스등은 난독화되더라도, 중요한 key의 값은 리터럴로 관리되어서 난독화되지 않는다.

따라서 코드가 완전 공개된 것은 아닐지라도, 약간의 수고로움만 거친다면 역시 값을 찾을 수 있다.

### 5. Hide using Base64
### 6. Hide using JNI
### 7. Android KeyBox
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ Android 개발자들이 실무도중 경험한 이슈들에 대해서 공부하
**7. MVVM vs MVI (gathering)**

**8. KeyStore System and Security (~ing)**
- branch guide : `keystore/{NAME}`
- branch guide : `security/{NAME}`