본문으로 이동

LUKS

위키백과, 우리 모두의 백과사전.
(Linux Unified Key Setup에서 넘어옴)

LUKS(Linux Unified Key Setup)는 2004년 클레멘스 프루비르트(Clemens Fruhwirth)가 만든 디스크 암호화 사양으로, 본래 리눅스를 위해 설계되었다.

LUKS는 다양한 도구에서 사용할 수 있도록 플랫폼 독립적인 표준 온디스크 포맷을 구현한다. 이는 서로 다른 프로그램과 운영 체제 간의 호환성 및 상호운용성을 용이하게 하며, 모든 프로그램이 안전하고 문서화된 방식으로 비밀번호 관리를 구현하도록 보장한다.[1]

설명

[편집]

LUKS는 블록 장치를 암호화하는 데 사용된다. 암호화된 장치의 내용은 임의적이며, 따라서 스왑 파티션을 포함한 모든 파일 시스템을 암호화할 수 있다.[2] 암호화된 볼륨의 시작 부분에는 암호화되지 않은 헤더가 있으며, 여기에는 암호화 유형 및 키 크기와 같은 암호화 매개변수와 함께 최대 8개(LUKS1) 또는 32개(LUKS2)의 암호화 키를 저장할 수 있다.[3][4]

이 헤더의 존재는 LUKS와 dm-crypt의 주요 차이점인데, 헤더를 통해 여러 개의 서로 다른 암호를 사용할 수 있고 이를 변경하거나 제거할 수 있기 때문이다. 헤더가 손실되거나 손상되면 장치를 더 이상 복호화할 수 없게 된다.[5]

암호화는 다층 구조 방식을 사용한다. 먼저 블록 장치는 마스터 키를 사용하여 암호화된다. 이 마스터 키는 활성화된 각 사용자 키로 암호화된다.[6] 사용자 키는 암호, FIDO2 보안 키, TPM 또는 스마트카드에서 파생된다.[7][8] 이러한 다층 구조 방식을 통해 사용자는 전체 블록 장치를 다시 암호화하지 않고도 암호를 변경할 수 있다. 키 슬롯에는 사용자 암호 또는 다른 유형의 키를 확인하기 위한 정보가 포함될 수 있다.

LUKS에는 두 가지 버전이 있는데, LUKS2는 헤더 손상에 대한 복구 능력을 갖추고 기본적으로 Argon2 키 유도 함수를 사용하는 반면, LUKS1은 PBKDF2를 사용한다.[9] 특정 상황에서 LUKS의 두 버전 간 변환이 가능하지만, Argon2와 같은 일부 기능은 LUKS1에서 사용하지 못할 수 있다.[3] LUKS2는 메타데이터 포맷으로 JSON을 사용한다.[3][10]

사용 가능한 암호화 알고리즘은 호스트의 개별 커널 지원에 따라 달라진다. 해싱을 위한 백엔드로 Libgcrypt를 사용할 수 있으며, 이는 해당 라이브러리의 모든 알고리즘을 지원한다.[11] 기본 알고리즘을 선택하는 것은 운영 체제 공급업체의 몫이다.[12] LUKS1은 AFsplitter라고 불리는 안티 포렌식 기법을 사용하여 안전한 데이터 소거 및 보호를 가능하게 한다.[13]

LVM과 함께 사용하는 LUKS

[편집]

논리 볼륨 관리(LVM)는 LUKS와 함께 사용할 수 있다.[14]

LVM on LUKS
잠금 해제된 LUKS 컨테이너 위에서 LVM을 사용하면, 모든 하위 파티션(LVM 논리 볼륨)을 단일 키로 암호화할 수 있다. 이는 LUKS 컨테이너를 여러 파티션으로 나누는 것과 유사하다. 디스크가 복호화되기 전까지는 LVM 구조가 보이지 않는다.[15]
LUKS on LVM
LVM 논리 볼륨을 암호화하기 위해 LUKS를 사용하면, 암호화된 볼륨이 여러 장치에 걸쳐 있을 수 있다. 하위 LVM 볼륨 그룹은 암호화된 볼륨을 복호화하지 않고도 볼 수 있다.[16]

