하드웨어 래핑 키

대부분의 디스크 및 파일 암호화 소프트웨어처럼 Android의 저장소 암호화는 일반적으로 암호화를 실행할 수 있도록 시스템 메모리에 있는 원시 암호화 키를 사용합니다. 소프트웨어가 아닌 전용 하드웨어에서 암호화를 실행하더라도 소프트웨어는 일반적으로 원시 암호화 키를 계속 관리해야 합니다.

이는 일반적으로 문제로 간주하지 않습니다. 저장소 암호화로 방어해야 하는 주요 공격 유형인 오프라인 공격 중에 키가 존재하지 않기 때문입니다. 그러나 콜드 부팅 공격과 같은 다른 유형의 공격이나 공격자가 기기를 완전히 손상하지 않고 시스템 메모리를 누수할 수 있는 온라인 공격으로부터 보호를 강화하고자 합니다.

이 문제를 해결하기 위해 Android 11에서는 하드웨어 지원이 있는 하드웨어 래핑 키 지원을 도입했습니다. 하드웨어 래핑 키는 전용 하드웨어에 원시 형식으로만 알려진 저장소 키입니다. 소프트웨어는 이러한 키를 래핑된(암호화된) 형식으로만 확인하여 사용합니다. 이 하드웨어는 저장소 키를 생성 및 가져오고 저장소 키를 임시 및 장기 형식으로 래핑하며 하위 키를 파생하고 하위 키 하나를 인라인 암호화 엔진에 직접 프로그래밍하고 별도의 하위 키를 소프트웨어에 반환할 수 있어야 합니다.

참고: 인라인 암호화 엔진 (또는 인라인 암호화 하드웨어)은 데이터가 저장소 기기로 들어가거나 기기에서 나오는 동안 데이터를 암호화/복호화하는 하드웨어를 의미합니다. 이는 일반적으로 상응하는 JEDEC 사양에서 정의된 암호화 확장 프로그램을 구현하는 UFS 또는 eMMC 호스트 컨트롤러입니다.

계획

이 섹션에서는 필요한 하드웨어 지원을 포함하여 하드웨어 래핑 키 기능의 디자인을 설명합니다. 이 설명에서는 파일 기반 암호화 (FBE)에 중점을 두지만 솔루션은 메타데이터 암호화에도 적용됩니다.

인라인 암호화 엔진의 키 슬롯에만 키를 유지하면 시스템 메모리에 원시 암호화 키가 없어도 됩니다. 그러나 이 방법에는 다음과 같은 문제가 있습니다.

  • 암호화 키 수가 키 슬롯 수를 초과할 수 있습니다.
  • 인라인 암호화 엔진은 일반적으로 저장소 호스트 컨트롤러가 재설정되면 키슬롯의 콘텐츠가 손실됩니다. 스토리지 호스트 컨트롤러 재설정은 특정 유형의 스토리지 오류가 발생할 때 실행되는 표준 오류 복구 절차이며 이러한 오류는 언제든지 발생할 수 있습니다. 따라서 인라인 암호화가 사용되는 경우 운영체제는 사용자 개입 없이 항상 키 슬롯을 다시 프로그래밍할 준비가 되어 있어야 합니다.
  • 인라인 암호화 엔진은 디스크의 전체 데이터 블록을 암호화/복호화하는 데만 사용할 수 있습니다. 그러나 FBE의 경우 소프트웨어가 파일 이름 암호화와 키 식별자 파생 등 다른 암호화 작업을 계속 실행할 수 있어야 합니다. 소프트웨어가 이러한 다른 작업을 실행하려면 계속 원시 FBE 키에 액세스해야 합니다.

이러한 문제를 방지하기 위해 저장소 키가 대신 하드웨어 래핑 키로 만들어지고 전용 하드웨어에서만 래핑 해제하여 사용할 수 있습니다. 따라서 무제한의 키를 지원할 수 있습니다. 또한 키 계층 구조가 수정되어 이 하드웨어로 부분적으로 이동하므로 인라인 암호화 엔진을 사용할 수 없는 작업을 위해 소프트웨어에 하위 키를 반환할 수 있습니다.

