7299a1c86de403387dcd137f6233d25bc8106859
[platform/upstream/cryptsetup.git] / docs / examples / crypt_luks_usage.c
1 /*
2  *  libcryptsetup API - using LUKS device example
3  *
4  * Copyright (C) 2011-2020 Red Hat, Inc. All rights reserved.
5  *
6  * This file is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This file is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <inttypes.h>
26 #include <sys/types.h>
27 #include <libcryptsetup.h>
28
29 static int format_and_add_keyslots(const char *path)
30 {
31         struct crypt_device *cd;
32         int r;
33
34         /*
35          * The crypt_init() call is used  to initialize crypt_device context,
36          * The path parameter specifies a device path.
37          *
38          * For path, you can use either link to a file or block device.
39          * The loopback device will be detached automatically.
40          */
41
42         r = crypt_init(&cd, path);
43         if (r < 0) {
44                 printf("crypt_init() failed for %s.\n", path);
45                 return r;
46         }
47
48         printf("Context is attached to block device %s.\n", crypt_get_device_name(cd));
49
50         /*
51          * So far, no data were written to the device.
52          */
53         printf("Device %s will be formatted as a LUKS device after 5 seconds.\n"
54                "Press CTRL+C now if you want to cancel this operation.\n", path);
55         sleep(5);
56
57         /*
58          * NULLs for uuid and volume_key means that these attributes will be
59          * generated during crypt_format().
60          */
61         r = crypt_format(cd,            /* crypt context */
62                          CRYPT_LUKS2,   /* LUKS2 is a new LUKS format; use CRYPT_LUKS1 for LUKS1 */
63                          "aes",         /* used cipher */
64                          "xts-plain64", /* used block mode and IV */
65                          NULL,          /* generate UUID */
66                          NULL,          /* generate volume key from RNG */
67                          512 / 8,       /* 512bit key - here AES-256 in XTS mode, size is in bytes */
68                          NULL);         /* default parameters */
69
70         if (r < 0) {
71                 printf("crypt_format() failed on device %s\n", crypt_get_device_name(cd));
72                 crypt_free(cd);
73                 return r;
74         }
75
76         /*
77          * The device now contains a LUKS header, but there is no active keyslot.
78          *
79          * crypt_keyslot_add_* call stores the volume_key in the encrypted form into the keyslot.
80          *
81          * After format, the volume key is stored internally.
82          */
83         r = crypt_keyslot_add_by_volume_key(cd,                 /* crypt context */
84                                             CRYPT_ANY_SLOT,     /* just use first free slot */
85                                             NULL,               /* use internal volume key */
86                                             0,                  /* unused (size of volume key) */
87                                             "foo",              /* passphrase - NULL means query*/
88                                             3);                 /* size of passphrase */
89
90         if (r < 0) {
91                 printf("Adding keyslot failed.\n");
92                 crypt_free(cd);
93                 return r;
94         }
95
96         printf("The first keyslot is initialized.\n");
97
98         /*
99          * Add another keyslot, now authenticating with the first keyslot.
100          * It decrypts the volume key from the first keyslot and creates a new one with the specified passphrase.
101          */
102         r = crypt_keyslot_add_by_passphrase(cd,                 /* crypt context */
103                                             CRYPT_ANY_SLOT,     /* just use first free slot */
104                                             "foo", 3,           /* passphrase for the old keyslot */
105                                             "bar", 3);          /* passphrase for the new kesylot */
106         if (r < 0) {
107                 printf("Adding keyslot failed.\n");
108                 crypt_free(cd);
109                 return r;
110         }
111
112         printf("The second keyslot is initialized.\n");
113
114         crypt_free(cd);
115         return 0;
116 }
117
118 static int activate_and_check_status(const char *path, const char *device_name)
119 {
120         struct crypt_device *cd;
121         struct crypt_active_device cad;
122         int r;
123
124         /*
125          * LUKS device activation example.
126          */
127         r = crypt_init(&cd, path);
128         if (r < 0) {
129                 printf("crypt_init() failed for %s.\n", path);
130                 return r;
131         }
132
133         /*
134          * crypt_load() is used to load existing LUKS header from a block device
135          */
136         r = crypt_load(cd,              /* crypt context */
137                        CRYPT_LUKS,      /* requested type - here LUKS of any type */
138                        NULL);           /* additional parameters (not used) */
139
140         if (r < 0) {
141                 printf("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
142                 crypt_free(cd);
143                 return r;
144         }
145
146         /*
147          * Device activation creates a device-mapper device with the specified name.
148          */
149         r = crypt_activate_by_passphrase(cd,            /* crypt context */
150                                          device_name,   /* device name to activate */
151                                          CRYPT_ANY_SLOT,/* the keyslot use (try all here) */
152                                          "foo", 3,      /* passphrase */
153                                          CRYPT_ACTIVATE_READONLY); /* flags */
154         if (r < 0) {
155                 printf("Device %s activation failed.\n", device_name);
156                 crypt_free(cd);
157                 return r;
158         }
159
160         printf("%s device %s/%s is active.\n", crypt_get_type(cd), crypt_get_dir(), device_name);
161         printf("\tcipher used: %s\n", crypt_get_cipher(cd));
162         printf("\tcipher mode: %s\n", crypt_get_cipher_mode(cd));
163         printf("\tdevice UUID: %s\n", crypt_get_uuid(cd));
164
165         /*
166          * Get info about the active device.
167          */
168         r = crypt_get_active_device(cd, device_name, &cad);
169         if (r < 0) {
170                 printf("Get info about active device %s failed.\n", device_name);
171                 crypt_deactivate(cd, device_name);
172                 crypt_free(cd);
173                 return r;
174         }
175
176         printf("Active device parameters for %s:\n"
177                 "\tDevice offset (in sectors): %" PRIu64 "\n"
178                 "\tIV offset (in sectors)    : %" PRIu64 "\n"
179                 "\tdevice size (in sectors)  : %" PRIu64 "\n"
180                 "\tread-only flag            : %s\n",
181                 device_name, cad.offset, cad.iv_offset, cad.size,
182                 cad.flags & CRYPT_ACTIVATE_READONLY ? "1" : "0");
183
184         crypt_free(cd);
185         return 0;
186 }
187
188 static int handle_active_device(const char *device_name)
189 {
190         struct crypt_device *cd;
191         int r;
192
193         /*
194          * crypt_init_by_name() initializes context by an active device-mapper name
195          */
196         r = crypt_init_by_name(&cd, device_name);
197         if (r < 0) {
198                 printf("crypt_init_by_name() failed for %s.\n", device_name);
199                 return r;
200         }
201
202         if (crypt_status(cd, device_name) == CRYPT_ACTIVE)
203                 printf("Device %s is still active.\n", device_name);
204         else {
205                 printf("Something failed perhaps, device %s is not active.\n", device_name);
206                 crypt_free(cd);
207                 return -1;
208         }
209
210         /*
211          * crypt_deactivate() is used to deactivate a device
212          */
213         r = crypt_deactivate(cd, device_name);
214         if (r < 0) {
215                 printf("crypt_deactivate() failed.\n");
216                 crypt_free(cd);
217                 return r;
218         }
219
220         printf("Device %s is now deactivated.\n", device_name);
221
222         crypt_free(cd);
223         return 0;
224 }
225
226 int main(int argc, char **argv)
227 {
228         if (geteuid()) {
229                 printf("Using of libcryptsetup requires super user privileges.\n");
230                 return 1;
231         }
232
233         if (argc != 2) {
234                 printf("usage: ./crypt_luks_usage <path>\n"
235                         "<path> refers to either a regular file or a block device.\n"
236                         "       WARNING: the file or device will be wiped.\n");
237                 return 2;
238         }
239
240         if (format_and_add_keyslots(argv[1]))
241                 return 3;
242
243         if (activate_and_check_status(argv[1], "example_device"))
244                 return 4;
245
246         if (handle_active_device("example_device"))
247                 return 5;
248
249         return 0;
250 }