blkid_rs/
lib.rs

1#![deny(warnings)]
2#[warn(unused_must_use)]
3// The following code has been ported from libcryptsetup
4extern crate byteorder;
5extern crate either;
6extern crate uuid;
7
8use either::Either::{Left, Right};
9use std::convert;
10use std::error;
11use std::fmt::{Display, Error as FmtError, Formatter};
12use std::io;
13use std::io::Read;
14use std::str;
15use uuid::Uuid;
16
17// TODO: missing docs
18
19#[derive(Debug)]
20pub enum Error {
21    InvalidMagic,
22    InvalidStringEncoding(str::Utf8Error),
23    InvalidVersion,
24    InvalidUuid(uuid::Error),
25    ReadError(io::Error),
26    ReadIncorrectHeaderSize,
27    HeaderProcessingError,
28    EmptyString,
29}
30
31impl Display for Error {
32    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
33        write!(f, "{:?}", &self)
34    }
35}
36
37impl error::Error for Error {
38    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
39        match &self {
40            &Error::InvalidStringEncoding(e) => Some(e),
41            &Error::InvalidUuid(e) => Some(e),
42            &Error::ReadError(e) => Some(e),
43            _ => None,
44        }
45    }
46}
47
48pub enum LuksHeader {
49    Luks1(LuksHeaderV1),
50    Luks2(LuksHeaderV2),
51}
52
53impl LuksHeader {
54    pub fn read<R: Read>(mut reader: R) -> Result<LuksHeader, Error> {
55        let res = match raw::read_luks_header(&mut reader)? {
56            Left(raw) => LuksHeader::Luks1(LuksHeaderV1 { raw }),
57            Right(raw) => LuksHeader::Luks2(LuksHeaderV2 { raw }),
58        };
59        Ok(res)
60    }
61}
62
63pub struct LuksHeaderV1 {
64    raw: raw::luks_phdr,
65}
66
67pub struct LuksHeaderV2 {
68    raw: raw::luks2_phdr,
69}
70
71pub trait LuksVersionedHeader {
72    fn version(&self) -> u16;
73    fn uuid(&self) -> Result<uuid::Uuid, Error>;
74}
75
76impl LuksVersionedHeader for LuksHeader {
77    fn version(&self) -> u16 {
78        match &self {
79            &LuksHeader::Luks1(h) => h.version(),
80            &LuksHeader::Luks2(h) => h.version(),
81        }
82    }
83
84    fn uuid(&self) -> Result<Uuid, Error> {
85        match &self {
86            &LuksHeader::Luks1(h) => h.uuid(),
87            &LuksHeader::Luks2(h) => h.uuid(),
88        }
89    }
90}
91
92pub trait Luks1Header: LuksVersionedHeader {
93    fn cipher_name(&self) -> Result<&str, Error>;
94    fn cipher_mode(&self) -> Result<&str, Error>;
95    fn hash_spec(&self) -> Result<&str, Error>;
96    fn payload_offset(&self) -> u32;
97    fn key_bytes(&self) -> u32;
98    fn mk_digest(&self) -> &[u8];
99    fn mk_digest_salt(&self) -> &[u8];
100    fn mk_digest_iterations(&self) -> u32;
101}
102
103impl LuksVersionedHeader for LuksHeaderV1 {
104    fn version(&self) -> u16 {
105        self.raw.version
106    }
107
108    fn uuid(&self) -> Result<Uuid, Error> {
109        raw::uuid_buf_to_uuid(&self.raw.uuid)
110    }
111}
112
113impl LuksVersionedHeader for LuksHeaderV2 {
114    fn version(&self) -> u16 {
115        self.raw.version
116    }
117
118    fn uuid(&self) -> Result<Uuid, Error> {
119        raw::uuid_buf_to_uuid(&self.raw.uuid)
120    }
121}
122
123impl Luks1Header for LuksHeaderV1 {
124    fn cipher_name(&self) -> Result<&str, Error> {
125        raw::u8_buf_to_str(&self.raw.cipherName)?.ok_or(Error::EmptyString)
126    }
127
128    fn cipher_mode(&self) -> Result<&str, Error> {
129        raw::u8_buf_to_str(&self.raw.cipherMode)?.ok_or(Error::EmptyString)
130    }
131
132    fn hash_spec(&self) -> Result<&str, Error> {
133        raw::u8_buf_to_str(&self.raw.hashSpec)?.ok_or(Error::EmptyString)
134    }
135
136    fn payload_offset(&self) -> u32 {
137        self.raw.payloadOffset
138    }
139
140    fn key_bytes(&self) -> u32 {
141        self.raw.keyBytes
142    }
143
144    fn mk_digest(&self) -> &[u8] {
145        &self.raw.mkDigest
146    }
147
148    fn mk_digest_salt(&self) -> &[u8] {
149        &self.raw.mkDigestSalt
150    }
151
152    fn mk_digest_iterations(&self) -> u32 {
153        self.raw.mkDigestIterations
154    }
155}
156
157pub trait Luks2Header: LuksVersionedHeader {
158    fn label(&self) -> Result<Option<&str>, Error>;
159    fn subsystem(&self) -> Result<Option<&str>, Error>;
160    fn seqid(&self) -> u64;
161    fn header_size(&self) -> u64;
162    fn header_offset(&self) -> u64;
163
164    // TODO add luks2 specifics (however the json header structure is not neccessary at the moment so not read)
165}
166
167impl Luks2Header for LuksHeaderV2 {
168    fn label(&self) -> Result<Option<&str>, Error> {
169        let label_opt = raw::u8_buf_to_str(&self.raw.label)?;
170        Ok(label_opt)
171    }
172
173    fn subsystem(&self) -> Result<Option<&str>, Error> {
174        let subsystem_opt = raw::u8_buf_to_str(&self.raw.subsystem)?;
175        Ok(subsystem_opt)
176    }
177
178    fn seqid(&self) -> u64 {
179        self.raw.seqid
180    }
181
182    fn header_size(&self) -> u64 {
183        self.raw.hdr_size
184    }
185
186    fn header_offset(&self) -> u64 {
187        self.raw.hdr_offset
188    }
189}
190
191impl convert::From<str::Utf8Error> for Error {
192    fn from(error: str::Utf8Error) -> Error {
193        Error::InvalidStringEncoding(error)
194    }
195}
196
197impl convert::From<uuid::Error> for Error {
198    fn from(error: uuid::Error) -> Error {
199        Error::InvalidUuid(error)
200    }
201}
202
203impl convert::From<io::Error> for Error {
204    fn from(error: io::Error) -> Error {
205        Error::ReadError(error)
206    }
207}
208
209mod raw {
210    #![allow(non_snake_case)]
211
212    use std::convert::From;
213    use std::io::{Cursor, Read};
214    use std::mem;
215    use std::str;
216
217    use byteorder::{BigEndian, ReadBytesExt};
218    use either::Either;
219    use either::Either::{Left, Right};
220    use uuid;
221
222    const V1: u16 = 1;
223    const V2: u16 = 2;
224
225    const LUKS_MAGIC_L: usize = 6;
226    const LUKS_CIPHERNAME_L: usize = 32;
227    const LUKS_CIPHERMODE_L: usize = 32;
228    const LUKS_HASHSPEC_L: usize = 32;
229    const LUKS_DIGESTSIZE: usize = 20;
230    const LUKS_SALTSIZE: usize = 32;
231    const UUID_STRING_L: usize = 40;
232    const LUKS2_LABEL_L: usize = 48;
233    const LUKS2_SALT_L: usize = 64;
234    const LUKS2_CHECKSUM_ALG_L: usize = 32;
235    const LUKS2_CHECKSUM_L: usize = 64;
236
237    const LUKS_MAGIC: &'static [u8; LUKS_MAGIC_L] = b"LUKS\xba\xbe";
238
239    // used for secondary header, currently unsupported here TODO
240    const _LUKS2_MAGIC_2: &'static [u8; LUKS_MAGIC_L] = b"SKUL\xba\xbe";
241
242    const LUKS2_PHDR_PADDING_L: usize = 184;
243
244    // note: these are not packed because it's unsafe to take a slice
245    #[repr(C)]
246    pub struct luks_phdr {
247        pub magic: [u8; LUKS_MAGIC_L],
248        pub version: u16,
249        pub cipherName: [u8; LUKS_CIPHERNAME_L],
250        pub cipherMode: [u8; LUKS_CIPHERMODE_L],
251        pub hashSpec: [u8; LUKS_HASHSPEC_L],
252        pub payloadOffset: u32,
253        pub keyBytes: u32,
254        pub mkDigest: [u8; LUKS_DIGESTSIZE],
255        pub mkDigestSalt: [u8; LUKS_SALTSIZE],
256        pub mkDigestIterations: u32,
257        pub uuid: [u8; UUID_STRING_L],
258    }
259
260    #[repr(C)]
261    pub struct luks2_phdr {
262        pub magic: [u8; LUKS_MAGIC_L],
263        pub version: u16,
264        pub hdr_size: u64,
265        pub seqid: u64,
266        pub label: [u8; LUKS2_LABEL_L],
267        pub checksum_alg: [u8; LUKS2_CHECKSUM_ALG_L],
268        pub salt: [u8; LUKS2_SALT_L],
269        pub uuid: [u8; UUID_STRING_L],
270        pub subsystem: [u8; LUKS2_LABEL_L],
271        pub hdr_offset: u64,
272        pub _padding: [u8; LUKS2_PHDR_PADDING_L],
273        pub csum: [u8; LUKS2_CHECKSUM_L],
274    }
275
276    pub fn read_luks_header<R: Read>(reader: &mut R) -> Result<Either<luks_phdr, luks2_phdr>, super::Error> {
277        let mut start_buf = [0u8; 8];
278        reader.read_exact(&mut start_buf)?;
279
280        let mut cursor = Cursor::new(start_buf);
281
282        let mut magic_buf = [0u8; LUKS_MAGIC_L];
283        let _magic_len = cursor.read(&mut magic_buf)?;
284
285        let version = cursor.read_u16::<BigEndian>()?;
286
287        if magic_buf == &LUKS_MAGIC[..] && version == V1 {
288            let mut buf = [0u8; mem::size_of::<luks_phdr>()];
289            buf[..8].copy_from_slice(&start_buf);
290            reader.read_exact(&mut buf[8..])?;
291            luks_phdr::from_buf(&mut buf).map(|h| Left(h))
292        } else if magic_buf == &LUKS_MAGIC[..] && version == V2 {
293            let mut buf = [0u8; mem::size_of::<luks2_phdr>()];
294            buf[..8].copy_from_slice(&start_buf);
295            reader.read_exact(&mut buf[8..])?;
296            luks2_phdr::from_buf(&mut buf).map(|h| Right(h))
297        } else if magic_buf != &LUKS_MAGIC[..] {
298            Err(super::Error::InvalidMagic)
299        } else {
300            Err(super::Error::InvalidVersion)
301        }
302    }
303
304    impl luks_phdr {
305        pub fn from_buf(buf: &[u8]) -> Result<luks_phdr, super::Error> {
306            // FIXME - this is not particularly pretty
307
308            if buf.len() < mem::size_of::<luks_phdr>() {
309                return Err(super::Error::ReadIncorrectHeaderSize);
310            }
311            let mut cursor = Cursor::new(buf);
312            let mut magic_buf = [0u8; LUKS_MAGIC_L];
313            let magic_len = cursor.read(&mut magic_buf)?;
314
315            if magic_len != LUKS_MAGIC_L || magic_buf != &LUKS_MAGIC[..] {
316                return Err(super::Error::InvalidMagic);
317            }
318
319            let version = cursor.read_u16::<BigEndian>()?;
320            if version != V1 {
321                return Err(super::Error::InvalidVersion);
322            }
323
324            let mut cipher_name_buf = [0u8; LUKS_CIPHERNAME_L];
325            let cipher_name_len = cursor.read(&mut cipher_name_buf)?;
326            if cipher_name_len != LUKS_CIPHERNAME_L {
327                return Err(super::Error::HeaderProcessingError);
328            }
329
330            let mut cipher_mode_buf = [0u8; LUKS_CIPHERMODE_L];
331            let cipher_mode_len = cursor.read(&mut cipher_mode_buf)?;
332            if cipher_mode_len != LUKS_CIPHERMODE_L {
333                return Err(super::Error::HeaderProcessingError);
334            }
335
336            let mut hash_spec_buf = [0u8; LUKS_HASHSPEC_L];
337            let hash_spec_len = cursor.read(&mut hash_spec_buf)?;
338            if hash_spec_len != LUKS_HASHSPEC_L {
339                return Err(super::Error::HeaderProcessingError);
340            }
341
342            let payload_offset = cursor.read_u32::<BigEndian>()?;
343            let key_bytes = cursor.read_u32::<BigEndian>()?;
344
345            let mut mk_digest_buf = [0u8; LUKS_DIGESTSIZE];
346            let mk_digest_len = cursor.read(&mut mk_digest_buf)?;
347            if mk_digest_len != LUKS_DIGESTSIZE {
348                return Err(super::Error::HeaderProcessingError);
349            }
350
351            let mut mk_digest_salt_buf = [0u8; LUKS_SALTSIZE];
352            let mk_digest_salt_len = cursor.read(&mut mk_digest_salt_buf)?;
353            if mk_digest_salt_len != LUKS_SALTSIZE {
354                return Err(super::Error::HeaderProcessingError);
355            }
356
357            let mk_digest_iterations = cursor.read_u32::<BigEndian>()?;
358
359            let mut uuid_buf = [0u8; UUID_STRING_L];
360            let uuid_len = cursor.read(&mut uuid_buf)?;
361            if uuid_len != UUID_STRING_L {
362                return Err(super::Error::HeaderProcessingError);
363            }
364
365            let res = luks_phdr {
366                magic: magic_buf,
367                version: version,
368                cipherName: cipher_name_buf,
369                cipherMode: cipher_mode_buf,
370                hashSpec: hash_spec_buf,
371                payloadOffset: payload_offset,
372                keyBytes: key_bytes,
373                mkDigest: mk_digest_buf,
374                mkDigestSalt: mk_digest_salt_buf,
375                mkDigestIterations: mk_digest_iterations,
376                uuid: uuid_buf,
377            };
378
379            Ok(res)
380        }
381    }
382
383    impl luks2_phdr {
384        pub fn from_buf(buf: &[u8]) -> Result<luks2_phdr, super::Error> {
385            if buf.len() < mem::size_of::<luks2_phdr>() {
386                return Err(super::Error::ReadIncorrectHeaderSize);
387            }
388            let mut cursor = Cursor::new(buf);
389            let mut magic_buf = [0u8; LUKS_MAGIC_L];
390            let magic_len = cursor.read(&mut magic_buf)?;
391
392            if magic_len != LUKS_MAGIC_L || magic_buf != &LUKS_MAGIC[..] {
393                return Err(super::Error::InvalidMagic);
394            }
395
396            let version = cursor.read_u16::<BigEndian>()?;
397            if version != V2 {
398                return Err(super::Error::InvalidVersion);
399            }
400
401            let hdr_size = cursor.read_u64::<BigEndian>()?;
402            let seqid = cursor.read_u64::<BigEndian>()?;
403
404            let mut label_buf = [0u8; LUKS2_LABEL_L];
405            let label_len = cursor.read(&mut label_buf)?;
406            if label_len != LUKS2_LABEL_L {
407                return Err(super::Error::HeaderProcessingError);
408            }
409
410            let mut checksum_alg_buf = [0u8; LUKS2_CHECKSUM_ALG_L];
411            let checksum_alg_len = cursor.read(&mut checksum_alg_buf)?;
412            if checksum_alg_len != LUKS2_CHECKSUM_ALG_L {
413                return Err(super::Error::HeaderProcessingError);
414            }
415
416            let mut salt_buf = [0u8; LUKS2_SALT_L];
417            let salt_len = cursor.read(&mut salt_buf)?;
418            if salt_len != LUKS2_SALT_L {
419                return Err(super::Error::HeaderProcessingError);
420            }
421
422            let mut uuid_buf = [0u8; UUID_STRING_L];
423            let uuid_len = cursor.read(&mut uuid_buf)?;
424            if uuid_len != UUID_STRING_L {
425                return Err(super::Error::HeaderProcessingError);
426            }
427
428            let mut subsystem_buf = [0u8; LUKS2_LABEL_L];
429            let subsystem_len = cursor.read(&mut subsystem_buf)?;
430            if subsystem_len != LUKS2_LABEL_L {
431                return Err(super::Error::HeaderProcessingError);
432            }
433
434            let hdr_offset = cursor.read_u64::<BigEndian>()?;
435
436            let mut padding_buf = [0u8; LUKS2_PHDR_PADDING_L];
437            let padding_len = cursor.read(&mut padding_buf)?;
438            if padding_len != LUKS2_PHDR_PADDING_L {
439                return Err(super::Error::HeaderProcessingError);
440            }
441
442            let mut csum_buf = [0u8; LUKS2_CHECKSUM_L];
443            let csum_len = cursor.read(&mut csum_buf)?;
444            if csum_len != LUKS2_CHECKSUM_L {
445                return Err(super::Error::HeaderProcessingError);
446            }
447
448            let res = luks2_phdr {
449                magic: magic_buf,
450                version,
451                hdr_size,
452                seqid,
453                label: label_buf,
454                checksum_alg: checksum_alg_buf,
455                salt: salt_buf,
456                uuid: uuid_buf,
457                subsystem: subsystem_buf,
458                hdr_offset,
459                _padding: padding_buf,
460                csum: csum_buf,
461            };
462
463            Ok(res)
464        }
465    }
466
467    pub fn u8_buf_to_str(buf: &[u8]) -> Result<Option<&str>, super::Error> {
468        if let Some(pos) = buf.iter().position(|&c| c == 0) {
469            if pos == 0 {
470                Ok(None)
471            } else {
472                str::from_utf8(&buf[0..pos]).map_err(From::from).map(|s| Some(s))
473            }
474        } else {
475            str::from_utf8(buf).map_err(From::from).map(|s| Some(s))
476        }
477    }
478
479    pub fn uuid_buf_to_uuid(buf: &[u8; UUID_STRING_L]) -> Result<uuid::Uuid, super::Error> {
480        let uuid_str = u8_buf_to_str(buf)?.ok_or(super::Error::EmptyString)?;
481        uuid::Uuid::parse_str(uuid_str).map_err(From::from)
482    }
483
484    #[cfg(test)]
485    mod tests {
486        use super::*;
487
488        #[test]
489        fn test_luks2_header_from_bytes() {
490            let header = b"LUKS\xba\xbe\x00\x02\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00sha256\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\x98\x84>\xba \x87\x16\xff\xdc\xdb\xc8\xe1\xd6\xd5\xf6\x01\x94\x9c^E\x84\x1e\xcc\x1c\xc5\xa6\xeb\xaePf\xde\x7f\x95\xfeL\x07\x1f46B\x95Z\xae\xf5\x8f\x88\xc0uj,\x08\xb4NW\r\x8c\xec\xb6D\x15P\x0e\x8f0748f429-3aad-426d-95b4-82005de5ad36\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xc7\x12\xf52$\xac\xd3\xc7G()<\xbb\x8d\x0f\x14\x03\x1e\xe6\x83\xc9\xe8C\x00\xff\xdf\xb8\x8b\x08\x9f4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
491            let luks2_header = luks2_phdr::from_buf(header).expect("luks2 header");
492
493            assert_eq!(luks2_header.version, 2);
494            assert_eq!(luks2_header.hdr_size, 16384);
495            assert_eq!(luks2_header.seqid, 3);
496            assert_eq!(u8_buf_to_str(&luks2_header.label).unwrap(), None);
497            assert_eq!(u8_buf_to_str(&luks2_header.checksum_alg).unwrap(), Some("sha256"));
498            assert_eq!(
499                luks2_header.salt.to_vec(),
500                vec!(
501                    103u8, 152, 132, 62, 186, 32, 135, 22, 255, 220, 219, 200, 225, 214, 213, 246, 1, 148, 156, 94, 69,
502                    132, 30, 204, 28, 197, 166, 235, 174, 80, 102, 222, 127, 149, 254, 76, 7, 31, 52, 54, 66, 149, 90,
503                    174, 245, 143, 136, 192, 117, 106, 44, 8, 180, 78, 87, 13, 140, 236, 182, 68, 21, 80, 14, 143
504                )
505            );
506            assert_eq!(
507                u8_buf_to_str(&luks2_header.uuid).unwrap(),
508                Some("0748f429-3aad-426d-95b4-82005de5ad36")
509            );
510            assert_eq!(u8_buf_to_str(&luks2_header.subsystem).unwrap(), None);
511            assert_eq!(luks2_header.hdr_offset, 0);
512            assert_eq!(
513                luks2_header.csum.to_vec(),
514                vec!(
515                    62u8, 199, 18, 245, 50, 36, 172, 211, 199, 71, 40, 41, 60, 187, 141, 15, 20, 3, 30, 230, 131, 201,
516                    232, 67, 0, 255, 223, 184, 139, 8, 159, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
517                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
518                )
519            );
520        }
521    }
522}
523
524#[cfg(test)]
525mod tests {
526    use super::*;
527    use std::io::Cursor;
528    use uuid;
529
530    #[test]
531    fn test_luks_header_from_byte_buffer() {
532        let header = b"LUKS\xba\xbe\x00\x01aes\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ecb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00sha256\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00 \xcf^\xb4\xc00q\xbe\xd5\xe6\x90\xc8G\xb3\x00\xbe\xba\xd052qp\x92\x0c\x9c\xa9\x07R\\y_D\x08b\xf1\xe6\x8f\x0c\xa95\xad\xdb\x15+\xa5\xd7\xa7\xbf^\x96B\x90z\x00\x00\x03\xe8a1b49d2d-8a7e-4b04-ab2a-89f3408fd198\x00\x00\x00\x00";
533        let mut cursor: Cursor<&[u8]> = Cursor::new(header);
534        let header = LuksHeader::read(&mut cursor).unwrap();
535
536        if let LuksHeader::Luks1(luks_header) = header {
537            assert_eq!(luks_header.version(), 1);
538            assert_eq!(luks_header.cipher_name().unwrap(), "aes");
539            assert_eq!(luks_header.cipher_mode().unwrap(), "ecb");
540            assert_eq!(luks_header.hash_spec().unwrap(), "sha256");
541            assert_eq!(luks_header.payload_offset(), 4096);
542            assert_eq!(luks_header.key_bytes(), 32);
543            assert_eq!(
544                luks_header.mk_digest(),
545                &[207, 94, 180, 192, 48, 113, 190, 213, 230, 144, 200, 71, 179, 0, 190, 186, 208, 53, 50, 113]
546            );
547            assert_eq!(
548                luks_header.mk_digest_salt(),
549                &[
550                    112, 146, 12, 156, 169, 7, 82, 92, 121, 95, 68, 8, 98, 241, 230, 143, 12, 169, 53, 173, 219, 21,
551                    43, 165, 215, 167, 191, 94, 150, 66, 144, 122
552                ]
553            );
554            assert_eq!(luks_header.mk_digest_iterations(), 1000);
555            assert_eq!(
556                luks_header.uuid().unwrap(),
557                uuid::Uuid::parse_str("a1b49d2d-8a7e-4b04-ab2a-89f3408fd198").unwrap()
558            );
559        } else {
560            assert!(false, "failed to read luks v1 header");
561        }
562    }
563
564    #[test]
565    fn test_luks2_header_from_byte_buffer() {
566        let header = b"LUKS\xba\xbe\x00\x02\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00sha256\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\x98\x84>\xba \x87\x16\xff\xdc\xdb\xc8\xe1\xd6\xd5\xf6\x01\x94\x9c^E\x84\x1e\xcc\x1c\xc5\xa6\xeb\xaePf\xde\x7f\x95\xfeL\x07\x1f46B\x95Z\xae\xf5\x8f\x88\xc0uj,\x08\xb4NW\r\x8c\xec\xb6D\x15P\x0e\x8f0748f429-3aad-426d-95b4-82005de5ad36\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xc7\x12\xf52$\xac\xd3\xc7G()<\xbb\x8d\x0f\x14\x03\x1e\xe6\x83\xc9\xe8C\x00\xff\xdf\xb8\x8b\x08\x9f4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
567        let mut cursor: Cursor<&[u8]> = Cursor::new(header);
568        let header = LuksHeader::read(&mut cursor).unwrap();
569
570        if let LuksHeader::Luks2(luks2_header) = header {
571            assert_eq!(luks2_header.version(), 2);
572            assert_eq!(
573                luks2_header.uuid().unwrap(),
574                uuid::Uuid::parse_str("0748f429-3aad-426d-95b4-82005de5ad36").unwrap()
575            );
576        } else {
577            assert!(false, "failed to read luks v2 header");
578        }
579    }
580}