키 계층 구조

키는 HKDF와 같은 키 파생 함수 (KDF)를 사용하여 다른 키에서 파생될 수 있으므로 키 계층 구조가 생성됩니다.

다음 다이어그램은 하드웨어 래핑 키가 사용되지 않을 때 FBE의 일반적인 키 계층 구조를 보여줍니다.

FBE 키 계층 구조(표준)
그림 1. FBE 키 계층 구조(표준)

FBE 클래스 키는 Android가 Linux 커널에 전달하여 특정 Android 사용자의 사용자 인증 정보 암호화 저장소 등 암호화된 특정 디렉터리 세트를 잠금 해제하는 원시 암호화 키입니다. 커널에서는 이 키를 fscrypt 마스터 키라고 합니다. 이 키에서 커널은 다음 하위 키를 파생합니다.

  • 키 식별자. 암호화에 사용되지 않지만 특정 파일이나 디렉터리를 보호하는 키를 식별하는 데 사용되는 값입니다.
  • 파일 콘텐츠 암호화 키
  • 파일 이름 암호화 키

반대로 다음 다이어그램은 하드웨어 래핑 키가 사용될 때 FBE의 키 계층 구조를 보여줍니다.

FBE 키 계층 구조(하드웨어 래핑 키 포함)
그림 2. FBE 키 계층 구조(하드웨어 래핑 키 포함)

앞의 사례와 비교할 때 키 계층 구조에 레벨이 추가되고 파일 콘텐츠 암호화 키가 재배치되었습니다. 루트 노드는 여전히 Android가 Linux에 전달하여 암호화된 디렉터리 세트를 잠금 해제하는 키를 나타냅니다. 그러나 이제 키가 임시 래핑 형식이므로 키를 사용하려면 전용 하드웨어에 전달해야 합니다. 이 하드웨어는 임시 래핑 키를 사용하는 인터페이스를 두 개 구현해야 합니다.

  • inline_encryption_key를 파생하여 인라인 암호화 엔진의 키슬롯에 직접 프로그래밍하는 인터페이스. 이를 통해 소프트웨어가 원시 키에 액세스하지 않고도 파일 콘텐츠를 암호화/복호화할 수 있습니다. Android 일반 커널에서 이 인터페이스는 저장소 드라이버에서 구현해야 하는 blk_crypto_ll_ops::keyslot_program 작업에 상응합니다.
  • Linux에서 파일 콘텐츠 암호화를 제외한 모든 항목의 하위 키를 파생하는 데 사용하는 키인 sw_secret ('소프트웨어 보안 비밀' - 이전에는 '원시 보안 비밀'이라고 함)를 파생하고 반환하는 인터페이스. Android 일반 커널에서 이 인터페이스는 저장소 드라이버에서 구현해야 하는 blk_crypto_ll_ops::derive_sw_secret 작업에 상응합니다.

원시 저장소 키에서 inline_encryption_keysw_secret을 파생하려면 하드웨어가 암호화 방식이 강력한 KDF를 사용해야 합니다. 이 KDF는 암호화 권장사항을 따라야 합니다. 보안 강도가 256비트 이상, 즉 나중에 사용되는 알고리즘에 충분해야 합니다. 결과 하위 키의 암호화 방식이 격리되도록, 즉 하위 키 중 하나에 관한 지식이 다른 키를 노출하지 않도록 하려면, 각 유형의 하위 키를 파생할 때 고유한 라벨과 컨텍스트도 사용해야 합니다. 원시 저장소 키가 이미 균일한 임의의 키이므로 키 확장은 필요하지 않습니다.

