대부분의 디스크 및 파일 암호화 소프트웨어처럼 Android의 저장소 암호화는 일반적으로 암호화를 실행할 수 있도록 시스템 메모리에 있는 원시 암호화 키를 사용합니다. 소프트웨어가 아닌 전용 하드웨어에서 암호화를 실행하더라도 소프트웨어는 일반적으로 원시 암호화 키를 계속 관리해야 합니다.
이는 일반적으로 문제로 간주하지 않습니다. 저장소 암호화로 방어해야 하는 주요 공격 유형인 오프라인 공격 중에 키가 존재하지 않기 때문입니다. 그러나 콜드 부팅 공격과 같은 다른 유형의 공격이나 공격자가 기기를 완전히 손상하지 않고 시스템 메모리를 누수할 수 있는 온라인 공격으로부터 보호를 강화하고자 합니다.
이 문제를 해결하기 위해 Android 11에서는 하드웨어 지원이 있는 하드웨어 래핑 키 지원을 도입했습니다. 하드웨어 래핑 키는 전용 하드웨어에 원시 형식으로만 알려진 저장소 키입니다. 소프트웨어는 이러한 키를 래핑된(암호화된) 형식으로만 확인하여 사용합니다. 이 하드웨어는 저장소 키를 생성 및 가져오고 저장소 키를 임시 및 장기 형식으로 래핑하며 하위 키를 파생하고 하위 키 하나를 인라인 암호화 엔진에 직접 프로그래밍하고 별도의 하위 키를 소프트웨어에 반환할 수 있어야 합니다.
참고: 인라인 암호화 엔진(또는 인라인 암호화 하드웨어)은 데이터가 저장소 기기로 들어가거나 기기에서 나오는 동안 데이터를 암호화/복호화하는 하드웨어를 의미합니다. 이는 일반적으로 상응하는 JEDEC 사양에서 정의된 암호화 확장 프로그램을 구현하는 UFS 또는 eMMC 호스트 컨트롤러입니다.
디자인
이 섹션에서는 필요한 하드웨어 지원을 포함하여 하드웨어 래핑 키 기능의 디자인을 설명합니다. 이 설명에서는 파일 기반 암호화 (FBE)에 중점을 두지만 솔루션은 메타데이터 암호화에도 적용됩니다.
인라인 암호화 엔진의 키 슬롯에만 키를 유지하면 시스템 메모리에 원시 암호화 키가 없어도 됩니다. 그러나 이 방법에는 다음과 같은 문제가 있습니다.
- 암호화 키 수가 키 슬롯 수를 초과할 수 있습니다.
- 인라인 암호화 엔진은 디스크의 전체 데이터 블록을 암호화/복호화하는 데만 사용할 수 있습니다. 그러나 FBE의 경우 소프트웨어가 파일 이름 암호화와 키 식별자 파생 등 다른 암호화 작업을 계속 실행할 수 있어야 합니다. 소프트웨어가 이러한 작업을 실행하려면 계속 원시 FBE 키에 액세스해야 합니다.
이러한 문제를 방지하기 위해 저장소 키가 대신 하드웨어 래핑 키로 만들어지고 전용 하드웨어에서만 래핑 해제하여 사용할 수 있습니다. 따라서 무제한의 키를 지원할 수 있습니다. 또한 키 계층 구조가 수정되어 이 하드웨어로 부분적으로 이동하므로 인라인 암호화 엔진을 사용할 수 없는 작업을 위해 소프트웨어에 하위 키를 반환할 수 있습니다.
키 계층 구조
키는 HKDF와 같은 KDF(키 파생 함수)를 사용하여 다른 키에서 파생될 수 있으므로 키 계층 구조가 생성됩니다.
다음 다이어그램은 하드웨어 래핑 키가 사용되지 않을 때 FBE의 일반적인 키 계층 구조를 보여줍니다.
FBE 클래스 키는 Android가 Linux 커널에 전달하여 특정 Android 사용자의 사용자 인증 정보 암호화 저장소 등 암호화된 특정 디렉터리 세트를 잠금 해제하는 원시 암호화 키입니다. 커널에서는 이 키를 fscrypt 마스터 키라고 합니다. 이 키에서 커널은 다음 하위 키를 파생합니다.
- 키 식별자. 암호화에 사용되지 않지만 특정 파일이나 디렉터리를 보호하는 키를 식별하는 데 사용되는 값입니다.
- 파일 콘텐츠 암호화 키
- 파일 이름 암호화 키
반대로 다음 다이어그램은 하드웨어 래핑 키가 사용될 때 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_key
와 sw_secret
을 파생하려면 하드웨어가 암호화 방식이 강력한 KDF를 사용해야 합니다. 이 KDF는 암호화 권장사항을 따라야 합니다.보안 강도가 256비트 이상, 즉 나중에 사용되는 알고리즘에 충분해야 합니다. 각 유형의 하위 키를 파생할 때 결과 하위 키의 암호화 방식이 격리되도록, 즉 하위 키 중 하나에 관한 지식이 다른 키를 노출하지 않도록 하려면, 고유한 라벨과 컨텍스트, 애플리케이션별 정보 문자열도 사용해야 합니다. 키 확장은 필요하지 않습니다. 원시 저장소 키가 이미 균일한 임의의 키이기 때문입니다.
기술적으로 보안 요구사항을 충족하는 모든 KDF를 사용할 수 있습니다.
그러나 테스트 목적으로 같은 KDF를 테스트 코드에서 다시 구현해야 합니다. 현재 KDF 하나를 검토하고 구현했습니다. vts_kernel_encryption_test
의 소스 코드에서 확인할 수 있습니다.
하드웨어는 PRF로 AES-256-CMAC와 함께 NIST SP 800-108 'KDF in Counter Mode'를 사용하는 KDF를 사용하는 것이 좋습니다. 호환 가능하려면 각 하위 키의 KDF 컨텍스트 및 라벨 선택을 비롯하여 알고리즘의 모든 부분이 동일해야 합니다.
키 래핑
하드웨어 래핑 키의 보안 목표를 충족하기 위해 두 가지 유형의 키 래핑을 정의합니다.
- 임시 래핑: 하드웨어는 부팅할 때마다 무작위로 생성되고 하드웨어 외부에 직접 노출되지 않는 키를 사용하여 원시 키를 암호화합니다.
- 장기 래핑: 하드웨어는 하드웨어 외부에 직접 노출되지 않는 하드웨어에 내장된 고유한 영구 키를 사용하여 원시 키를 암호화합니다.
Linux 커널에 전달되어 저장소를 잠금 해제하는 모든 키는 임시 래핑됩니다. 이렇게 하면 공격자가 시스템 메모리에서 사용 중인 키를 추출할 수 있는 경우 기기 외부는 물론 재부팅 후에 기기에서도 키를 사용할 수 없게 됩니다.
동시에 Android는 먼저 잠금 해제할 수 있도록 암호화된 버전의 키를 디스크에 여전히 저장할 수 있어야 합니다. 원시 키가 이러한 용도에 적합합니다. 그러나 원시 키가 시스템 메모리에 아예 존재하지 않도록 하여 부팅 시 추출되더라도 기기 외부에서 사용하기 위해 추출될 수 없도록 하는 것이 좋습니다. 이러한 이유로 장기 래핑 개념이 정의됩니다.
이 두 가지 방법으로 래핑된 키 관리를 지원하려면 하드웨어가 다음 인터페이스를 구현해야 합니다.
- 저장소 키를 생성하고 가져와 장기 래핑 형식으로 반환하는 인터페이스. 이러한 인터페이스는 KeyMint를 통해 간접적으로 액세스되고
TAG_STORAGE_KEY
KeyMint 태그에 상응합니다. '생성' 기능은vold
에서 사용하여 Android에서 사용할 새 저장소 키를 생성하고 '가져오기' 기능은vts_kernel_encryption_test
에서 사용하여 테스트 키를 가져옵니다. - 장기 래핑 저장소 키를 임시 래핑 저장소 키로 변환하는 인터페이스.
convertStorageKeyToEphemeral
KeyMint 메서드에 상응합니다.vold
와vts_kernel_encryption_test
에서 이 메서드를 사용하여 저장소를 잠금 해제합니다.
키 래핑 알고리즘은 구현 세부정보이지만 임의의 IV가 포함된 AES-256-GCM과 같은 강력한 AEAD를 사용해야 합니다.
소프트웨어 변경 필요
AOSP에는 하드웨어 래핑 키를 지원하는 기본 프레임워크가 이미 있습니다. 여기에는 vold
와 같은 사용자 공간 구성요소 지원 및 blk-crypto, fscrypt, dm-default-key의 Linux 커널 지원이 포함됩니다.
그러나 일부 구현별 변경사항이 필요합니다.
KeyMint 변경사항
TAG_STORAGE_KEY
를 지원하고 convertStorageKeyToEphemeral
메서드를 구현하도록 기기의 KeyMint 구현을 수정해야 합니다.
Keymaster에서는 exportKey
가 convertStorageKeyToEphemeral
대신 사용되었습니다.
Linux 커널 변경사항
하드웨어 래핑 키를 지원하려면 기기의 인라인 암호화 엔진용 Linux 커널 드라이버를 수정해야 합니다.
android14
이상 커널의 경우 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
을 구현합니다.
android12
및 android13
커널의 경우 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
을 구현합니다.
테스트
하드웨어 래핑 키를 사용한 암호화는 표준 키를 사용한 암호화보다 테스트하기가 더 어렵지만 테스트 키를 가져오고 하드웨어에서 실행하는 키 파생을 다시 구현하여 여전히 테스트할 수 있습니다. vts_kernel_encryption_test
에서 구현됩니다. 이 테스트를 실행하려면 다음을 실행하세요.
atest -v vts_kernel_encryption_test
테스트 로그를 읽고 하드웨어 래핑 키 지원이 감지되지 않아서 하드웨어 래핑 키 테스트 사례(예: FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy
및 DmDefaultKeyTest.TestHwWrappedKey
)를 건너뛰지 않았는지 확인합니다. 이 경우 테스트 결과는 여전히 '통과됨'입니다.
사용 설정
기기의 하드웨어 래핑 키 지원이 올바르게 작동하면 Android에서 FBE 및 메타데이터 암호화에 사용하도록 기기의 fstab
파일을 다음과 같이 변경할 수 있습니다.
- FBE:
wrappedkey_v0
플래그를fileencryption
매개변수에 추가합니다. 예를 들어fileencryption=::inlinecrypt_optimized+wrappedkey_v0
을 사용하세요. 자세한 내용은 FBE 문서를 참고하세요. - 메타데이터 암호화:
wrappedkey_v0
플래그를metadata_encryption
매개변수에 추가합니다. 예를 들어metadata_encryption=:wrappedkey_v0
을 사용하세요. 자세한 내용은 메타데이터 암호화 문서를 참고하세요.