-
Notifications
You must be signed in to change notification settings - Fork 2
/
inspect.go
154 lines (148 loc) · 5.74 KB
/
inspect.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package main
import (
"fmt"
"os"
"text/tabwriter"
"github.com/containers/luksy"
"github.com/spf13/cobra"
)
var all bool
func init() {
inspectCommand := &cobra.Command{
Use: "inspect",
Short: "Inspect a LUKS-formatted file or device",
RunE: func(cmd *cobra.Command, args []string) error {
return inspectCmd(cmd, args)
},
Args: cobra.ExactArgs(1),
Example: `luksy - inspect /dev/mapper/encrypted-lv`,
}
flags := inspectCommand.Flags()
flags.SetInterspersed(false)
flags.BoolVarP(&all, "all", "a", false, "include information about inactive key slots")
rootCmd.AddCommand(inspectCommand)
}
func inspectCmd(cmd *cobra.Command, args []string) error {
f, err := os.Open(args[0])
if err != nil {
return err
}
defer f.Close()
v1header, v2header, _, v2json, err := luksy.ReadHeaders(f, luksy.ReadHeaderOptions{})
if err != nil {
return err
}
tw := tabwriter.NewWriter(os.Stdout, 0, 8, 1, ' ', 0)
defer tw.Flush()
if v1header != nil {
if v1header.Version() != 1 {
return fmt.Errorf("internal error: magic/version mismatch (%d)", v1header.Version())
}
fmt.Fprintf(tw, "Magic\t%q\n", v1header.Magic())
fmt.Fprintf(tw, "Version\t%d\n", v1header.Version())
fmt.Fprintf(tw, "Cipher\t%s, %s\n", v1header.CipherName(), v1header.CipherMode())
fmt.Fprintf(tw, "Hash\t%s\n", v1header.HashSpec())
fmt.Fprintf(tw, "Payload offset sectors\t%d\n", v1header.PayloadOffset())
fmt.Fprintf(tw, "Main key\tlength %d\n", v1header.KeyBytes())
fmt.Fprintf(tw, "\tdigest %q\n", v1header.MKDigest())
fmt.Fprintf(tw, "\tsalt %q\n", v1header.MKDigestSalt())
fmt.Fprintf(tw, "\t%d rounds\n", v1header.MKDigestIter())
fmt.Fprintf(tw, "UUID\t%s\n", v1header.UUID())
for i := 0; i < 8; i++ {
ks, err := v1header.KeySlot(i)
if err != nil {
return fmt.Errorf("reading key slot %d: %w", i, err)
}
active, err := ks.Active()
if err != nil {
return fmt.Errorf("reading key slot %d status: %w", i, err)
}
if active || all {
active, err := ks.Active()
activeStr := fmt.Sprintf("%t", active)
if err != nil {
activeStr = fmt.Sprintf("unknown (corrupted?): %v", err)
}
fmt.Fprintf(tw, "Slot %d\tactive\t%s\n", i, activeStr)
fmt.Fprintf(tw, "\titerations\t%d\n", ks.Iterations())
fmt.Fprintf(tw, "\tsalt\t%q\n", ks.KeySlotSalt())
fmt.Fprintf(tw, "\tkey material offset sectors\t%d\n", ks.KeyMaterialOffset())
fmt.Fprintf(tw, "\tstripes\t%d\n", ks.Stripes())
}
}
}
if v2header != nil {
if v2header.Version() != 2 {
return fmt.Errorf("internal error: magic/version mismatch (%d)", v2header.Version())
}
fmt.Fprintf(tw, "Magic\t%q\n", v2header.Magic())
fmt.Fprintf(tw, "Version\t%d\n", v2header.Version())
fmt.Fprintf(tw, "Header size\t%d\n", v2header.HeaderSize())
fmt.Fprintf(tw, "Header offset\t%d\n", v2header.HeaderOffset())
fmt.Fprintf(tw, "Checksum\t%q, algorithm %q\n", v2header.Checksum(), v2header.ChecksumAlgorithm())
fmt.Fprintf(tw, "UUID\t%s\n", v2header.UUID())
fmt.Fprintf(tw, "Requirements\t%v\n", v2json.Config.Requirements)
for key, segment := range v2json.Segments {
fmt.Fprintf(tw, "Segment %s\ttype %q, offset %s, size %s, flags %v\n", key, segment.Type, segment.Offset, segment.Size, segment.Flags)
switch segment.Type {
case "crypt":
fmt.Fprintf(tw, "\tcrypt encryption %s, sector size %d, IV tweak %d\n", segment.Encryption, segment.SectorSize, segment.IVTweak)
if segment.Integrity != nil {
fmt.Fprintf(tw, "\tcrypt integrity type %s, journal encryption %s, journal integrity %s\n", segment.Integrity.Type, segment.Integrity.JournalEncryption, segment.Integrity.JournalIntegrity)
}
}
}
for key, slot := range v2json.Keyslots {
fmt.Fprintf(tw, "Slot %s \ttype %s\n", key, slot.Type)
switch slot.Type {
case "luks2":
fmt.Fprintf(tw, "\tluks2 AF type %s\n", slot.AF.Type)
switch slot.AF.Type {
case "luks1":
fmt.Fprintf(tw, "\tluks1 AF stripes %d, hash %s\n", slot.AF.Stripes, slot.AF.Hash)
}
fmt.Fprintf(tw, "\tluks2 KDF type %s, salt %q\n", slot.Kdf.Type, slot.Kdf.Salt)
switch slot.Kdf.Type {
case "argon2i":
fmt.Fprintf(tw, "\targon2i time %d, memory %d, cpus %d\n", slot.Kdf.Time, slot.Kdf.Memory, slot.Kdf.CPUs)
case "pbkdf2":
fmt.Fprintf(tw, "\tpbkdf2 hash %s, iterations %d\n", slot.Kdf.Hash, slot.Kdf.Iterations)
}
case "reencrypt":
fmt.Fprintf(tw, "\treencrypt mode %s, direction %s\n", slot.Mode, slot.Direction)
}
fmt.Fprintf(tw, "\tarea type %q, offset %d, size %d\n", slot.Area.Type, slot.Area.Offset, slot.Area.Size)
switch slot.Area.Type {
case "raw":
fmt.Fprintf(tw, "\traw encryption %q, key size %d\n", slot.Area.Encryption, slot.Area.KeySize)
case "checksum":
fmt.Fprintf(tw, "\tchecksum hash %q, sector size %d\n", slot.Area.Hash, slot.Area.SectorSize)
case "datashift":
fmt.Fprintf(tw, "\tdatashift shift size %d\n", slot.Area.ShiftSize)
case "datashift-checksum":
fmt.Fprintf(tw, "\tdatashift-checksum hash %q, sector size %d, shift size %d\n", slot.Area.Hash, slot.Area.SectorSize, slot.Area.ShiftSize)
}
if slot.Priority != nil {
fmt.Fprintf(tw, "\tpriority %s\n", slot.Priority.String())
}
}
for key, digest := range v2json.Digests {
fmt.Fprintf(tw, "Digest %s\tdigest %q\n", key, digest.Digest)
fmt.Fprintf(tw, "\tsalt\t%q\n", digest.Salt)
fmt.Fprintf(tw, "\ttype\t%q\n", digest.Type)
fmt.Fprintf(tw, "\tsegments\t%v\n", digest.Segments)
switch digest.Type {
case "pbkdf2":
fmt.Fprintf(tw, "\thash %s, iterations %d\n", digest.Hash, digest.Iterations)
}
}
for key, token := range v2json.Tokens {
fmt.Fprintf(tw, "Token %s\ttype %s, keyslots %v\n", key, token.Type, token.Keyslots)
switch token.Type {
case "luks2-keyring":
fmt.Fprintf(tw, "\tdescription %q\n", token.KeyDescription)
}
}
}
return nil
}