기술적으로 보안 요구사항을 충족하는 모든 KDF를 사용할 수 있습니다. 그러나 테스트 목적으로 vts_kernel_encryption_test는 소프트웨어에서 동일한 KDF를 구현하여 디스크의 암호문을 재현하고 올바른지 확인합니다. 테스트를 쉽게 하고 안전하고 이미 검토된 KDF가 사용되도록 하려면 하드웨어에서 테스트에서 확인하는 기본 KDF를 구현하는 것이 좋습니다. 다른 KDF를 사용하는 하드웨어의 경우 이에 따라 테스트를 구성하는 방법은 래핑된 키 테스트를 참고하세요.

키 래핑

하드웨어 래핑 키의 보안 목표를 충족하기 위해 두 가지 유형의 키 래핑을 정의합니다.

  • 임시 래핑: 하드웨어는 부팅할 때마다 무작위로 생성되고 하드웨어 외부에 직접 노출되지 않는 키를 사용하여 원시 키를 암호화합니다.
  • 장기 래핑: 하드웨어는 하드웨어 외부에 직접 노출되지 않는 하드웨어에 내장된 고유한 영구 키를 사용하여 원시 키를 암호화합니다.

Linux 커널에 전달되어 저장소를 잠금 해제하는 모든 키는 임시 래핑됩니다. 이렇게 하면 공격자가 시스템 메모리에서 사용 중인 키를 추출할 수 있는 경우 기기 외부는 물론 재부팅 후에 기기에서도 키를 사용할 수 없게 됩니다.

동시에 Android는 먼저 잠금 해제할 수 있도록 암호화된 버전의 키를 디스크에 여전히 저장할 수 있어야 합니다. 원시 키가 이러한 용도에 적합합니다. 그러나 원시 키가 시스템 메모리에 아예 존재하지 않도록 하여 부팅 시 추출되더라도 기기 외부에서 사용하기 위해 추출될 수 없도록 하는 것이 좋습니다. 이러한 이유로 장기 래핑 개념이 정의됩니다.

이 두 가지 방법으로 래핑된 키 관리를 지원하려면 하드웨어가 다음 인터페이스를 구현해야 합니다.

  • 저장소 키를 생성하고 가져와 장기 래핑 형식으로 반환하는 인터페이스. generate 인터페이스는 vold에서 Android에서 사용할 새 저장소 키를 생성하는 데 사용됩니다. import 인터페이스는 vts_kernel_encryption_test에서 테스트 키를 가져오는 데 사용됩니다.
  • 장기 래핑 저장소 키를 임시 래핑 저장소 키로 변환하는 인터페이스. 이 인터페이스는 voldvts_kernel_encryption_test 모두에서 저장소를 잠금 해제하는 데 사용됩니다.

키 래핑 알고리즘은 구현 세부정보이지만 임의의 IV가 포함된 AES-256-GCM과 같은 강력한 AEAD를 사용해야 합니다.

소프트웨어 변경 필요

AOSP에는 하드웨어 래핑 키를 지원하는 기본 프레임워크가 이미 있습니다. 여기에는 vold와 같은 사용자 공간 구성요소 지원 및 blk-crypto, fscrypt, dm-default-key의 Linux 커널 지원이 포함됩니다.

Linux 커널 변경사항

인라인 암호화 지원이 있는 기기의 스토리지 컨트롤러용 Linux 커널 드라이버를 수정하여 하드웨어 래핑 키를 지원해야 합니다.

android17 이상 커널의 경우:

  • blk_crypto_profile::key_types_supported에서 BLK_CRYPTO_KEY_TYPE_HW_WRAPPED를 설정합니다.
  • blk_crypto_ll_ops::keyslot_program가 하드웨어 래핑 키 프로그래밍을 지원하도록 합니다.
  • blk_crypto_ll_ops::keyslot_evict가 하드웨어 래핑 키 제거를 지원하도록 합니다.
  • blk_crypto_ll_ops::derive_sw_secret, blk_crypto_ll_ops::import_key, blk_crypto_ll_ops::generate_key, blk_crypto_ll_ops::prepare_key를 구현합니다.

