libcryptsetup_rs/
keyslot.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use std::{
6    path::{Path, PathBuf},
7    ptr,
8};
9
10use either::Either;
11use libc::{c_int, c_uint};
12
13use crate::{
14    consts::{
15        flags::CryptVolumeKey,
16        vals::{EncryptionFormat, KeyslotInfo, KeyslotPriority},
17    },
18    device::CryptDevice,
19    err::LibcryptErr,
20    settings::CryptPbkdfType,
21};
22
23/// Handle for keyslot operations
24pub struct CryptKeyslotHandle<'a> {
25    reference: &'a mut CryptDevice,
26}
27
28impl<'a> CryptKeyslotHandle<'a> {
29    pub(crate) fn new(reference: &'a mut CryptDevice) -> Self {
30        CryptKeyslotHandle { reference }
31    }
32
33    /// Add key slot using a passphrase
34    pub fn add_by_passphrase(
35        &mut self,
36        keyslot: Option<c_uint>,
37        passphrase: &[u8],
38        new_passphrase: &[u8],
39    ) -> Result<c_uint, LibcryptErr> {
40        errno_int_success!(mutex!(
41            libcryptsetup_rs_sys::crypt_keyslot_add_by_passphrase(
42                self.reference.as_ptr(),
43                keyslot
44                    .map(|k| k as c_int)
45                    .unwrap_or(libcryptsetup_rs_sys::CRYPT_ANY_SLOT),
46                to_byte_ptr!(passphrase),
47                passphrase.len(),
48                to_byte_ptr!(new_passphrase),
49                new_passphrase.len(),
50            )
51        ))
52        .map(|k| k as c_uint)
53    }
54
55    /// Change allocated key slot using a passphrase
56    pub fn change_by_passphrase(
57        &mut self,
58        keyslot_old: Option<c_uint>,
59        keyslot_new: Option<c_uint>,
60        passphrase: &[u8],
61        new_passphrase: &[u8],
62    ) -> Result<c_uint, LibcryptErr> {
63        errno_int_success!(mutex!(
64            libcryptsetup_rs_sys::crypt_keyslot_change_by_passphrase(
65                self.reference.as_ptr(),
66                keyslot_old
67                    .map(|k| k as c_int)
68                    .unwrap_or(libcryptsetup_rs_sys::CRYPT_ANY_SLOT),
69                keyslot_new
70                    .map(|k| k as c_int)
71                    .unwrap_or(libcryptsetup_rs_sys::CRYPT_ANY_SLOT),
72                to_byte_ptr!(passphrase),
73                passphrase.len(),
74                to_byte_ptr!(new_passphrase),
75                new_passphrase.len(),
76            )
77        ))
78        .map(|k| k as c_uint)
79    }
80
81    /// Add key slot using key file
82    pub fn add_by_keyfile_device_offset(
83        &mut self,
84        keyslot: Option<c_uint>,
85        keyfile_and_size: (&Path, crate::size_t),
86        keyfile_offset: u64,
87        new_keyfile_and_size: (&Path, crate::size_t),
88        new_keyfile_offset: u64,
89    ) -> Result<c_uint, LibcryptErr> {
90        let (keyfile, keyfile_size) = keyfile_and_size;
91        let (new_keyfile, new_keyfile_size) = new_keyfile_and_size;
92        let keyfile_cstring = path_to_cstring!(keyfile)?;
93        let new_keyfile_cstring = path_to_cstring!(new_keyfile)?;
94        errno_int_success!(mutex!(
95            libcryptsetup_rs_sys::crypt_keyslot_add_by_keyfile_device_offset(
96                self.reference.as_ptr(),
97                keyslot
98                    .map(|k| k as c_int)
99                    .unwrap_or(libcryptsetup_rs_sys::CRYPT_ANY_SLOT),
100                keyfile_cstring.as_ptr(),
101                keyfile_size,
102                keyfile_offset,
103                new_keyfile_cstring.as_ptr(),
104                new_keyfile_size,
105                new_keyfile_offset,
106            )
107        ))
108        .map(|k| k as c_uint)
109    }
110
111    /// Add key slot with a key
112    pub fn add_by_key(
113        &mut self,
114        keyslot: Option<c_uint>,
115        volume_key: Option<Either<&[u8], usize>>,
116        passphrase: &[u8],
117        flags: CryptVolumeKey,
118    ) -> Result<c_uint, LibcryptErr> {
119        let (vk_ptr, vk_len) = match volume_key {
120            Some(Either::Left(vk)) => (to_byte_ptr!(vk), vk.len()),
121            Some(Either::Right(s)) => (std::ptr::null(), s),
122            None => (std::ptr::null(), 0),
123        };
124        errno_int_success!(mutex!(libcryptsetup_rs_sys::crypt_keyslot_add_by_key(
125            self.reference.as_ptr(),
126            keyslot
127                .map(|k| k as c_int)
128                .unwrap_or(libcryptsetup_rs_sys::CRYPT_ANY_SLOT),
129            vk_ptr,
130            vk_len,
131            to_byte_ptr!(passphrase),
132            passphrase.len(),
133            flags.bits(),
134        )))
135        .map(|k| k as c_uint)
136    }
137
138    /// Destroy key slot
139    pub fn destroy(&mut self, keyslot: c_uint) -> Result<(), LibcryptErr> {
140        errno!(mutex!(libcryptsetup_rs_sys::crypt_keyslot_destroy(
141            self.reference.as_ptr(),
142            keyslot as c_int
143        )))
144    }
145
146    /// Get keyslot status
147    pub fn status(&mut self, keyslot: c_uint) -> Result<KeyslotInfo, LibcryptErr> {
148        try_int_to_return!(
149            mutex!(libcryptsetup_rs_sys::crypt_keyslot_status(
150                self.reference.as_ptr(),
151                keyslot as c_int,
152            )),
153            KeyslotInfo
154        )
155    }
156
157    /// Get keyslot priority (LUKS2 specific)
158    pub fn get_priority(&mut self, keyslot: c_uint) -> Result<KeyslotPriority, LibcryptErr> {
159        try_int_to_return!(
160            mutex!(libcryptsetup_rs_sys::crypt_keyslot_get_priority(
161                self.reference.as_ptr(),
162                keyslot as c_int,
163            )),
164            KeyslotPriority
165        )
166    }
167
168    /// Get keyslot priority (LUKS2 specific)
169    pub fn set_priority(
170        &mut self,
171        keyslot: c_uint,
172        priority: KeyslotPriority,
173    ) -> Result<(), LibcryptErr> {
174        errno!(mutex!(libcryptsetup_rs_sys::crypt_keyslot_set_priority(
175            self.reference.as_ptr(),
176            keyslot as c_int,
177            priority.into(),
178        )))
179    }
180
181    /// Get maximum keyslots supported for device type
182    pub fn max_keyslots(fmt: EncryptionFormat) -> Result<c_uint, LibcryptErr> {
183        errno_int_success!(mutex!(libcryptsetup_rs_sys::crypt_keyslot_max(
184            fmt.as_ptr()
185        )))
186        .map(|k| k as c_uint)
187    }
188
189    /// Get keyslot area pointers
190    pub fn area(&mut self, keyslot: c_uint) -> Result<(u64, u64), LibcryptErr> {
191        let mut offset = 0u64;
192        let mut length = 0u64;
193        errno!(mutex!(libcryptsetup_rs_sys::crypt_keyslot_area(
194            self.reference.as_ptr(),
195            keyslot as c_int,
196            &mut offset as *mut u64,
197            &mut length as *mut u64,
198        )))
199        .map(|_| (offset, length))
200    }
201
202    /// Get size of key in keyslot - only different from `crypt_get_volume_key_size()` binding
203    /// in the case of LUKS2 using unbound keyslots
204    pub fn get_key_size(&mut self, keyslot: c_uint) -> Result<c_uint, LibcryptErr> {
205        errno_int_success!(mutex!(libcryptsetup_rs_sys::crypt_keyslot_get_key_size(
206            self.reference.as_ptr(),
207            keyslot as c_int,
208        )))
209        .map(|k| k as c_uint)
210    }
211
212    /// Get encryption cipher and key size of keyslot (not data)
213    pub fn get_encryption(
214        &mut self,
215        keyslot: Option<c_uint>,
216    ) -> Result<(&str, crate::size_t), LibcryptErr> {
217        let mut key_size: crate::size_t = 0;
218        ptr_to_result!(mutex!(libcryptsetup_rs_sys::crypt_keyslot_get_encryption(
219            self.reference.as_ptr(),
220            keyslot
221                .map(|k| k as c_int)
222                .unwrap_or(libcryptsetup_rs_sys::CRYPT_ANY_SLOT),
223            &mut key_size as *mut crate::size_t,
224        )))
225        .and_then(|ptr| from_str_ptr!(ptr))
226        .map(|st| (st, key_size))
227    }
228
229    /// Get PBDKF parameters for a keyslot
230    pub fn get_pbkdf(&mut self, keyslot: c_uint) -> Result<CryptPbkdfType, LibcryptErr> {
231        let mut type_ = libcryptsetup_rs_sys::crypt_pbkdf_type {
232            type_: ptr::null(),
233            hash: ptr::null(),
234            time_ms: 0,
235            iterations: 0,
236            max_memory_kb: 0,
237            parallel_threads: 0,
238            flags: 0,
239        };
240        errno!(mutex!(libcryptsetup_rs_sys::crypt_keyslot_get_pbkdf(
241            self.reference.as_ptr(),
242            keyslot as c_int,
243            &mut type_ as *mut _,
244        )))
245        .and_then(|_| CryptPbkdfType::try_from(type_))
246    }
247
248    /// Set encryption used for keyslot
249    pub fn set_encryption(
250        &mut self,
251        cipher: &str,
252        key_size: crate::size_t,
253    ) -> Result<(), LibcryptErr> {
254        let cipher_cstring = to_cstring!(cipher)?;
255        errno!(mutex!(libcryptsetup_rs_sys::crypt_keyslot_set_encryption(
256            self.reference.as_ptr(),
257            cipher_cstring.as_ptr(),
258            key_size,
259        )))
260    }
261
262    /// Get directory where crypt devices are mapped
263    pub fn get_dir() -> Result<Box<Path>, LibcryptErr> {
264        ptr_to_result!(mutex!(libcryptsetup_rs_sys::crypt_get_dir()))
265            .and_then(|s| from_str_ptr_to_owned!(s))
266            .map(PathBuf::from)
267            .map(|b| b.into_boxed_path())
268    }
269}