其他分享
首页 > 其他分享> > LUKS磁盘格式Specification

LUKS磁盘格式Specification

作者:互联网

1 介绍

LUKS是"Linux Unified Key Setup"的简写。LUKS最初是为了解决用户在从更改用户空间和忘记命令行参数中导出加密设置时的问题。目前qemu的磁盘加密格式是luks格式。
LUKS磁盘格式如下:

LUKS phdr

KM1

KM2

...

KM8

bulk data

另外,LUKS phdr中还包含了Key Slot的信息。每个Key Slot和一个KM相关联。Key Slot处于激活状态时,其对应的KM中保存了Master Key的加密副本(该加密副本由用户密码锁定)。Master Key则用于加密数据块。
一个LUKS分区的用户密码数量和Key Slot数量一致。通常情况下Master Key长度是16或者32字节。

2 前言

2.1 数据块加密

LUKS并未限制具体的加密算法实现(如AES或Twofish),以下伪代码展示了加解密的过程:

enc-data = encrypt(cipher-name, cipher-mode, key, original, original-length)

original = decrypt(cipher-name, cipher-mode, key, enc-data, original-length)

注意:如果加密算法要求固定块长度,不足的部分需要用0做填充。反之,解密的时候需要将填充的0去除。

2.2 加密哈希

在 PBKDF2 中需要一个伪随机函数,对于 AFsplitting 需要一个扩散函数。因此在HMAC setup中需要用到该哈希函数。

2.3 PBKDF2

