forked from anatol/luks.go
/
volume.go
94 lines (82 loc) · 2.59 KB
/
volume.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package luks
import (
"encoding/hex"
"fmt"
"os"
"strconv"
"strings"
"time"
"github.com/anatol/devmapper.go"
)
// Volume represents information provided by an unsealed (i.e. with recovered password) LUKS slot
type Volume struct {
backingDevice string
flags []string // dmmapper flags
uuid string
key []byte
luksType string
storageEncryption string
storageIvTweak uint64
storageSectorSize uint64
storageOffset uint64 // offset of underlying storage in bytes
storageSize uint64 // length of underlying device in bytes, zero means that size should be calculated using `diskSize` function
}
// SetupMapper creates a device mapper for the given LUKS volume
func (v *Volume) SetupMapper(name string) error {
kernelFlags := make([]string, 0, len(v.flags))
for _, f := range v.flags {
flag, ok := flagsKernelNames[f]
if !ok {
return fmt.Errorf("unknown LUKS flag: %v", f)
}
kernelFlags = append(kernelFlags, flag)
}
if v.storageSectorSize == 0 {
return fmt.Errorf("invalid sector size")
}
if v.storageSectorSize != devmapper.SectorSize {
kernelFlags = append(kernelFlags, "sector_size:"+strconv.Itoa(int(v.storageSectorSize)))
}
if v.storageSize%v.storageSectorSize != 0 {
return fmt.Errorf("storage size must be multiple of sector size")
}
if v.storageOffset%v.storageSectorSize != 0 {
return fmt.Errorf("offset must be multiple of sector size")
}
// the key should have hex format
key := make([]byte, hex.EncodedLen(len(v.key)))
hex.Encode(key, v.key)
defer clearSlice(key)
table := devmapper.CryptTable{
StartSector: 0,
Length: v.storageSize / devmapper.SectorSize,
BackendDevice: v.backingDevice,
BackendOffset: v.storageOffset / devmapper.SectorSize,
Encryption: v.storageEncryption,
Key: string(key),
IVTweak: v.storageIvTweak,
Flags: kernelFlags,
}
uuid := fmt.Sprintf("CRYPT-%v-%v-%v", v.luksType, strings.ReplaceAll(v.uuid, "-", ""), name) // See dm_prepare_uuid()
return devmapper.CreateAndLoad(name, uuid, 0, table)
}
// MapperReady waits for the mapped device to be created. This is a temporary
// workaround until devmapper does this. Use when the mapped device is not
// created immediately upon `SetupMapper` return.
func (v *Volume) MapperReady(name string, timeout time.Duration) bool {
exists := func() bool {
_, err := os.Stat(fmt.Sprintf("/dev/mapper/%s", name))
return err == nil
}
end := time.Now().Add(timeout)
for {
if exists() {
return true
}
if time.Now().After(end) {
break
}
time.Sleep(10 * time.Millisecond)
}
return false
}