android14, android15, android16 커널의 경우:

  • blk_crypto_profile::key_types_supported에서 BLK_CRYPTO_KEY_TYPE_HW_WRAPPED를 설정합니다.
  • blk_crypto_ll_ops::keyslot_program가 하드웨어 래핑 키 프로그래밍을 지원하도록 합니다.
  • blk_crypto_ll_ops::keyslot_evict가 하드웨어 래핑 키 제거를 지원하도록 합니다.
  • blk_crypto_ll_ops::derive_sw_secret를 구현합니다.

android12android13 커널의 경우:

  • blk_keyslot_manager::features에서 BLK_CRYPTO_FEATURE_WRAPPED_KEYS를 설정합니다.
  • blk_ksm_ll_ops::keyslot_program가 하드웨어 래핑 키 프로그래밍을 지원하도록 합니다.
  • blk_ksm_ll_ops::keyslot_evict가 하드웨어 래핑 키 제거를 지원하도록 합니다.
  • blk_ksm_ll_ops::derive_raw_secret를 구현합니다.

android11 커널의 경우:

  • keyslot_manager::features에서 BLK_CRYPTO_FEATURE_WRAPPED_KEYS를 설정합니다.
  • keyslot_mgmt_ll_ops::keyslot_program가 하드웨어 래핑 키 프로그래밍을 지원하도록 합니다.
  • keyslot_mgmt_ll_ops::keyslot_evict가 하드웨어 래핑 키 제거를 지원하도록 합니다.
  • keyslot_mgmt_ll_ops::derive_raw_secret를 구현합니다.

KeyMint 변경사항 (이전)

현재 버전의 하드웨어 래핑 키 (wrappedkey)에서 하드웨어 래핑 키의 생성, 가져오기, 준비는 Linux 커널 ioctl BLKCRYPTOGENERATEKEY, BLKCRYPTOIMPORTKEY, BLKCRYPTOPREPAREKEY을 사용합니다. 이러한 ioctl은 struct blk_crypto_ll_ops의 메서드에 해당합니다. 스토리지 드라이버는 이러한 메서드를 구현하고 키 래핑 하드웨어와 통신하여 요청된 작업을 실행합니다. 이러한 ioctl에 관한 자세한 내용은 Linux 커널 문서를 참고하세요.

이러한 ioctl은 Linux 6.16에 추가되었습니다. ioctl 기반 솔루션으로 출시되지 않은 기기에서는 Android KeyMint (또는 이전 KeyMaster)를 사용하는 다른 솔루션이 사용됩니다. 기존 솔루션 (wrappedkey_v0)은 메인라인 Linux 커널 또는 현재 솔루션과 호환되지 않습니다. 기존 솔루션은 다음 KeyMint 기능을 사용합니다.

  • 키 생성 및 가져오기 모두에 TAG_STORAGE_KEY 지원
  • convertStorageKeyToEphemeral 메서드 지원

이 KeyMint 기능은 fstab 파일에서 wrappedkey_v0에 해당하는 기존 솔루션을 사용하는 기기에서만 필요합니다.

fstab 파일에서 wrappedkey에 해당하는 현재 솔루션을 사용하는 기기는 이 KeyMint 기능을 구현할 필요가 없습니다.

래핑된 키 테스트

하드웨어 래핑 키를 사용한 암호화는 원시 키를 사용한 암호화보다 테스트하기가 더 어렵지만 테스트 키를 가져오고 하드웨어에서 실행하는 키 파생을 다시 구현하여 여전히 테스트할 수 있습니다. vts_kernel_encryption_test에서 구현됩니다. 이 테스트를 실행하려면 다음을 실행하세요.

atest -v vts_kernel_encryption_test

