1 #pragma once
2 
3 #include <libcryptsetup.h>
4 
5 #include <stdplus/handle/managed.hpp>
6 
7 namespace estoraged
8 {
9 
10 /** @class CryptsetupInterface
11  *  @brief Interface to the cryptsetup functions used to manage a LUKS device.
12  *  @details This class is used to mock out the cryptsetup functions.
13  */
14 class CryptsetupInterface
15 {
16   public:
17     virtual ~CryptsetupInterface() = default;
18 
19     /** @brief Wrapper around crypt_format.
20      *  @details Used for mocking purposes.
21      *
22      *  @param[in] cd - crypt device handle.
23      *  @param[in] type - type of device (optional params struct must be of
24      *    this type).
25      *  @param[in] cipher - (e.g. "aes").
26      *  @params[in cipher_mode - including IV specification (e.g. "xts-plain").
27      *  @params[in] uuid - requested UUID or NULL if it should be generated.
28      *  @params[in] volume_key - pre-generated volume key or NULL if it should
29      *    be generated (only for LUKS).
30      *  @params[in] volume_key_size - size of volume key in bytes.
31      *  @params[in] params - crypt type specific parameters.
32      *
33      *  @returns 0 on success or negative errno value otherwise.
34      */
35     virtual int cryptFormat(struct crypt_device* cd, const char* type,
36                             const char* cipher, const char* cipherMode,
37                             const char* uuid, const char* volumeKey,
38                             size_t volumeKeySize, void* params) = 0;
39 
40     /** @brief Wrapper around crypt_keyslot_add_by_volume_key.
41      *  @details Used for mocking purposes.
42      *
43      *  @param[in] cd - crypt device handle.
44      *  @param[in] keyslot - requested keyslot or CRYPT_ANY_SLOT.
45      *  @param[in] volume_key - provided volume key or NULL if used after
46      *    crypt_format.
47      *  @param[in] volume_key_size - size of volume_key.
48      *  @param[in] passphrase - passphrase for new keyslot.
49      *  @param[in] passphrase_size - size of passphrase.
50      *
51      *  @returns allocated key slot number or negative errno otherwise.
52      */
53     virtual int cryptKeyslotAddByVolumeKey(struct crypt_device* cd, int keyslot,
54                                            const char* volumeKey,
55                                            size_t volumeKeySize,
56                                            const char* passphrase,
57                                            size_t passphraseSize) = 0;
58 
59     /** @brief Wrapper around crypt_load.
60      *  @details Used for mocking purposes.
61      *
62      *  @param[in] cd - crypt device handle.
63      *  @param[in] requested_type - crypt-type or NULL for all known.
64      *  @param[in] params - crypt type specific parameters (see crypt-type).
65      *
66      *  @returns 0 on success or negative errno value otherwise.
67      */
68     virtual int cryptLoad(struct crypt_device* cd, const char* requestedType,
69                           void* params) = 0;
70 
71     /** @brief Wrapper around crypt_activate_by_passphrase.
72      *  @details Used for mocking purposes.
73      *
74      *  @param[in] cd - crypt device handle.
75      *  @param[in] name - name of device to create, if NULL only check
76      *    passphrase.
77      *  @param[in] keyslot - requested keyslot to check or CRYPT_ANY_SLOT.
78      *  @param[in] passphrase - passphrase used to unlock volume key.
79      *  @param[in] passphrase_size - size of passphrase.
80      *  @param[in] flags - activation flags.
81      *
82      *  @returns unlocked key slot number or negative errno otherwise.
83      */
84     virtual int cryptActivateByPassphrase(struct crypt_device* cd,
85                                           const char* name, int keyslot,
86                                           const char* passphrase,
87                                           size_t passphraseSize,
88                                           uint32_t flags) = 0;
89 
90     /** @brief Wrapper around crypt_deactivate.
91      *  @details Used for mocking purposes.
92      *
93      *  @param[in] cd - crypt device handle, can be NULL.
94      *  @param[in] name - name of device to deactivate.
95      *
96      *  @returns 0 on success or negative errno value otherwise.
97      */
98     virtual int cryptDeactivate(struct crypt_device* cd, const char* name) = 0;
99 
100     /** @brief Wrapper around crypt_keyslot_destory.
101      *  @details Used for mocking purposes.
102      *
103      *  @param[in] cd - crypt device handle, can not be NULL.
104      *  @param[in] keyslot requested key slot to destroy
105      *
106      *  @returns 0 on success or negative errno value otherwise.
107      */
108     virtual int cryptKeyslotDestroy(struct crypt_device* cd,
109                                     const int keyslot) = 0;
110 
111     /** @breif Wapper around crypt_keyslot_max
112      *  @details Used for mocking purposes.
113      *
114      * @param type crypt device type
115      *
116      * @return slot count or negative errno otherwise if device
117      * does not support keyslots.
118      */
119     virtual int cryptKeySlotMax(const char* type) = 0;
120 
121     /** @breif Wapper around crypt_keyslot_status
122      *  @details Used for mocking purposes.
123      *  Get information about particular key slot.
124      *
125      * @param cd crypt device handle
126      * @param keyslot requested keyslot to check or CRYPT_ANY_SLOT
127      *
128      * @return value defined by crypt_keyslot_info
129      *
130      */
131     virtual crypt_keyslot_info cryptKeySlotStatus(struct crypt_device* cd,
132                                                   int keyslot) = 0;
133 };
134 
135 /** @class Cryptsetup
136  *  @brief Implements CryptsetupInterface.
137  */
138 class Cryptsetup : public CryptsetupInterface
139 {
140   public:
141     ~Cryptsetup() = default;
142 
143     int cryptFormat(struct crypt_device* cd, const char* type,
144                     const char* cipher, const char* cipherMode,
145                     const char* uuid, const char* volumeKey,
146                     size_t volumeKeySize, void* params) override
147     {
148         return crypt_format(cd, type, cipher, cipherMode, uuid, volumeKey,
149                             volumeKeySize, params);
150     }
151 
152     int cryptKeyslotAddByVolumeKey(struct crypt_device* cd, int keyslot,
153                                    const char* volumeKey, size_t volumeKeySize,
154                                    const char* passphrase,
155                                    size_t passphraseSize) override
156     {
157         return crypt_keyslot_add_by_volume_key(
158             cd, keyslot, volumeKey, volumeKeySize, passphrase, passphraseSize);
159     }
160 
161     int cryptLoad(struct crypt_device* cd, const char* requestedType,
162                   void* params) override
163     {
164         return crypt_load(cd, requestedType, params);
165     }
166 
167     int cryptActivateByPassphrase(struct crypt_device* cd, const char* name,
168                                   int keyslot, const char* passphrase,
169                                   size_t passphraseSize,
170                                   uint32_t flags) override
171     {
172         return crypt_activate_by_passphrase(cd, name, keyslot, passphrase,
173                                             passphraseSize, flags);
174     }
175 
176     int cryptDeactivate(struct crypt_device* cd, const char* name) override
177     {
178         return crypt_deactivate(cd, name);
179     }
180 
181     int cryptKeyslotDestroy(struct crypt_device* cd, const int keyslot) override
182     {
183         return crypt_keyslot_destroy(cd, keyslot);
184     }
185 
186     int cryptKeySlotMax(const char* type) override
187     {
188         return crypt_keyslot_max(type);
189     }
190 
191     crypt_keyslot_info cryptKeySlotStatus(struct crypt_device* cd,
192                                           int keyslot) override
193     {
194         return crypt_keyslot_status(cd, keyslot);
195     }
196 };
197 
198 /** @class CryptHandle
199  *  @brief This manages a crypt_device struct and automatically frees it when
200  *  this handle exits the current scope.
201  */
202 class CryptHandle
203 {
204   public:
205     /** @brief Constructor for CryptHandle
206      *
207      *  @param[in] device - path to device file
208      */
209     explicit CryptHandle(const char* device) : handle(init(device))
210     {}
211 
212     /** @brief Get a pointer to the crypt_device struct. */
213     struct crypt_device* get()
214     {
215         return *handle;
216     }
217 
218   private:
219     /** @brief Allocate and initialize the crypt_device struct
220      *
221      *  @param[in] device - path to device file
222      */
223     struct crypt_device* init(const char* device)
224     {
225         struct crypt_device* cryptDev;
226         int retval = crypt_init(&cryptDev, device);
227         if (retval < 0)
228         {
229             return nullptr;
230         }
231 
232         return cryptDev;
233     }
234 
235     /** @brief Free the crypt_device struct
236      *
237      *  @param[in] cd - pointer to crypt_device*, to be freed
238      */
239     static void cryptFree(struct crypt_device*&& cd)
240     {
241         crypt_free(cd);
242     }
243 
244     /** @brief Managed handle to crypt_device struct */
245     stdplus::Managed<struct crypt_device*>::Handle<cryptFree> handle;
246 };
247 
248 } // namespace estoraged
249