전체 디스크 암호화

[편집]
LUKS 위에서 LVM을 사용하는 자동 파티션 옵션을 보여주는 데비안 인소톨러

LUKS의 일반적인 용도는 전체 디스크 암호화를 제공하는 것이다. 이는 운영 체제 설치 시 루트 파티션을 암호화하여 운영 체제 파일이 사악한 가정부 공격을 받거나 권한이 없는 당사자에 의해 읽히는 것을 방지하는 과정을 포함한다.[14]

리눅스 시스템에서 부트로더(예: GRUB) 자체가 LUKS를 지원하는 경우 부트 파티션(/boot)도 암호화될 수 있다. 이는 리눅스 커널의 변조를 방지하기 위해 수행된다. 그러나 1단계 부트로더EFI 시스템 파티션은 암호화될 수 없다(전체 디스크 암호화의 부트 키 문제 참조).[14]

모바일 리눅스 시스템에서는 postmarketOS가 터치스크린을 사용하여 전체 디스크 암호화 시스템의 잠금을 해제할 수 있도록 osk-sdl을 개발했다.

Systemd를 실행하는 시스템의 경우, systemd-homed 구성 요소를 사용하여 개별 홈 디렉토리를 암호화할 수 있다.[17]

운영 체제 지원

[편집]

LUKS의 참조 구현은 리눅스에서 작동하며, 디스크 암호화 백엔드로 dm-crypt를 사용하는 cryptsetup의 개선된 버전을 기반으로 한다. 마이크로소프트 윈도우에서는 리눅스용 윈도우 하위 시스템을 통해 LUKS로 암호화된 디스크를 사용할 수 있다.[18] (이전에는 LibreCrypt를 통해 가능했으나,[19] 현재는 근본적인 보안 결함이 발견되었으며,[20][21] 이는 DoxBox의 후속인 FreeOTFE를 계승한 것이었다.)

DragonFly BSD는 LUKS를 지원한다.[22]

설치 프로그램 지원

[편집]

여러 리눅스 배포판은 OS 설치 시 루트 장치를 암호화할 수 있도록 지원한다. 이러한 설치 프로그램에는 칼라마레스,[23] 유비퀴티,[24] 데비안 인스톨러,[25] 등이 포함된다.

온디스크 포맷

[편집]

LUKS 헤더는 하위 호환성을 제공한다. 최신 버전의 LUKS는 이전 버전의 헤더를 읽을 수 있다.[26]

LUKS1

[편집]
LUKS1 헤더[26]
오프셋 데이터 유형 설명
000 00016진수 char[6] 매직 넘버 {'L', 'U', 'K', 'S', 0xBA, 0xBE }
006 00616진수 uint16_t LUKS 버전 (LUKS1의 경우 0x0001)
008 00816진수 char[32] 암호 알고리즘 (예: "twofish", "aes")
040 02816진수 char[32] 암호 모드 (예: "cbc-essiv:sha256")
072 04816진수 char[32] 암호화 해시 함수 (예: "sha1", "ripemd160")
104 06816진수 uint32_t 페이로드 오프셋 (암호화된 데이터의 위치, 512바이트 오프셋 단위)
108 06C16진수 uint32_t 키 바이트 수
112 07016진수 char[20] PBKDF2 마스터 키 체크섬
132 08416진수 char[32] PBKDF2 마스터 키 솔트 매개변수
164 0A416진수 uint32_t PBKDF2 마스터 키 반복 횟수 (기본값: 10)
168 0A816진수 char[40] 파티션의 UUID (예: "504c9fa7-d080-4acf-a829-73227b48fb89")
208 0D016진수 (48 바이트) 키슬롯 1
544 22016진수 (48 바이트) 키슬롯 8
총 592 바이트
각 키슬롯의 포맷
오프셋 데이터 유형 설명
00 uint32_t 키슬롯 상태: 활성=0x00AC71F3; 비활성=0x0000DEAD
04 uint32_t PBKDF2 반복 매개변수
04 char[32] PBKDF2 솔트 매개변수
40 uint32_t 키의 시작 섹터
44 uint32_t 안티 포렌식 스트라이프 수 (기본값: 4000)
총 48 바이트

