Add some examples. (thanks to okozina)
authorMilan Broz <gmazyland@gmail.com>
Sat, 8 Oct 2011 19:27:03 +0000 (19:27 +0000)
committerMilan Broz <gmazyland@gmail.com>
Sat, 8 Oct 2011 19:27:03 +0000 (19:27 +0000)
git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@618 36d66b0a-2a48-0410-832c-cd162a569da5

docs/examples/crypt_examples.h [new file with mode: 0644]
docs/examples/crypt_log_usage.c [new file with mode: 0644]
docs/examples/crypt_luks_usage.c [new file with mode: 0644]

diff --git a/docs/examples/crypt_examples.h b/docs/examples/crypt_examples.h
new file mode 100644 (file)
index 0000000..1fdbf75
--- /dev/null
@@ -0,0 +1,20 @@
+#define EX_STEP(step_nr, format, args...)      do { \
+                                                       printf("STEP_%02d: Entering "format"... ", step_nr, ##args); \
+                                               } while(0)
+
+#define EX_FAIL(format, args...)       do { \
+                                               printf("FAIL\n"); \
+                                               fprintf(stderr, "\t"format"\n", ##args); \
+                                       } while(0)
+
+#define EX_SUCCESS(format, args...)    do { \
+                                               printf("OK\n\t"format"\n", ##args); \
+                                       } while(0)
+
+#define EX_DELIM       printf("-------------------------------\n")
+
+#define EX_PRESS_ENTER(msg, args...)   do { \
+                                               printf(msg "\nPress <ENTER> to continue: ", ##args); \
+                                               getc(stdin); \
+                                       } while(0)
+
diff --git a/docs/examples/crypt_log_usage.c b/docs/examples/crypt_log_usage.c
new file mode 100644 (file)
index 0000000..234f8f8
--- /dev/null
@@ -0,0 +1,98 @@
+#include <libcryptsetup.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "crypt_examples.h"
+
+#define LOG_PREFIX_CD  "cslog_example_prefix"
+
+int log_ready = 0;
+
+/*
+ * This is an example of function that can be registered using crypt_set_log_callback API.
+ *
+ * Its prototype is void (*log)(int level, const char *msg, void *usrptr) as defined
+ * in crypt_set_log_callback
+ *
+ * NOTE: that some syslog message levels may not be visible with respect to your
+ *      syslog setings
+ *
+ *      If your syslog daemon is turned off, messages should be printed to stderr
+ */
+static void simple_syslog_wrapper(int level, const char *msg, void *usrptr)
+{
+       if(!log_ready) {
+               openlog((char *)usrptr, LOG_CONS | LOG_PID, LOG_USER);
+               log_ready = 1;
+       }
+       switch(level) {
+               case CRYPT_LOG_NORMAL:
+                       syslog(LOG_NOTICE, msg);
+                       break;
+               case CRYPT_LOG_ERROR:
+                       syslog(LOG_ERR, msg);
+                       break;
+               case CRYPT_LOG_VERBOSE:
+                       syslog(LOG_INFO, msg);
+                       break;
+               case CRYPT_LOG_DEBUG:
+                       syslog(LOG_DEBUG, msg);
+                       break;
+               default:
+                       fprintf(stderr, "Unsupported log level requested!\n");
+       }
+}
+
+int main(void)
+{
+       int step = 0, r = 0;
+       struct crypt_device *cd;
+
+       if (geteuid())
+               fprintf(stderr, "WARN: Process doesn't have super user privileges. "
+                               "Most of examples will fail because of that.\n");
+
+       EX_STEP(++step, "crypt_init() to get an empty device context");
+       if ((r = crypt_init(&cd, NULL))) {
+               EX_FAIL("crypt_init() failed.");
+               return r;
+       }
+       EX_SUCCESS("crypt_init() successfull");
+
+       EX_STEP(++step, "crypt_set_log_callback() to register a log function tied with context");
+       crypt_set_log_callback(cd, &simple_syslog_wrapper, LOG_PREFIX_CD);
+       EX_SUCCESS("");
+       EX_DELIM;
+
+       EX_STEP(++step, "multiple crypt_log() to send messages into the context set log function. "
+                       "The messages should be prefixed with '" LOG_PREFIX_CD "'");
+       crypt_log(cd, CRYPT_LOG_NORMAL, "This is normal log message");
+       crypt_log(cd, CRYPT_LOG_ERROR, "This is error log message");
+       crypt_log(cd, CRYPT_LOG_VERBOSE, "This is verbose log message");
+       crypt_log(cd, CRYPT_LOG_DEBUG, "This is debug message");
+       EX_SUCCESS("");
+       EX_DELIM;
+
+       crypt_free(cd);
+
+       if (log_ready)
+               closelog();
+
+       log_ready = 0;
+
+       EX_STEP(++step, "crypt_set_log_callback() to register a default (global) log function");
+       crypt_set_log_callback(NULL, &simple_syslog_wrapper, NULL);
+       EX_SUCCESS("");
+       EX_DELIM;
+
+       EX_STEP(++step, "multiple crypt_log() to send messages into default log");
+       crypt_log(NULL, CRYPT_LOG_NORMAL, "This is normal log message");
+       crypt_log(NULL, CRYPT_LOG_ERROR, "This is error log message");
+       crypt_log(NULL, CRYPT_LOG_VERBOSE, "This is verbose log message");
+       crypt_log(NULL, CRYPT_LOG_DEBUG, "This is debug message");
+       EX_SUCCESS("");
+
+       return r;
+}
diff --git a/docs/examples/crypt_luks_usage.c b/docs/examples/crypt_luks_usage.c
new file mode 100644 (file)
index 0000000..53e75e4
--- /dev/null
@@ -0,0 +1,306 @@
+#include <inttypes.h>
+#include <libcryptsetup.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "crypt_examples.h"
+
+#define KEY_SIZE 32
+#define EX_DEV_NAME "ex_crypt_dev"
+#define DMDIR "/dev/mapper/"
+#define SECTOR_SIZE 512
+
+/*
+ * You can use this example with command line parameters as follows,
+ * but please note, that this example will not do any sophisticated parameters
+ * checking at all.
+ *
+ * ./crypt_luks_usage <path>
+ *
+ *     where:
+ *     <path> is either regular file or block device. DO NOT use your physical HDD
+ *     with running system or another device containing valuable data otherwise you risk
+ *     partial or complete loss of it.
+ */
+static void usage(const char *msg)
+{
+       fprintf(stderr, "ERROR: %s\nusage: ./crypt_luks_usage <path>\n"
+                       "The <path> can refer to either a regular file or a block device.\n",
+                       msg ?: "");
+}
+
+int main(int argc, char **argv)
+{
+       char *answer = NULL, *cipher, *cipher_mode, *dev;
+       int step = 0, r;
+       size_t size = 0;
+       /* crypt device handle */
+       struct crypt_active_device cad;
+       struct crypt_device *cd;
+       struct crypt_params_luks1 params;
+
+       if (geteuid())
+               fprintf(stderr, "WARN: Process doesn't have super user privileges. "
+                               "Most of examples will fail because of that.\n");
+
+       if (argc != 2) {
+               usage("Wrong number of cmd line parameters.");
+               exit(1);
+       }
+
+       dev = argv[1];
+
+       /*
+        * __STEP_01__
+        *
+        * crypt_init() call precedes most of operations of cryptsetup API. The call is used
+        * to initialize crypt device context stored in structure referenced by _cd_ in
+        * the example. Second parameter is used to pass underlaying device path.
+        *
+        * Note:
+        * If path refers to a regular file it'll be attached to a first free loop device.
+        * crypt_init() operation fails in case there's no more loop device available.
+        * Also, loop device will have the AUTOCLEAR flag set, so the file will be
+        * detached after crypt_free() call on the concerned context.
+        */
+       EX_STEP(++step, "crypt_init()");
+       if ((r = crypt_init(&cd, dev))) {
+               EX_FAIL("crypt_init() failed for '%s'\n", dev ?: "(not set)");
+               return r;
+       }
+       EX_SUCCESS("crypt_init() on '%s' has been successful", dev);
+       if (strcmp(dev, crypt_get_device_name(cd)))
+               printf("\tFile '%s' has been attached to %s\n", dev, crypt_get_device_name(cd));
+
+       EX_DELIM;
+       /*
+        * So far no data were written on your device. This will change with call of
+        * crypt_format() only if you specify CRYPT_LUKS1 as device type.
+        */
+       printf("8 initial sectors of the device will be overwritten\n"
+              "Are you sure you want to call crypt_format() over '%s'?\n"
+              "If you're absolutely sure the device doesn't contain any valuable data,\n"
+              "approve the operation by typing 'yes' in upper case: ", crypt_get_device_name(cd));
+
+       if ((r = getline(&answer, &size, stdin)) == -1) {
+               perror("getline");
+               goto out;
+       }
+
+       if (strcmp(answer, "YES\n"))
+               goto out;
+
+       /* Example of crypt_format() follows: */
+
+       /*
+        * cipher and cipher_mode:
+        *
+        * you'll get more on _cipher_ and _cipher_mode_ in man page
+        * for cryptsetup userspace utility or at cryptsetup project
+        * documentation.
+        */
+       cipher = "aes";
+       cipher_mode = "cbc-essiv:sha256";
+       params.hash = "sha1";
+
+       /*
+        * This parameter is relevant only in case of the luks header
+        * and the payload are both stored on same device.
+        *
+        * In this particular case, payload offset (which is
+        * computed internaly, according to volume key size)
+        * is aligned to 2048 sectors
+        *
+        * if you set data_alignment = 0, cryptsetup will autodetect
+        * data_alignment from underlaying device topology.
+        */
+       params.data_alignment = 2048;
+
+       /*
+        * this parameter defines that no external device
+        * for luks header will be used
+        */
+       params.data_device = NULL;
+
+       /*
+        * __STEP_02__
+        *
+        * NULLs for uuid and volume_key means that these attributes will be
+        * generated during crypt_format(). Volume key is generated with respect
+        * to key size parameter passed to function.
+        *
+        * Note that in crypt_format() device is checked wheter it's large enough to
+        * store the luks header only.
+        */
+       EX_STEP(++step, "crypt_format()");
+       if((r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, NULL, KEY_SIZE, &params))) {
+               EX_FAIL("crypt_format() failed on device %s\n", crypt_get_device_name(cd));
+               goto out;
+       }
+       EX_SUCCESS("crypt_format() on device %s formated successfully. "
+                       "The device now contains LUKS1 header, but there is no active keyslot with encrypted "
+                       "volume key.", crypt_get_device_name(cd));
+       EX_DELIM;
+
+       /*
+        * __STEP_03__
+        *
+        * This call is intended to store volume_key in encrypted form into structure called keyslot.
+        * Without keyslot you can't manipulate with LUKS device after the context will be freed.
+        *
+        * To create a new keyslot you need to supply the existing one (to get the volume key from) or
+        * you need to supply the volume key. Now we have volume key stored internally and we have no active
+        * keyslot so this the only option.
+        *
+        */
+       printf("Going to create a new keyslot...\n");
+       EX_STEP(++step, "crypt_keyslot_add_by_volume_key()");
+       if ((r = crypt_keyslot_add_by_volume_key(cd, CRYPT_ANY_SLOT, NULL, 0, NULL, 0)) < 0) {
+               EX_FAIL("Adding keyslot failed.");
+               goto out;
+       }
+       EX_SUCCESS("Keyslot nr. %d created successfully on device %s.", r, crypt_get_device_name(cd));
+       EX_DELIM;
+
+       /*
+        * __STEP_04__
+        *
+        * This is the example of the second method mentioned in STEP 03. By supplying passphrase for
+        * the active keyslot you can create a new one.
+        */
+       printf("Now let's try to add a keyslot using the existing active keyslot\n");
+       EX_STEP(++step, "crypt_keyslot_add_by_passphrase()");
+       if ((r = crypt_keyslot_add_by_passphrase(cd, CRYPT_ANY_SLOT, NULL, 0, NULL, 0)) < 0) {
+               EX_FAIL("Adding keyslot failed\n");
+               goto out;
+       }
+       EX_SUCCESS("Keyslot nr. %d created successfully and written on device %s.", r, crypt_get_device_name(cd));
+       EX_DELIM;
+
+       crypt_free(cd);
+       cd = NULL;
+
+       /*
+        * __STEP_05__
+        *
+        * In previous steps the device was formatted (LUKS header was written to backing device)
+        * and keyslots were activated (volume key was written in two separate structures encrypted
+        * by two user supplied passwords).
+        *
+        * This example demonstrates typical use case for LUKS device activation.
+        * It's sequence of sub-steps: device initialization (crypt_init), LUKS header load (crypt_load())
+        * and finally the device activation itself
+        */
+       EX_PRESS_ENTER("Device context going to be freed. New one will initialized to demonstrate activation process.");
+       EX_STEP(++step, "crypt_init()");
+       if ((r = crypt_init(&cd, dev))) {
+               EX_FAIL("crypt_init() failed for '%s'!", dev);
+               goto out;
+       }
+       EX_SUCCESS("crypt_init() on '%s' has been successful.", dev);
+       if (strcmp(dev, crypt_get_device_name(cd)))
+               printf("\tFile '%s' has been attached to %s\n", dev, crypt_get_device_name(cd));
+       EX_DELIM;
+       /* __STEP_05__
+        *
+        * crypt_load() is used to load the LUKS header from backing block device
+        * into crypt_device context
+        */
+       EX_PRESS_ENTER("Going to load LUKS header.");
+       EX_STEP(step, "crypt_load()");
+       if ((r = crypt_load(cd, CRYPT_LUKS1, &params))) {
+               EX_FAIL("crypt_load() failed on device '%s'!", crypt_get_device_name(cd));
+               goto out;
+       }
+       EX_SUCCESS("crypt_load() successful. The header has been read from %s.", crypt_get_device_name(cd));
+       EX_DELIM;
+
+       /*
+        * __STEP_05__
+        *
+        * Device activation creates mapping in device-mapper with name EX_DEV_NAME.
+        * The volume key is stored into kernel mem. space and the encryption of backing
+        * device is now set in motion.
+        */
+       printf("Going to activate LUKS device\n");
+       EX_STEP(step, "crypt_activate_by_passphrase()");
+       if ((r = crypt_activate_by_passphrase(cd, EX_DEV_NAME, CRYPT_ANY_SLOT, NULL, 0, 0)) < 0) {
+               EX_FAIL("Device activation failed!");
+               goto out;
+       }
+       EX_SUCCESS("Encrypted device is active on " DMDIR EX_DEV_NAME ".");
+       printf("\tThe cipher used in device context: '%s'\n", crypt_get_cipher(cd) ?: "(not set) !");
+       printf("\tThe cipher mode used in device context: '%s'\n", crypt_get_cipher_mode(cd) ?: "(not set) !");
+       printf("\tThe device UUID '%s'\n", crypt_get_uuid(cd) ?: "(not set) !");
+       EX_DELIM;
+
+       /*
+        * __STEP_06__
+        *
+        * Get info about active device (query DM backend)
+        */
+       EX_PRESS_ENTER("Going to get active active device parameters.");
+       EX_STEP(++step, "crypt_get_active_device()");
+       if ((r = crypt_get_active_device(cd, EX_DEV_NAME, &cad))) {
+               EX_FAIL("Get info about active device '%s' failed!", EX_DEV_NAME);
+               goto out;
+       }
+       EX_SUCCESS("Active device parameters for " EX_DEV_NAME ":\n"
+                       "\tPayload offset (in sectors): %" PRIu64 "\n"
+                       "\tEncrypted payload area size in sectors: %" PRIu64 " and bytes: %" PRIu64 "\n"
+                       "\tThe device has a read-only flag %sset",
+                       cad.offset, cad.size, cad.size * SECTOR_SIZE,
+                       cad.flags & CRYPT_ACTIVATE_READONLY ? "" : "not ");
+       EX_DELIM;
+
+       crypt_free(cd);
+       cd = NULL;
+
+       /*
+        * __STEP_07__
+        *
+        * crypt_init_by_name() initializes device context and loads LUKS header from backing device
+        */
+       EX_PRESS_ENTER("The context used in previous examples is going to be freed to demonstrate "
+                       "how to initialize a device context from the active device.");
+       EX_STEP(++step, "crypt_init_by_name()");
+       if ((r = crypt_init_by_name(&cd, EX_DEV_NAME))) {
+               EX_FAIL("crypt_init_by_name() failed for the device name: " EX_DEV_NAME);
+               goto out;
+       }
+       EX_SUCCESS("A new context has been initialized, LUKS header has been restored"
+                       "\n\tDevice UUID is '%s'", crypt_get_uuid(cd));
+
+       /*
+        * __STEP_08__
+        *
+        * crypt_deactivate() is used to remove the volume_key from kernel mem. space and to remove the
+        * device nod associated with decrypted backing device.
+        *
+        */
+       EX_PRESS_ENTER("\n\tGoing to deactivate the crypt device. Note that the device "
+                       "won't be deactivated while it's opened with O_EXCL flag (e.g. mounted).");
+       EX_STEP(++step, "crypt_deactivate()");
+       //printf("\nPress <ENTER> to continue to device deactivation of the test device.\n"
+       //      "Note that mounted device won't be deactivated. First unmount the device!");
+       //getc(stdin);
+       while ((r = crypt_deactivate(cd, EX_DEV_NAME))) {
+               EX_FAIL("crypt_deactivate() failed. Most propably the device is still busy!");
+               EX_PRESS_ENTER("Going to retry device deactivation");
+       }
+       EX_SUCCESS("crypt_deactivate() successful. Device " DMDIR EX_DEV_NAME " is now deactivated");
+
+out:
+       if (crypt_status(cd, EX_DEV_NAME) == CRYPT_ACTIVE)
+               crypt_deactivate(cd, EX_DEV_NAME);
+       if (answer)
+               free(answer);
+       /* always free context which is no longer used  */
+       if (cd)
+               crypt_free(cd);
+
+       return r;
+}