HOME > android > feature

Android - File-Based Encryption과 Direct Boot

JSFollow05 Oct 2019

Encryption은 데이터를 암호화하는 과정을 말합니다. Encryption된 데이터에 접근하려면 encryption key가 있어야 합니다. 안드로이드는 다음과 같은 Encryption 정책이 있습니다. Android 10부터 File-Based Encryption만 지원하도록 하고 있습니다.

  • Full-Disk Encryption: Android 5.0 ~ 9.0까지 지원하며 디바이스의 데이터 파티션 전체를 암호화 합니다.
  • File-Based Encryption: Android 7.0부터 계속 지원하며 파일 단위로 암호화할 수 있습니다.

Direct Boot는 File-Based Encryption에 실행되는 앱을 지원하기 위한 정책입니다. 먼저 Encryption에 대해서 간단히 알아보고 Direct Boot에 대해서 알아보겠습니다.

Full-Disk Encryption

디바이스에 /system, /data 등의 파티션들이 있습니다. Encryption은 사용자의 데이터를 보호하는 것이 목적이기 때문에 /data 파티션을 암호화합니다.

Full-Disk Encryption은 /data 파티션을 통째로 암호화합니다. Encryption된 디바이스가 reboot이 되었다면, Lockscreen 화면에서 패스워드를 입력하지 않으면 /data 파티션이 decryption되지 않습니다. 앱은 /data 파티션에 접근할 수 없기 때문에 알람 등의 앱이 동작하지 않고 전화를 받을 수도 없습니다.

File-Based Encryption

Full-Disk Encryption의 단점은 /data 파티션 전체를 암호화하기 때문에 부팅 후 패스워드를 입력하지 않으면 앱이 동작하지 않는다는 것입니다. 예를 들어, 사용자가 알람을 맞추고 자는데 알 수 없는 오류로 reboot이 되었다면 알람은 울리지 않게 됩니다.

File-Based Encryption은 이런 단점을 해결하기 위해 도입되었습니다. File 단위로 다른 key로 암호화합니다. 부팅 후 패스워드가 입력되기 전에 앱이 사용할 수 있는 공간을 미리 decryption하고, 패스워드가 입력되면 모든 /data 파티션을 decryption하는 것입니다. 알람 앱은 패스워드가 입력 안되었더라도, 미리 decryption된 데이터 영역을 이용하기 때문에 동작이 됩니다.

다음은 디바이스에서 미리 decryption되는 폴더의 패스입니다. 아래 영역은 패스워드를 입력하기 전에 decryption되는 영역입니다.

  • /data/user_de/
  • /data/system_de/
  • /data/vendor_de/

다음은 패스워드를 입력해야 decryption되는 영역입니다.

  • /data/user_ce/
  • /data/system_ce/
  • /data/vendor_ce/

DE와 CE의 의미는 다음과 같습니다.

  • DE: Credential Encrypted storage
  • CE: Device Encrypted storage

Direct Boot

Direct Boot는 File-Based Encryption을 지원하기 위한 정책입니다. Direct Boot라는 정책을 디바이스에서 지원하지 않는다면 File-Based Encryption을 사용할 수 없습니다.

부팅 후 사용자가 패스워드를 입력했다면 Device가 Unlock되었다고 합니다. 패스워드를 입력하지 않았다면 Device가 Lock되었다고 합니다.

Direct Boot는 디바이스가 Lock인 상태에서 앱이 동작하도록 도와줍니다. Unlock 상태가 되면 모든 앱이 실행될 수 있습니다.

기본적으로 앱이 아무 설정도 하지 않는다면 시스템은 Lock 상태에서 이 앱을 실행하지 않습니다. 만약 알람앱 처럼 Lock 상태에서 실행되고 싶은 앱이 있다면 앱의 AndroidManifest에 몇가지 설정을 해줘야 합니다.

다음과 같이 directBootAware=true는 Lock일 때 실행가능하도록 만들고, Component마다 설정을 할 수 있습니다. 부팅이 완료되고 Lock 상태일 때 LOCKED_BOOT_COMPLETED인텐트가 전달됩니다. 이 인텐트를 받고 액티비티를 띄우거나 서비스를 실행하거나 할 수 있습니다.

<receiver
  android:directBootAware="true" >
  ...
  <intent-filter>
    <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
  </intent-filter>
</receiver>

데이터 접근

Unlock 상태일 때 앱이 접근한 데이터 영역은 /data/user_ce/입니다. Context.getDataDir() 등의 코드로 이 패스를 가져왔을 것입니다.

만약 Lock 상태일 때 앱이 실행되었다면 이 영역은 접근이 불가능합니다. Context.getDataDir()로 패스를 가져와서 접근하려고 하면 File Not Found 등의 Exception이 발생할 수 있습니다.

Lock 상태일 때는 /data/user_de/에 접근을 해야 합니다. 이 패스를 얻는 방법은 아래와 같은 코드를 사용해야 합니다.

Context directBootContext = appContext.createDeviceProtectedStorageContext();

데이터 마이그레이션

자, 이제 Unlock일 때는 CE라는 데이터 영역에 접근했고, Lock일 때는 DE라는 데이터 영역에 접근해야 한다는 것을 알았습니다. 하지만 DE에 접근한다고 해도, 지금까지 CE에만 데이터를 저장했기 때문에 아무 파일이 없을 텐데요.

DE에서 사용할 데이터를 틈틈이 옴겨줘야 합니다. 다음 API는 데이터를 CE에서 DE 옴겨주는데 도와주는 API입니다.

  • Context.moveSharedPreferencesFrom()
  • Context.moveDatabaseFrom()

파일이 필요하다면, Context.createDeviceProtectedStorageContext()로 DE 데이터 패스를 얻고 파일을 복사할 수 있습니다.

Lock or Unlock 상태 확인

앱이 현재 디바이스가 Lock 상태인지 궁금할 수 있습니다. UserManager.isUserUnlocked() API는 현재 디바이스의 상태를 boolean으로 리턴해줍니다.

그리고 Unlock이 되었을 때 Intent.ACTION_USER_UNLOCKED인텐트도 전달됩니다.

정리

Andorid 10에서는 File-Based Encryption만 지원됩니다. Direct Boot라는 말이 뭔가 어려운 말 처럼 느껴지지만 Lock 상태일 때 앱이 실행될 수 있도록 도와주는 기능입니다. 일반적인 앱이라면 디바이스가 Lock 상태일 때 실행될 필요는 없을 것입니다. 모르셔도 상관없지만 안드로이드가 어떻게 동작하는지 이해하는데 도움이 될 수 있습니다.

참고