LUKS2

[편집]

LUKS2 헤더는 바이너리 영역과 JSON 영역, 두 번째 바이너리 및 JSON 영역, 그리고 키슬롯 영역으로 구성된다. 바이너리 및 JSON 영역은 약간의 차이를 두고 두 번 반복된다.[10]

바이너리 영역

[편집]

바이너리 영역의 크기는 항상 4kiB이다. 바이너리와 JSON 영역을 합친 크기는 16kiB에서 4MiB 사이의 2의 거듭제곱 바이트일 수 있으며, 이에 따라 각 JSON 영역의 크기는 12kiB에서 4092kiB 사이가 된다.

LUKS2 바이너리 및 JSON 헤더 영역 (각각 16kiB)[10]
오프셋 데이터 유형 설명
첫 번째 바이너리 영역
00000 000016진수 char[6] 매직 넘버 {'L', 'U', 'K', 'S', 0xBA, 0xBE }, blkid를 통한 빠른 감지 허용
00006 000616진수 uint16_t LUKS 버전 (LUKS2의 경우 0x0002)
00008 000816진수 uint64_t 바이너리 및 JSON 영역의 크기 (일반적으로 16kiB, 400016진수)
00016 001016진수 uint64_t 에포크(Epoch), 헤더가 수정될 때마다 증가함
00024 001816진수 char[48] ASCII 파티션 레이블, 널 종료
00072 004816진수 char[32] 체크섬 알고리즘을 결정하는 문자열 (일반적으로 "sha256"), 널 종료
00104 006816진수 uint8_t[64] 솔트, 각 바이너리 영역마다 고유함
00168 00A816진수 char[40] 장치의 UUID, 널 종료 (예: "02f47c64-7e74-4711-8bd4-a37613d1ecd3")
00208 00D016진수 char[48] 보조 "서브시스템" 레이블, 널 종료
00256 010016진수 uint64_t 장치 내 이 LUKS 영역의 오프셋 (일반적으로 0)
00264 010816진수 _char[184] 패딩, 0으로 채워져야 함
00448 01C016진수 uint8_t[64] 체크섬 알고리즘으로 계산된 첫 번째 바이너리 영역의 체크섬, 더 짧으면 0으로 패딩됨
00512 020016진수 _char[3584] 패딩, 0으로 채워져야 함
첫 번째 JSON 영역
04096 100016진수 char[12288] LUKS JSON 객체, 널 종료
두 번째 바이너리 영역
16384 400016진수 char[6] 두 번째 매직 넘버 {'S', 'K', 'U', 'L', 0xBA, 0xBE }
첫 번째 바이너리 영역과 동일
16488 406816진수 uint8_t[64] 솔트, 각 바이너리 영역마다 고유함
첫 번째 바이너리 영역과 동일
16640 410016진수 uint64_t 장치 내 이 LUKS 영역의 오프셋 (일반적으로 400016진수, 1638410진수)
16648 410816진수 _char[184] 패딩, 0으로 채워져야 함
16832 41C016진수 uint8_t[64] 체크섬 알고리즘으로 계산된 두 번째 바이너리 영역의 체크섬, 더 짧으면 0으로 패딩됨
16896 420016진수 _char[3584] 패딩, 0으로 채워져야 함
두 번째 JSON 영역
첫 번째 JSON 영역과 동일
총 32kiB

JSON 영역

[편집]

기본 LUKS2 JSON 메타데이터 객체는 5개의 키를 가진다: config, keyslots, digests, segments, tokens.[10]

Config에는 LUKS 헤더의 일반적인 설정과 정보, 그리고 영구적인 마운트 옵션이 포함된다.

Segments는 데이터를 포함하고 복호화할 수 있는 디스크 상의 영역을 기술한다. 또한 각 세그먼트가 어떤 알고리즘으로 암호화되었는지 기술한다.

Digests는 어떤 키슬롯이 어떤 세그먼트를 복호화할 수 있는 암호화된 키를 포함하는지 기술한다. 여기에는 체크섬 역할을 하며 비밀번호의 정확성을 검증하는 키슬롯의 복호화된 키의 해시가 포함된다.