테스트 로그를 읽고 하드웨어 래핑 키 지원이 감지되지 않아서 하드웨어 래핑 키 테스트 사례 (예: FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicyDmDefaultKeyTest.TestHwWrappedKey)를 건너뛰지 않았는지 확인합니다. 이 경우 테스트 결과는 여전히 '통과됨'입니다.

기본적으로 vts_kernel_encryption_test는 하드웨어가 kdf1이라고 하는 KDF를 구현한다고 가정합니다. 이 KDF는 NIST SP 800-108의 카운터 모드 KDF 계열에 속하며 AES-256-CMAC를 의사 난수 함수로 사용합니다. CMAC에 관한 자세한 내용은 CMAC 사양을 참고하세요. KDF는 각 하위 키를 파생할 때 특정 컨텍스트와 라벨을 사용합니다. 하드웨어는 각 하위 키를 파생할 때 컨텍스트, 라벨, 고정 입력 문자열의 형식의 정확한 선택을 비롯하여 이 KDF를 구현해야 합니다.

하지만 vts_kernel_encryption_testkdf4를 통해 추가 KDF kdf2도 구현합니다. 이는 kdf1만큼 안전하며 컨텍스트, 라벨, 고정 입력 문자열의 형식 선택만 다릅니다. 이러한 레이어는 다양한 하드웨어를 수용하기 위해서만 존재합니다.

다른 KDF를 사용하는 기기의 경우 PRODUCT_VENDOR_PROPERTIES에서 ro.crypto.hw_wrapped_keys.kdf 시스템 속성을 테스트 소스 코드에 정의된 KDF 이름으로 설정합니다. 이렇게 하면 vts_kernel_encryption_testkdf1 대신 해당 KDF를 확인합니다. 예를 들어 kdf2을 선택하려면 다음을 사용합니다.

PRODUCT_VENDOR_PROPERTIES += ro.crypto.hw_wrapped_keys.kdf=kdf2

테스트에서 지원하지 않는 KDF를 사용하는 기기의 경우 해당 KDF의 구현을 테스트에 추가하고 고유한 이름을 지정합니다.

래핑된 키 사용 설정

기기의 하드웨어 래핑 키 지원이 올바르게 작동하면 Android에서 FBE 및 메타데이터 암호화에 사용하도록 기기의 fstab 파일을 다음과 같이 변경합니다.

  • FBE: wrappedkey (또는 기존 버전의 경우 wrappedkey_v0) 플래그를 fileencryption 매개변수에 추가합니다. 예를 들어 fileencryption=::inlinecrypt_optimized+wrappedkey을 사용합니다. 자세한 내용은 FBE 문서를 참고하세요.
  • 메타데이터 암호화: wrappedkey 플래그 (또는 기존 버전의 경우 wrappedkey_v0)를 metadata_encryption 매개변수에 추가합니다. 예를 들어 metadata_encryption=:wrappedkey을 사용합니다. 자세한 내용은 메타데이터 암호화 문서를 참고하세요.

각 경우에 플래그에는 두 가지 버전이 있습니다.

  • Android 17 이상에서 지원되는 wrappedkey는 하드웨어 래핑 키의 현재 버전을 지원합니다. 이 버전은 메인라인 Linux 커널과 호환됩니다.
  • Android 11 이상에서 지원되는 wrappedkey_v0는 하드웨어 래핑 키의 기존 버전을 사용 설정합니다. 이 버전은 메인라인 Linux 커널과 호환되지 않습니다. KeyMint를 통해 특정 작업을 프록시하고 비표준 온디스크 형식을 사용합니다. 자세한 내용은 KeyMint 변경사항 (레거시)을 참고하세요.

Android 17 이상으로 출시되는 기기에서는 wrappedkey를 선호합니다.

이미 wrappedkey_v0로 출시된 기기에서는 이전 버전과의 호환성을 위해 wrappedkey_v0를 계속 사용합니다.