Add some examples. (thanks to okozina)
[platform/upstream/cryptsetup.git] / docs / examples / crypt_luks_usage.c
1 #include <inttypes.h>
2 #include <libcryptsetup.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8
9 #include "crypt_examples.h"
10
11 #define KEY_SIZE 32
12 #define EX_DEV_NAME "ex_crypt_dev"
13 #define DMDIR "/dev/mapper/"
14 #define SECTOR_SIZE 512
15
16 /*
17  * You can use this example with command line parameters as follows,
18  * but please note, that this example will not do any sophisticated parameters
19  * checking at all.
20  *
21  * ./crypt_luks_usage <path>
22  *
23  *      where:
24  *      <path> is either regular file or block device. DO NOT use your physical HDD
25  *      with running system or another device containing valuable data otherwise you risk
26  *      partial or complete loss of it.
27  */
28 static void usage(const char *msg)
29 {
30         fprintf(stderr, "ERROR: %s\nusage: ./crypt_luks_usage <path>\n"
31                         "The <path> can refer to either a regular file or a block device.\n",
32                         msg ?: "");
33 }
34
35 int main(int argc, char **argv)
36 {
37         char *answer = NULL, *cipher, *cipher_mode, *dev;
38         int step = 0, r;
39         size_t size = 0;
40         /* crypt device handle */
41         struct crypt_active_device cad;
42         struct crypt_device *cd;
43         struct crypt_params_luks1 params;
44
45         if (geteuid())
46                 fprintf(stderr, "WARN: Process doesn't have super user privileges. "
47                                 "Most of examples will fail because of that.\n");
48
49         if (argc != 2) {
50                 usage("Wrong number of cmd line parameters.");
51                 exit(1);
52         }
53
54         dev = argv[1];
55
56         /*
57          * __STEP_01__
58          *
59          * crypt_init() call precedes most of operations of cryptsetup API. The call is used
60          * to initialize crypt device context stored in structure referenced by _cd_ in
61          * the example. Second parameter is used to pass underlaying device path.
62          *
63          * Note:
64          * If path refers to a regular file it'll be attached to a first free loop device.
65          * crypt_init() operation fails in case there's no more loop device available.
66          * Also, loop device will have the AUTOCLEAR flag set, so the file will be
67          * detached after crypt_free() call on the concerned context.
68          */
69         EX_STEP(++step, "crypt_init()");
70         if ((r = crypt_init(&cd, dev))) {
71                 EX_FAIL("crypt_init() failed for '%s'\n", dev ?: "(not set)");
72                 return r;
73         }
74         EX_SUCCESS("crypt_init() on '%s' has been successful", dev);
75         if (strcmp(dev, crypt_get_device_name(cd)))
76                 printf("\tFile '%s' has been attached to %s\n", dev, crypt_get_device_name(cd));
77
78         EX_DELIM;
79         /*
80          * So far no data were written on your device. This will change with call of
81          * crypt_format() only if you specify CRYPT_LUKS1 as device type.
82          */
83         printf("8 initial sectors of the device will be overwritten\n"
84                "Are you sure you want to call crypt_format() over '%s'?\n"
85                "If you're absolutely sure the device doesn't contain any valuable data,\n"
86                "approve the operation by typing 'yes' in upper case: ", crypt_get_device_name(cd));
87
88         if ((r = getline(&answer, &size, stdin)) == -1) {
89                 perror("getline");
90                 goto out;
91         }
92
93         if (strcmp(answer, "YES\n"))
94                 goto out;
95
96         /* Example of crypt_format() follows: */
97
98         /*
99          * cipher and cipher_mode:
100          *
101          * you'll get more on _cipher_ and _cipher_mode_ in man page
102          * for cryptsetup userspace utility or at cryptsetup project
103          * documentation.
104          */
105         cipher = "aes";
106         cipher_mode = "cbc-essiv:sha256";
107         params.hash = "sha1";
108
109         /*
110          * This parameter is relevant only in case of the luks header
111          * and the payload are both stored on same device.
112          *
113          * In this particular case, payload offset (which is
114          * computed internaly, according to volume key size)
115          * is aligned to 2048 sectors
116          *
117          * if you set data_alignment = 0, cryptsetup will autodetect
118          * data_alignment from underlaying device topology.
119          */
120         params.data_alignment = 2048;
121
122         /*
123          * this parameter defines that no external device
124          * for luks header will be used
125          */
126         params.data_device = NULL;
127
128         /*
129          * __STEP_02__
130          *
131          * NULLs for uuid and volume_key means that these attributes will be
132          * generated during crypt_format(). Volume key is generated with respect
133          * to key size parameter passed to function.
134          *
135          * Note that in crypt_format() device is checked wheter it's large enough to
136          * store the luks header only.
137          */
138         EX_STEP(++step, "crypt_format()");
139         if((r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, NULL, KEY_SIZE, &params))) {
140                 EX_FAIL("crypt_format() failed on device %s\n", crypt_get_device_name(cd));
141                 goto out;
142         }
143         EX_SUCCESS("crypt_format() on device %s formated successfully. "
144                         "The device now contains LUKS1 header, but there is no active keyslot with encrypted "
145                         "volume key.", crypt_get_device_name(cd));
146         EX_DELIM;
147
148         /*
149          * __STEP_03__
150          *
151          * This call is intended to store volume_key in encrypted form into structure called keyslot.
152          * Without keyslot you can't manipulate with LUKS device after the context will be freed.
153          *
154          * To create a new keyslot you need to supply the existing one (to get the volume key from) or
155          * you need to supply the volume key. Now we have volume key stored internally and we have no active
156          * keyslot so this the only option.
157          *
158          */
159         printf("Going to create a new keyslot...\n");
160         EX_STEP(++step, "crypt_keyslot_add_by_volume_key()");
161         if ((r = crypt_keyslot_add_by_volume_key(cd, CRYPT_ANY_SLOT, NULL, 0, NULL, 0)) < 0) {
162                 EX_FAIL("Adding keyslot failed.");
163                 goto out;
164         }
165         EX_SUCCESS("Keyslot nr. %d created successfully on device %s.", r, crypt_get_device_name(cd));
166         EX_DELIM;
167
168         /*
169          * __STEP_04__
170          *
171          * This is the example of the second method mentioned in STEP 03. By supplying passphrase for
172          * the active keyslot you can create a new one.
173          */
174         printf("Now let's try to add a keyslot using the existing active keyslot\n");
175         EX_STEP(++step, "crypt_keyslot_add_by_passphrase()");
176         if ((r = crypt_keyslot_add_by_passphrase(cd, CRYPT_ANY_SLOT, NULL, 0, NULL, 0)) < 0) {
177                 EX_FAIL("Adding keyslot failed\n");
178                 goto out;
179         }
180         EX_SUCCESS("Keyslot nr. %d created successfully and written on device %s.", r, crypt_get_device_name(cd));
181         EX_DELIM;
182
183         crypt_free(cd);
184         cd = NULL;
185
186         /*
187          * __STEP_05__
188          *
189          * In previous steps the device was formatted (LUKS header was written to backing device)
190          * and keyslots were activated (volume key was written in two separate structures encrypted
191          * by two user supplied passwords).
192          *
193          * This example demonstrates typical use case for LUKS device activation.
194          * It's sequence of sub-steps: device initialization (crypt_init), LUKS header load (crypt_load())
195          * and finally the device activation itself
196          */
197         EX_PRESS_ENTER("Device context going to be freed. New one will initialized to demonstrate activation process.");
198         EX_STEP(++step, "crypt_init()");
199         if ((r = crypt_init(&cd, dev))) {
200                 EX_FAIL("crypt_init() failed for '%s'!", dev);
201                 goto out;
202         }
203         EX_SUCCESS("crypt_init() on '%s' has been successful.", dev);
204         if (strcmp(dev, crypt_get_device_name(cd)))
205                 printf("\tFile '%s' has been attached to %s\n", dev, crypt_get_device_name(cd));
206         EX_DELIM;
207         /* __STEP_05__
208          *
209          * crypt_load() is used to load the LUKS header from backing block device
210          * into crypt_device context
211          */
212         EX_PRESS_ENTER("Going to load LUKS header.");
213         EX_STEP(step, "crypt_load()");
214         if ((r = crypt_load(cd, CRYPT_LUKS1, &params))) {
215                 EX_FAIL("crypt_load() failed on device '%s'!", crypt_get_device_name(cd));
216                 goto out;
217         }
218         EX_SUCCESS("crypt_load() successful. The header has been read from %s.", crypt_get_device_name(cd));
219         EX_DELIM;
220
221         /*
222          * __STEP_05__
223          *
224          * Device activation creates mapping in device-mapper with name EX_DEV_NAME.
225          * The volume key is stored into kernel mem. space and the encryption of backing
226          * device is now set in motion.
227          */
228         printf("Going to activate LUKS device\n");
229         EX_STEP(step, "crypt_activate_by_passphrase()");
230         if ((r = crypt_activate_by_passphrase(cd, EX_DEV_NAME, CRYPT_ANY_SLOT, NULL, 0, 0)) < 0) {
231                 EX_FAIL("Device activation failed!");
232                 goto out;
233         }
234         EX_SUCCESS("Encrypted device is active on " DMDIR EX_DEV_NAME ".");
235         printf("\tThe cipher used in device context: '%s'\n", crypt_get_cipher(cd) ?: "(not set) !");
236         printf("\tThe cipher mode used in device context: '%s'\n", crypt_get_cipher_mode(cd) ?: "(not set) !");
237         printf("\tThe device UUID '%s'\n", crypt_get_uuid(cd) ?: "(not set) !");
238         EX_DELIM;
239
240         /*
241          * __STEP_06__
242          *
243          * Get info about active device (query DM backend)
244          */
245         EX_PRESS_ENTER("Going to get active active device parameters.");
246         EX_STEP(++step, "crypt_get_active_device()");
247         if ((r = crypt_get_active_device(cd, EX_DEV_NAME, &cad))) {
248                 EX_FAIL("Get info about active device '%s' failed!", EX_DEV_NAME);
249                 goto out;
250         }
251         EX_SUCCESS("Active device parameters for " EX_DEV_NAME ":\n"
252                         "\tPayload offset (in sectors): %" PRIu64 "\n"
253                         "\tEncrypted payload area size in sectors: %" PRIu64 " and bytes: %" PRIu64 "\n"
254                         "\tThe device has a read-only flag %sset",
255                         cad.offset, cad.size, cad.size * SECTOR_SIZE,
256                         cad.flags & CRYPT_ACTIVATE_READONLY ? "" : "not ");
257         EX_DELIM;
258
259         crypt_free(cd);
260         cd = NULL;
261
262         /*
263          * __STEP_07__
264          *
265          * crypt_init_by_name() initializes device context and loads LUKS header from backing device
266          */
267         EX_PRESS_ENTER("The context used in previous examples is going to be freed to demonstrate "
268                         "how to initialize a device context from the active device.");
269         EX_STEP(++step, "crypt_init_by_name()");
270         if ((r = crypt_init_by_name(&cd, EX_DEV_NAME))) {
271                 EX_FAIL("crypt_init_by_name() failed for the device name: " EX_DEV_NAME);
272                 goto out;
273         }
274         EX_SUCCESS("A new context has been initialized, LUKS header has been restored"
275                         "\n\tDevice UUID is '%s'", crypt_get_uuid(cd));
276
277         /*
278          * __STEP_08__
279          *
280          * crypt_deactivate() is used to remove the volume_key from kernel mem. space and to remove the
281          * device nod associated with decrypted backing device.
282          *
283          */
284         EX_PRESS_ENTER("\n\tGoing to deactivate the crypt device. Note that the device "
285                         "won't be deactivated while it's opened with O_EXCL flag (e.g. mounted).");
286         EX_STEP(++step, "crypt_deactivate()");
287         //printf("\nPress <ENTER> to continue to device deactivation of the test device.\n"
288         //      "Note that mounted device won't be deactivated. First unmount the device!");
289         //getc(stdin);
290         while ((r = crypt_deactivate(cd, EX_DEV_NAME))) {
291                 EX_FAIL("crypt_deactivate() failed. Most propably the device is still busy!");
292                 EX_PRESS_ENTER("Going to retry device deactivation");
293         }
294         EX_SUCCESS("crypt_deactivate() successful. Device " DMDIR EX_DEV_NAME " is now deactivated");
295
296 out:
297         if (crypt_status(cd, EX_DEV_NAME) == CRYPT_ACTIVE)
298                 crypt_deactivate(cd, EX_DEV_NAME);
299         if (answer)
300                 free(answer);
301         /* always free context which is no longer used  */
302         if (cd)
303                 crypt_free(cd);
304
305         return r;
306 }