Keyslots는 암호화된 키를 포함한다. 암호화 방식은 다양하며, 비밀번호, 키 파일, 하드웨어 키 및 기타 방법의 조합을 사용하여 포함된 마스터 키를 복호화할 수 있다.

Tokens 객체는 LUKS와 통합되는 외부 시스템을 위한 추가 정보를 보유할 수 있다.

사용자 데이터인 세그먼트는 커다란 마스터 키와 효율적인 암호화 알고리즘으로 암호화된다. 이 마스터 키는 더 비용이 많이 드는 알고리즘과 잠재적으로 약할 수 있는 사용자 제공 키로 다시 암호화될 수 있으며, 이렇게 암호화된 마스터 키들이 키슬롯에 저장된다. 이는 비밀번호를 추측하려는 무차별 대입 공격을 늦추며, 또한 키슬롯에 다르게 암호화된 동일한 마스터 키를 다시 쓰는 것만으로 전체 데이터 섹션을 재암호화할 필요 없이 복호화 방법과 비밀번호를 변경할 수 있게 해준다.[10]

들여쓰기와 줄 바꿈이 추가된 전형적인 LUKS2 JSON 영역 예시는 다음과 같다.

{
	"keyslots": {
		"0": {
			"type": "luks2",
			"key_size": 64,
			"af": {
				"type": "luks1",
				"stripes": 4000,
				"hash": "sha256"
			},
			"area": {
				"type": "raw",
				"offset": "32768",
				"size": "258048",
				"encryption": "aes-xts-plain64",
				"key_size": 64
			},
			"kdf": {
				"type": "argon2id",
				"time": 4,
				"memory": 1048576,
				"cpus": 4,
				"salt": "YOvmrBmgFT7Ehm7ANZrn0quep1fUFisNCv4e+X8+CLk="
			}
		}
	},
	"tokens": {},
	"segments": {
		"0": {
			"type": "crypt",
			"offset": "16777216",
			"size": "dynamic",
			"iv_tweak": "0",
			"encryption": "aes-xts-plain64",
			"sector_size": 512
		}
	},
	"digests": {
		"0": {
			"type": "pbkdf2",
			"keyslots": [
				"0"
			],
			"segments": [
				"0"
			],
			"hash": "sha256",
			"iterations": 105703,
			"salt": "hrSZ0Sh6t3EVAyeH7XLSH1dEQrRmJwimbjHx85PLS/k=",
			"digest": "tXiDNw8fanGe8QcXewvtzF3AOTOqaIXBmhAGa8Kb42w="
		}
	},
	"config": {
		"json_size": "12288",
		"keyslots_size": "16744448",
		"flags": [
				"allow-discards"
		]
	}
}

키슬롯 영역

[편집]

키슬롯은 두 개의 바이너리 및 JSON 영역 뒤의 장치 영역을 차지한다. 위에서 보여준 전형적인 사례에서 이는 32kiB에서 시작하여 4MiB 또는 16MiB까지 이어진다. 여기서는 16MiB를 예로 든다.

보통 하나의 장치는 오프셋이 16MiB로 설정되고 크기가 dynamic인 단일 세그먼트로 구성된다. 재암호화 중이거나 특이한 구성의 경우, 전체 장치를 빈틈이나 겹침 없이 덮는 여러 세그먼트가 있을 수 있다.

각 세그먼트는 하나의 연관된 다이제스트(digest)를 가져야 하며, 각 다이제스트는 하나 이상의 연관된 키슬롯을 가진다. 키슬롯은 다이제스트와 연관되지 않고 다른 목적으로 사용될 수도 있다.

키슬롯 자체는 키슬롯 영역에 매핑되며, 위의 예시에서는 헤더 바로 뒤인 32kiB에서 시작하는 단일 252kiB 영역으로 매핑된다. 이 영역은 LUKS1과 동일한 방식으로 안티 포렌식 스트라이프로 난독화된다.

