summaryrefslogtreecommitdiffstats
path: root/docs/examples/crypt_luks_usage.c
blob: b690378fdcecaa2d905585566ead0f10782af56e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/*
 *  libcryptsetup API - using LUKS device example
 *
 * Copyright (C) 2011-2024 Red Hat, Inc. All rights reserved.
 *
 * This file is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This file is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this file; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/types.h>
#include <libcryptsetup.h>

static int format_and_add_keyslots(const char *path)
{
	struct crypt_device *cd;
	int r;

	/*
	 * The crypt_init() call is used  to initialize crypt_device context,
	 * The path parameter specifies a device path.
	 *
	 * For path, you can use either link to a file or block device.
	 * The loopback device will be detached automatically.
	 */

	r = crypt_init(&cd, path);
	if (r < 0) {
		printf("crypt_init() failed for %s.\n", path);
		return r;
	}

	printf("Context is attached to block device %s.\n", crypt_get_device_name(cd));

	/*
	 * So far, no data were written to the device.
	 */
	printf("Device %s will be formatted as a LUKS device after 5 seconds.\n"
	       "Press CTRL+C now if you want to cancel this operation.\n", path);
	sleep(5);

	/*
	 * NULLs for uuid and volume_key means that these attributes will be
	 * generated during crypt_format().
	 */
	r = crypt_format(cd,		/* crypt context */
			 CRYPT_LUKS2,	/* LUKS2 is a new LUKS format; use CRYPT_LUKS1 for LUKS1 */
			 "aes",		/* used cipher */
			 "xts-plain64",	/* used block mode and IV */
			 NULL,		/* generate UUID */
			 NULL,		/* generate volume key from RNG */
			 512 / 8,	/* 512bit key - here AES-256 in XTS mode, size is in bytes */
			 NULL);		/* default parameters */

	if (r < 0) {
		printf("crypt_format() failed on device %s\n", crypt_get_device_name(cd));
		crypt_free(cd);
		return r;
	}

	/*
	 * The device now contains a LUKS header, but there is no active keyslot.
	 *
	 * crypt_keyslot_add_* call stores the volume_key in the encrypted form into the keyslot.
	 *
	 * After format, the volume key is stored internally.
	 */
	r = crypt_keyslot_add_by_volume_key(cd,			/* crypt context */
					    CRYPT_ANY_SLOT,	/* just use first free slot */
					    NULL,		/* use internal volume key */
					    0,			/* unused (size of volume key) */
					    "foo",		/* passphrase - NULL means query*/
					    3);			/* size of passphrase */

	if (r < 0) {
		printf("Adding keyslot failed.\n");
		crypt_free(cd);
		return r;
	}

	printf("The first keyslot is initialized.\n");

	/*
	 * Add another keyslot, now authenticating with the first keyslot.
	 * It decrypts the volume key from the first keyslot and creates a new one with the specified passphrase.
	 */
	r = crypt_keyslot_add_by_passphrase(cd,			/* crypt context */
					    CRYPT_ANY_SLOT,	/* just use first free slot */
					    "foo", 3,		/* passphrase for the old keyslot */
					    "bar", 3);		/* passphrase for the new kesylot */
	if (r < 0) {
		printf("Adding keyslot failed.\n");
		crypt_free(cd);
		return r;
	}

	printf("The second keyslot is initialized.\n");

	crypt_free(cd);
	return 0;
}

static int activate_and_check_status(const char *path, const char *device_name)
{
	struct crypt_device *cd;
	struct crypt_active_device cad;
	int r;

	/*
	 * LUKS device activation example.
	 */
	r = crypt_init(&cd, path);
	if (r < 0) {
		printf("crypt_init() failed for %s.\n", path);
		return r;
	}

	/*
	 * crypt_load() is used to load existing LUKS header from a block device
	 */
	r = crypt_load(cd,		/* crypt context */
		       CRYPT_LUKS,	/* requested type - here LUKS of any type */
		       NULL);		/* additional parameters (not used) */

	if (r < 0) {
		printf("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
		crypt_free(cd);
		return r;
	}

	/*
	 * Device activation creates a device-mapper device with the specified name.
	 */
	r = crypt_activate_by_passphrase(cd,		/* crypt context */
					 device_name,	/* device name to activate */
					 CRYPT_ANY_SLOT,/* the keyslot use (try all here) */
					 "foo", 3,	/* passphrase */
					 CRYPT_ACTIVATE_READONLY); /* flags */
	if (r < 0) {
		printf("Device %s activation failed.\n", device_name);
		crypt_free(cd);
		return r;
	}

	printf("%s device %s/%s is active.\n", crypt_get_type(cd), crypt_get_dir(), device_name);
	printf("\tcipher used: %s\n", crypt_get_cipher(cd));
	printf("\tcipher mode: %s\n", crypt_get_cipher_mode(cd));
	printf("\tdevice UUID: %s\n", crypt_get_uuid(cd));

	/*
	 * Get info about the active device.
	 */
	r = crypt_get_active_device(cd, device_name, &cad);
	if (r < 0) {
		printf("Get info about active device %s failed.\n", device_name);
		crypt_deactivate(cd, device_name);
		crypt_free(cd);
		return r;
	}

	printf("Active device parameters for %s:\n"
		"\tDevice offset (in sectors): %" PRIu64 "\n"
		"\tIV offset (in sectors)    : %" PRIu64 "\n"
		"\tdevice size (in sectors)  : %" PRIu64 "\n"
		"\tread-only flag            : %s\n",
		device_name, cad.offset, cad.iv_offset, cad.size,
		cad.flags & CRYPT_ACTIVATE_READONLY ? "1" : "0");

	crypt_free(cd);
	return 0;
}

static int handle_active_device(const char *device_name)
{
	struct crypt_device *cd;
	int r;

	/*
	 * crypt_init_by_name() initializes context by an active device-mapper name
	 */
	r = crypt_init_by_name(&cd, device_name);
	if (r < 0) {
		printf("crypt_init_by_name() failed for %s.\n", device_name);
		return r;
	}

	if (crypt_status(cd, device_name) == CRYPT_ACTIVE)
		printf("Device %s is still active.\n", device_name);
	else {
		printf("Something failed perhaps, device %s is not active.\n", device_name);
		crypt_free(cd);
		return -1;
	}

	/*
	 * crypt_deactivate() is used to deactivate a device
	 */
	r = crypt_deactivate(cd, device_name);
	if (r < 0) {
		printf("crypt_deactivate() failed.\n");
		crypt_free(cd);
		return r;
	}

	printf("Device %s is now deactivated.\n", device_name);

	crypt_free(cd);
	return 0;
}

int main(int argc, char **argv)
{
	if (geteuid()) {
		printf("Using of libcryptsetup requires super user privileges.\n");
		return 1;
	}

	if (argc != 2) {
		printf("usage: ./crypt_luks_usage <path>\n"
			"<path> refers to either a regular file or a block device.\n"
			"       WARNING: the file or device will be wiped.\n");
		return 2;
	}

	if (format_and_add_keyslots(argv[1]))
		return 3;

	if (activate_and_check_status(argv[1], "example_device"))
		return 4;

	if (handle_active_device("example_device"))
		return 5;

	return 0;
}