static char * _volume_device_name( const char * mapper,char * ( *function )( const char * ) ) { struct crypt_device * cd ; const char * e = crypt_get_dir() ; char * f = NULL ; if( zuluCryptTrueCryptOrVeraCryptVolume( mapper ) ){ return _device_name( mapper,function ) ; }else{ if( crypt_init_by_name( &cd,mapper ) == 0 ){ e = crypt_get_device_name( cd ) ; if( e != NULL ){ f = function( e ) ; } crypt_free( cd ) ; } return f ; } }
/** * Opens the device with the specified flags. * * The length parameter is set to the amount of space in the gap between the * end of the last slot and the start of the encrypted data. * * The function returns either the file descriptor positioned to the start of * the hole or a negative errno. */ static int open_hole(struct crypt_device *cd, int flags, uint32_t *length) { const char *name = NULL; const char *type = NULL; uint64_t hole = 0; uint64_t data = 0; int fd = 0; int r = 0; type = crypt_get_type(cd); if (!type || strcmp(CRYPT_LUKS1, type) != 0) return -ENOTSUP; data = crypt_get_data_offset(cd) * 512; if (data < 4096) return -ENOSPC; for (int slot = 0; slot < LUKS_NSLOTS; slot++) { uint64_t off = 0; uint64_t len = 0; r = crypt_keyslot_area(cd, slot, &off, &len); if (r < 0) return r; if (hole < off + len) hole = ALIGN(off + len, true); } if (hole == 0) return -ENOTSUP; if (hole >= data) return -ENOSPC; name = crypt_get_device_name(cd); if (!name) return -ENOTSUP; fd = open(name, flags); if (fd < 0) return -errno; if (lseek(fd, hole, SEEK_SET) == -1) { close(fd); return -errno; } *length = ALIGN(data - hole, false); return fd; }
static string_t _get_crypto_info_from_cryptsetup( const char * mapper ) { char buff[ SIZE ] ; char * buffer = buff ; const char * z ; const char * type ; uint64_t e ; string_t q ; string_t p ; int k ; int i = 0 ; int j ; crypt_status_info info ; struct crypt_device * cd ; struct crypt_active_device cad ; if( crypt_init_by_name( &cd,mapper ) != 0 ){ return StringVoid ; } p = String( mapper ) ; info = crypt_status( cd,mapper ) ; switch( info ){ case CRYPT_INACTIVE : StringAppend( p," is inactive.\n" ) ; break ; case CRYPT_INVALID : StringAppend( p," is invalid.\n" ) ; break ; case CRYPT_ACTIVE : StringAppend( p," is active.\n" ) ; break ; case CRYPT_BUSY : StringAppend( p," is active and is in use.\n" ) ; break ; default : StringAppend( p," is invalid.\n" ) ; } if( info == CRYPT_ACTIVE || info == CRYPT_BUSY ){ StringAppend( p," type: \t" ) ; type = crypt_get_type( cd ) ; if( type != NULL ){ q = String( type ) ; StringAppend( p,StringToLowerCase( q ) ) ; StringDelete( &q ) ; }else{ q = _get_type_from_udev_1( mapper ) ; StringAppendString( p,q ) ; StringDelete( &q ) ; } z = crypt_get_cipher( cd ) ; if( z != NULL ){ StringMultipleAppend( p,"\n cipher:\t",z,"-",NULL ) ; }else{ StringAppend( p,"\n cipher:\tNil-" ) ; } z = crypt_get_cipher_mode( cd ) ; if( z != NULL ){ StringAppend( p,z ) ; }else{ StringAppend( p,"Nil" ) ; } z = StringIntToString_1( buffer,SIZE,8 * crypt_get_volume_key_size( cd ) ) ; StringMultipleAppend( p,"\n keysize:\t",z," bits",NULL ) ; e = crypt_get_data_offset( cd ) ; z = StringIntToString_1( buffer,SIZE,e ) ; StringMultipleAppend( p,"\n offset:\t",z," sectors",NULL ) ; zuluCryptFormatSize( e * 512,buffer,SIZE ) ; StringMultipleAppend( p," / ",buffer,NULL ) ; _device_info( p,crypt_get_device_name( cd ) ) ; crypt_get_active_device( NULL,mapper,&cad ) ; if( cad.flags == 1 ){ StringAppend( p,"\n mode: \tread only" ) ; }else{ StringAppend( p,"\n mode: \tread and write" ) ; } k = crypt_keyslot_max( crypt_get_type( cd ) ) ; if( k > 0 ){ i = 0 ; for( j = 0 ; j < k ; j++ ){ switch( crypt_keyslot_status( cd,j ) ){ case CRYPT_SLOT_ACTIVE_LAST : i++ ; break ; case CRYPT_SLOT_ACTIVE : i++ ; break ; default : ; } } StringMultipleAppend( p,"\n active slots:\t",StringIntToString_1( buffer,SIZE,i ),NULL ) ; StringMultipleAppend( p," / ",StringIntToString_1( buffer,SIZE,k ),NULL ) ; }else{ StringAppend( p,"\n active slots:\tNil" ) ; } } crypt_free( cd ) ; return p ; }
static int format_and_add_keyslots(const char *path) { struct crypt_device *cd; struct crypt_params_luks1 params; int r; /* * 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 loopback 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 on your device. This will change with call of * crypt_format() only if you specify CRYPT_LUKS1 as device type. */ printf("Device %s will be formatted to LUKS device after 5 seconds.\n" "Press CTRL+C now if you want to cancel this operation.\n", path); sleep(5); /* * Prepare LUKS format parameters * * hash parameter defines PBKDF2 hash algorithm used in LUKS header. * For compatibility reason we use SHA1 here. */ params.hash = "sha1"; /* * data_alignment parameter is relevant only in case of the luks header * and the payload are both stored on same device. * * if you set data_alignment = 0, cryptsetup will autodetect * data_alignment according to underlaying device topology. */ params.data_alignment = 0; /* * data_device parameter defines that no external device * for luks header will be used */ params.data_device = NULL; /* * 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. * * crypt_format() checks device size (LUKS header must fit there). */ r = crypt_format(cd, /* crypt context */ CRYPT_LUKS1, /* LUKS1 is standard LUKS header */ "aes", /* used cipher */ "xts-plain64", /* used block mode and IV generator*/ NULL, /* generate UUID */ NULL, /* generate volume key from RNG */ 256 / 8, /* 256bit key - here AES-128 in XTS mode, size is in bytes */ ¶ms); /* parameters above */ 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 LUKS1 header, but there is * no active keyslot with encrypted volume key yet. */ /* * cryptt_kesylot_add_* call stores volume_key in encrypted form into 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. * * After format, we have volume key stored internally in context so add new keyslot * using this internal volume key. */ 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 using the first keyslot. * It will decrypt volume key from the first keyslot and creates new one with another 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. * It's sequence of sub-steps: device initialization, LUKS header load * and the device activation itself. */ r = crypt_init(&cd, path); if (r < 0 ) { printf("crypt_init() failed for %s.\n", path); return r; } /* * crypt_load() is used to load the LUKS header from block device * into crypt_device context. */ r = crypt_load(cd, /* crypt context */ CRYPT_LUKS1, /* requested 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 device-mapper devie mapping with name device_name. */ r = crypt_activate_by_passphrase(cd, /* crypt context */ device_name, /* device name to activate */ CRYPT_ANY_SLOT,/* which slot use (ANY - try all) */ "foo", 3, /* passphrase */ CRYPT_ACTIVATE_READONLY); /* flags */ if (r < 0) { printf("Device %s activation failed.\n", device_name); crypt_free(cd); return r; } printf("LUKS device %s/%s is active.\n", 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 active device (query DM backend) */ 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 action_format(int arg) { struct crypt_device *cd = NULL; struct crypt_params_integrity params = { .journal_size = opt_journal_size, .interleave_sectors = opt_interleave_sectors, /* in bitmap mode we have to overload these values... */ .journal_watermark = opt_integrity_bitmap ? opt_bitmap_sectors_per_bit : opt_journal_watermark, .journal_commit_time = opt_integrity_bitmap ? opt_bitmap_flush_time : opt_journal_commit_time, .buffer_sectors = opt_buffer_sectors, .tag_size = opt_tag_size, .sector_size = opt_sector_size ?: SECTOR_SIZE, }; char integrity[MAX_CIPHER_LEN], journal_integrity[MAX_CIPHER_LEN], journal_crypt[MAX_CIPHER_LEN]; char *integrity_key = NULL, *msg = NULL; int r; size_t signatures; if (opt_integrity) { r = crypt_parse_hash_integrity_mode(opt_integrity, integrity); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.integrity = integrity; } if (opt_journal_integrity) { r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.journal_integrity = journal_integrity; } if (opt_journal_crypt) { r = crypt_parse_hash_integrity_mode(opt_journal_crypt, journal_crypt); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.journal_crypt = journal_crypt; } r = _read_keys(&integrity_key, ¶ms); if (r) goto out; r = crypt_init_data_device(&cd, action_argv[0], opt_data_device); if (r < 0) goto out; r = asprintf(&msg, _("This will overwrite data on %s irrevocably."), action_argv[0]); if (r == -1) { r = -ENOMEM; goto out; } r = yesDialog(msg, _("Operation aborted.\n")) ? 0 : -EINVAL; free(msg); if (r < 0) goto out; r = tools_detect_signatures(action_argv[0], 0, &signatures); if (r < 0) goto out; /* Signature candidates found */ if (signatures && ((r = tools_wipe_all_signatures(action_argv[0])) < 0)) goto out; r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, ¶ms); if (r < 0) /* FIXME: call wipe signatures again */ goto out; if (!opt_batch_mode) log_std(_("Formatted with tag size %u, internal integrity %s.\n"), opt_tag_size, opt_integrity); if (!opt_no_wipe) r = _wipe_data_device(cd, integrity_key); out: crypt_safe_free(integrity_key); crypt_safe_free(CONST_CAST(void*)params.journal_integrity_key); crypt_safe_free(CONST_CAST(void*)params.journal_crypt_key); crypt_free(cd); return r; } static int action_open(int arg) { struct crypt_device *cd = NULL; struct crypt_params_integrity params = { /* in bitmap mode we have to overload these values... */ .journal_watermark = opt_integrity_bitmap ? opt_bitmap_sectors_per_bit : opt_journal_watermark, .journal_commit_time = opt_integrity_bitmap ? opt_bitmap_flush_time : opt_journal_commit_time, .buffer_sectors = opt_buffer_sectors, }; uint32_t activate_flags = 0; char integrity[MAX_CIPHER_LEN], journal_integrity[MAX_CIPHER_LEN], journal_crypt[MAX_CIPHER_LEN]; char *integrity_key = NULL; int r; if (opt_integrity) { r = crypt_parse_hash_integrity_mode(opt_integrity, integrity); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.integrity = integrity; } if (opt_journal_integrity) { r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.journal_integrity = journal_integrity; } if (opt_journal_crypt) { r = crypt_parse_hash_integrity_mode(opt_journal_crypt, journal_crypt); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.journal_crypt = journal_crypt; } if (opt_integrity_nojournal || opt_integrity_bitmap) activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL; if (opt_integrity_recovery) activate_flags |= CRYPT_ACTIVATE_RECOVERY; if (opt_integrity_bitmap) activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP; if (opt_integrity_recalculate) activate_flags |= CRYPT_ACTIVATE_RECALCULATE; r = _read_keys(&integrity_key, ¶ms); if (r) goto out; if ((r = crypt_init_data_device(&cd, action_argv[0], opt_data_device))) goto out; r = crypt_load(cd, CRYPT_INTEGRITY, ¶ms); if (r) goto out; r = crypt_activate_by_volume_key(cd, action_argv[1], integrity_key, opt_integrity_key_size, activate_flags); out: crypt_safe_free(integrity_key); crypt_safe_free(CONST_CAST(void*)params.journal_integrity_key); crypt_safe_free(CONST_CAST(void*)params.journal_crypt_key); crypt_free(cd); return r; } static int action_close(int arg) { struct crypt_device *cd = NULL; int r; r = crypt_init_by_name(&cd, action_argv[0]); if (r == 0) r = crypt_deactivate(cd, action_argv[0]); crypt_free(cd); return r; } static int action_status(int arg) { crypt_status_info ci; struct crypt_active_device cad; struct crypt_params_integrity ip = {}; struct crypt_device *cd = NULL; char *backing_file; const char *device, *metadata_device; int path = 0, r = 0; /* perhaps a path, not a dm device name */ if (strchr(action_argv[0], '/')) path = 1; ci = crypt_status(NULL, action_argv[0]); switch (ci) { case CRYPT_INVALID: r = -EINVAL; break; case CRYPT_INACTIVE: if (path) log_std("%s is inactive.\n", action_argv[0]); else log_std("%s/%s is inactive.\n", crypt_get_dir(), action_argv[0]); r = -ENODEV; break; case CRYPT_ACTIVE: case CRYPT_BUSY: if (path) log_std("%s is active%s.\n", action_argv[0], ci == CRYPT_BUSY ? " and is in use" : ""); else log_std("%s/%s is active%s.\n", crypt_get_dir(), action_argv[0], ci == CRYPT_BUSY ? " and is in use" : ""); r = crypt_init_by_name_and_header(&cd, action_argv[0], NULL); if (r < 0) goto out; log_std(" type: %s\n", crypt_get_type(cd) ?: "n/a"); r = crypt_get_active_device(cd, action_argv[0], &cad); if (r < 0) goto out; r = crypt_get_integrity_info(cd, &ip); if (r < 0) goto out; log_std(" tag size: %u\n", ip.tag_size); log_std(" integrity: %s\n", ip.integrity ?: "(none)"); device = crypt_get_device_name(cd); metadata_device = crypt_get_metadata_device_name(cd); log_std(" device: %s%s\n", device, metadata_device ? " (detached)" : ""); if (crypt_loop_device(device)) { backing_file = crypt_loop_backing_file(device); log_std(" loop: %s\n", backing_file); free(backing_file); } if (metadata_device) { log_std(" metadata device: %s\n", metadata_device); if (crypt_loop_device(metadata_device)) { backing_file = crypt_loop_backing_file(metadata_device); log_std(" loop: %s\n", backing_file); free(backing_file); } } log_std(" sector size: %u bytes\n", crypt_get_sector_size(cd)); log_std(" interleave sectors: %u\n", ip.interleave_sectors); log_std(" size: %" PRIu64 " sectors\n", cad.size); log_std(" mode: %s%s\n", cad.flags & CRYPT_ACTIVATE_READONLY ? "readonly" : "read/write", cad.flags & CRYPT_ACTIVATE_RECOVERY ? " recovery" : ""); log_std(" failures: %" PRIu64 "\n", crypt_get_active_integrity_failures(cd, action_argv[0])); if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) { log_std(" bitmap 512-byte sectors per bit: %u\n", ip.journal_watermark); log_std(" bitmap flush interval: %u ms\n", ip.journal_commit_time); } if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL) { log_std(" journal: not active\n"); } else { log_std(" journal size: %" PRIu64 " bytes\n", ip.journal_size); log_std(" journal watermark: %u%%\n", ip.journal_watermark); log_std(" journal commit time: %u ms\n", ip.journal_commit_time); if (ip.journal_integrity) log_std(" journal integrity MAC: %s\n", ip.journal_integrity); if (ip.journal_crypt) log_std(" journal encryption: %s\n", ip.journal_crypt); } } out: crypt_free(cd); if (r == -ENOTSUP) r = 0; return r; return -EINVAL; } static int action_dump(int arg) { struct crypt_device *cd = NULL; struct crypt_params_integrity params = {}; int r; if ((r = crypt_init(&cd, action_argv[0]))) return r; r = crypt_load(cd, CRYPT_INTEGRITY, ¶ms); if (!r) crypt_dump(cd); crypt_free(cd); return r; } static struct action_type { const char *type; int (*handler)(int); int required_action_argc; const char *arg_desc; const char *desc; } action_types[] = { { "format", action_format, 1, N_("<integrity_device>"),N_("format device") }, { "open", action_open, 2, N_("<integrity_device> <name>"),N_("open device as <name>") }, { "close", action_close, 1, N_("<name>"),N_("close device (deactivate and remove mapping)") }, { "status", action_status, 1, N_("<name>"),N_("show active device status") }, { "dump", action_dump, 1, N_("<integrity_device>"),N_("show on-disk information") }, { NULL, NULL, 0, NULL, NULL } }; static void help(poptContext popt_context, enum poptCallbackReason reason __attribute__((unused)), struct poptOption *key, const char *arg __attribute__((unused)), void *data __attribute__((unused))) { struct action_type *action; if (key->shortName == '?') { log_std("%s %s\n", PACKAGE_INTEGRITY, PACKAGE_VERSION); poptPrintHelp(popt_context, stdout, 0); log_std(_("\n" "<action> is one of:\n")); for(action = action_types; action->type; action++) log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc)); log_std(_("\n" "<name> is the device to create under %s\n" "<integrity_device> is the device containing data with integrity tags\n"), crypt_get_dir()); log_std(_("\nDefault compiled-in dm-integrity parameters:\n" "\tTag size: %u bytes, Checksum algorithm: %s\n"), DEFAULT_TAG_SIZE, DEFAULT_ALG_NAME); exit(EXIT_SUCCESS); } else usage(popt_context, EXIT_SUCCESS, NULL, NULL); } static int run_action(struct action_type *action) { int r; log_dbg("Running command %s.", action->type); r = action->handler(0); show_status(r); return translate_errno(r); }