다이제스트의 기본 알고리즘인 pbkdf2와 안티 포렌식 스트라이프 유형인 "luks1"은 LUKS1과 동일하다. 키 유도는 기본적으로 LUKS1에서 지원되지 않는 더 강력한 알고리즘을 사용하지만, 지원되는 pbkdf2로 설정할 수도 있다.[10]

예제

[편집]

Cryptsetup은 LUKS 프런트엔드의 참조 구현체이다.

경로가 /dev/sda1인 장치를 암호화하려면:

# cryptsetup luksFormat /dev/sda1

암호화된 장치를 열려면(여기서 name매핑된 장치 이름임):

# cryptsetup open /dev/sda1 name

재암호화

[편집]

LUKS 컨테이너의 재암호화는 cryptsetup 도구 자체를 사용하거나 cryptsetup-reencrypt라는 기존 도구를 사용하여 수행할 수 있다. 이러한 도구는 기존의 암호화되지 않은 파일 시스템에 암호화를 추가하거나, 블록 장치에서 암호화를 제거하는 데에도 사용될 수 있다.[11][27]

두 방법 모두 유사한 구문을 가진다:

# cryptsetup reencrypt /dev/sda1
# cryptsetup-reencrypt /dev/sda1

같이 보기

[편집]

각주

[편집]
  1. Fruhwirth, Clemens (2018년 1월 20일). “LUKS On-Disk Format Specification Version 1.2.3” (PDF). 2021년 9월 23일에 확인함. 
  2. “Encrypting drives using LUKS”. 《Fedora Docs》. 2022년 5월 6일에 확인함. 
  3. “Chapter 12. Encrypting block devices using LUKS”. 《Red Hat Customer Portal》. 
  4. “How to Encrypt Hard Disk (partition) using LUKS in Linux”. 2019년 2월 27일. 
  5. “How to Encrypt Your Data with dm-crypt”. 《Linode》. 2022년 11월 22일. 
  6. Bossi, Simone; Visconti, Andrea (2015). 《What Users Should Know About Full Disk Encryption Based on LUKS》 (PDF). 
  7. “systemd-cryptenroll - ArchWiki”. 《wiki.archlinux.org》. 2023년 11월 22일에 확인함. 
  8. “How to encrypt a LUKS container using a smart card or token”. 2014년 4월 20일. 
  9. “How LUKS works with Full Disk Encryption in Linux”. 2021년 9월 25일. 
  10. “on-disk-format-luks2.pdf” (PDF). 2024년 3월 7일. 
  11. cryptsetup(8) – 리눅스 Administration and Privileged Commands 매뉴얼 페이지
  12. “Breaking LUKS Encryption”. 《eForensics》. 2020년 8월 21일. 
  13. “AFsplitter”. 
  14. “dm-crypt/Encrypting an entire system”. 2022년 5월 6일에 확인함. 
  15. “Arch with LVM on LUKS”. 
  16. “LUKS on LVM: encrypted logical volumes and secure backups”. 2014년 9월 12일. 
  17. “Home Directories”. 《systemd》. 
  18. “Servicing the Windows Subsystem for Linux (WSL) 2 Linux Kernel”. 《Microsoft Developer Blogs》. 2021년 4월 16일. 
  19. “LibreCrypt”. 《GitHub》. 2022년 7월 27일. 
  20. “Flaw in driver allows privilege escalation. Feedback wanted · Issue #38 · t-d-k/LibreCrypt”. 《GitHub》. 2015년 9월 30일. 
  21. “Driver allows writing to arbitrary devices · Issue #39 · t-d-k/LibreCrypt”. 《깃허브》. 2015년 10월 7일. 
  22. “DragonFly's Major Features List”. 2022년 5월 6일에 확인함. 
  23. Michael Larabel (2016년 5월 8일). “Calamares Installer Adds LUKS Encryption Support”. 《Phoronix》. 
  24. “How to Encrypt Your Hard Disk in Ubuntu”. 《Make Tech Easier》. 2017년 1월 13일. 
  25. “PartmanCrypto”. 《Debian Wiki》. 2022년 5월 6일에 확인함. 
  26. “LUKS On-Disk Format Specification” (PDF). 
  27. “CRYPTSETUP-REENCRYPT(8) Man page”. 《man7.org》. 

외부 링크

[편집]