LUKS 需要处理来自诸如键盘输入等熵弱来源的密码,PBKDF2(PKCS #5’s password based key derive function 2)正是为增强熵弱密码的安全特性而定义。LUKS默认使用SHA1作为伪随机函数,也可以通过设置hash-spec字段来设置其他哈希函数。在伪代码中,使用了以下语法:

result = PBKDF2(password, salt, iteration-count, derived-key-length)

以上PBKDF2函数的输出依赖于实际的hash-spec,可以将hash-spec认为一种环境变量。
有关PBKDF2的其他介绍如下:

2.4 AF-Splitter

LUKS使用了反取证(Anti-Forensic)信息拆分。参考实现使用了SHA1作为底层扩散函数。

split-material = AFsplit(unsplit-material, length, stripes)

unsplit-material = AFmerge(split-material, length, stripes)

注意:split-material的长度是unsplit-material的stripes倍,即length * stripes字节。length是unsplit-material的字节数。
用符号D代表unsplit-material,H代表扩散函数,n表示条带数量,AFsplit函数返回的值为s1, s2 . . . sn。其中s1 . . . sn−1是随机选取的,sn则是通过以下方式计算得出:

  1. d0 = 0
  2. dk = H(dk−1 ⊕ sk)
  3. sn = dn−1 ⊕ D

反之,AFmerge则计算dn−1和D:
        D = dn−1 ⊕ sn

3 LUKS partition header

LUKS partition header总长度为592字节,其定义如下:

偏移

字段名称

长度

数据类型

描述

0

magic

6

byte[]

魔数,值为LUKS_MAGIC

6

version

2

uint16_t

LUKS版本,目前是1

8

cipher-name

32

char[]

加密算法

40

cipher-mode

32

char[]

加密模式

72

hash-spec

32

char[]

哈希算法

104

payload-offset

4

uint32_t

数据块偏移,单位是sector,即512字节

108

key-bytes

4

uint32_t

Master Key长度,单位字节

112

mk-digest

20

byte[]

Master Key PBKDF2计算的校验和

132

mk-digest-salt

32

byte[]

盐值,Master Key PBKDF2计算时的参数

164

mk-digest-iter

4

uint32_t

迭代次数,Master Key PBKDF2计算时的参数

168

uuid

40

char[]

分区UUID

208

key-slot-1

48

key slot

key slot 1

256

key-slot-2

48

key slot

key slot 2

...

...

...

...

...

544

key-slot-8

48

key slot

key slot 8

key slot定义如下:

偏移

字段名称

长度

数据类型

描述

0

active

4

uint32_t

key slot状态,enabled/disabled

4

iterations

4

uint32_t

迭代次数,PBKDF2计算时的参数

8

salt

32

byte[]

盐值,PBKDF2计算时的参数

40

key-material-offset

4

uint32_t

key material偏移,单位是sector,即512字节

44

stripes

4

uint32_t

反取证(Anti-Forensic)条带数量

4 LUKS操作

4.1 初始化

LUKS初始化需要以下参数:

整个磁盘的布局取决于phdr后面的Key Material区域的长度。phdr是固定长度的,而Key Material区域的长度取决于Master Key的长度和AF-splitter用到的条带数量。计算好Key Material区域的长度之后,phdr中的payload-offset字段需要填入。
Master Key的校验和需要通过PBKDF2进行计算,其中会涉及多次加盐和迭代哈希。
除此之外,初始化阶段还需要激活至少一个Key Slot。
初始化的伪代码如下:

masterKeyLength = defined by user

masterKey = generate random vector, length : masterKeyLength

phdr.magic = LUKS_MAGIC

phdr.version = 1

phdr.cipher−name = as supplied by user

phdr.cipher−mode = as supplied by user

phdr.key−bytes = masterKey

phdr.mk−digest−salt = generate random vector, length : LUKS_SALTSIZE

// benchmarked according to user input

// ( in older versions fixed to 10 )

phdr.mk−digest-iteration−count = as above

phdr.mk−digest = PBKDF2(masterKey,

            phdr.mk−digest−salt,

            phdr.mk−digest−iteration-count,

            LUKS_DIGESTSIZE)

stripes = LUKS_STRIPES or user defined

// integer divisions, result rounded down

baseOffset = ( size of phdr ) / LUKS_SECTOR_SIZE + 1

keyMaterialSectors = ( stripes ∗ masterKeyLength ) /

           LUKS_SECTOR_SIZE + 1

for each keyslot in phdr as ks {

    // Align keyslot up to multiple of LUKS_ALIGN_KEYSLOTS

    baseOffset = round_up ( baseOffset , LUKS_ALIGN_KEYSLOTS)

    ks.active = LUKS_KEY_DISABLED

    ks.stripes = stripes

    ks.key−material-offset = baseOffset

    baseOffset = baseOffset + keyMaterialSectors

}

phdr.payload−offset = baseOffset

phdr.uuid = generate uuid

 

write phdr to disk

4.2 密钥创建

密钥创建的伪代码如下:

masterKey = must be available, either because it is still in

      memory from initialisation or because it has been

      recovered by a correct password

masterKeyLength = phdr.key−bytes

 

emptyKeySlotIndex = find inactive key slot index in phdr by

          scanning the keyslot.active field for

          LUKS_KEY_DISABLED.

keyslot ks = phdr.keyslots[ emptyKeySlotIndex ]

 

PBKDF2-IterationsPerSecond = benchmark system

ks.iteration-count = PBKDF2-IterationsPerSecond *

              intendedPasswordCheckingTime (in seconds)

ks.salt = generate random vector, length: LUKS_SALTSIZE

 

splitKeyLength = masterKeyLength * ks.stripes

 

pwd = read password from user input

pwd−PBKDF2ed = PBKDF2( password ,

            ks.salt,

            ks.iteration-count,

            masterKeyLength) // key size is the same

                     // as for the bulk data

 

encryptedKey = encrypt(phdr.cipher-name,

               phdr.cipher-mode,

               pwd-PBKDF2ed,    // key

               splitKey,      // content

               splitKeyLength)   // content length

                        

write to partition(encryptedKey,

            ks.key-material-offset,

            splitKeyLength)

 

ks.active = LUKS_KEY_ACTIVE

 

update keyslot ks i phdr

4.3 Master Key恢复

Master Key恢复的伪代码如下:

read phdr from disk

check for correct LUKS_MAGIC and compatible version number

 

masterKeyLength = phdr.key-bytes

pwd = read password form user input

 

for each active keyslot in phdr do as ks {

    pwd-PBKDF2ed = PBKDF2(pwd, ks.salt, ks.iteration-count,

               masterKeyLength)

    read from partition(encryptedKey,            // destination

              ks.key-material-offset,       // sector number

              masterKeyLength * ks.stripes)     // number of bytes

    splitKey = decrypt(phdr.cipherSpec,          // cipher spec

                  pwd-PBKDF2ed,           // key

              encryptedKey,           // content

              encrypted)          // content length

    masterKeyCandidate = AFmerge(splitKey, masterkeyLength, ks.stripes)

    MKCandidate-PBKDF2ed = PBKDF2(masterKeyCandidate,

                   phdr.mk-digest-salt,

                   phdr.mk-digest-iter,

                   LUKS_DIGEST_SIZE)

    if equal (MKCandidate-PBKDF2ed, phdr.mk-digest) {

        break loop and return masterKeyCandidate as correct master key

    }

}

return error, password does not match any keyslot

5 常量

符号

描述

LUKS_MAGIC

{'L', 'U', 'K', 'S', 0xBA, 0xBE}

LUKS魔数

LUKS_DIGESTSIZE

20

Master Key校验和长度

LUKS_SALTSIZE

32

PBKDF2盐值长度

LUKS_NUMKEYS

8

Key Slot数量

LUKS_KEY_DISABLED

0x0000DEAD

Key Slot disable标识

LUKS_KEY_ENABLED

0x00AC71F3

Key Slot enable标识

LUKS_STRIPES

4000

AFsplit条带数量

LUKS_ALIGN_KEYSLOTS

4096

默认Key Slot对齐边界

LUKS_SECTOR_SIZE

512

sector大小

附 可用的加密算法和哈希算法

可用的加密算法包括:

可用的加密模式包括:

可用的哈希算法

 

标签:key,PBKDF2,Specification,磁盘格式,ks,phdr,Key,LUKS
来源: https://blog.csdn.net/bemind1/article/details/117450044