/* * Generate a new encryption key for use in volume encryption. * We don't ask the user for a encryption key but generate a semi * random passphrase of the wanted length which is way stronger. * When the config has a wrap key we use that to wrap the newly * created passphrase using RFC3394 aes wrap and always convert * the passphrase into a base64 encoded string. This key is * stored in the database and is passed to the storage daemon * when needed. The storage daemon has the same wrap key per * director so it can unwrap the passphrase for use. * * Changing the wrap key will render any previously created * crypto keys useless so only change the wrap key after initial * setting when you know what you are doing and always store * the old key somewhere save so you can use bscrypto to * convert them for the new wrap key. */ static bool generate_new_encryption_key(UAContext *ua, MEDIA_DBR *mr) { int length; char *passphrase; passphrase = generate_crypto_passphrase(DEFAULT_PASSPHRASE_LENGTH); if (!passphrase) { ua->error_msg(_("Failed to generate new encryption passphrase for Volume %s.\n"), mr->VolumeName); return false; } /* * See if we need to wrap the passphrase. */ if (me->keyencrkey) { char *wrapped_passphrase; length = DEFAULT_PASSPHRASE_LENGTH + 8; wrapped_passphrase = (char *)malloc(length); memset(wrapped_passphrase, 0, length); aes_wrap((unsigned char *)me->keyencrkey, DEFAULT_PASSPHRASE_LENGTH / 8, (unsigned char *)passphrase, (unsigned char *)wrapped_passphrase); free(passphrase); passphrase = wrapped_passphrase; } else { length = DEFAULT_PASSPHRASE_LENGTH; } /* * The passphrase is always base64 encoded. */ bin_to_base64(mr->EncrKey, sizeof(mr->EncrKey), passphrase, length, true); free(passphrase); return true; }
int main(int argc, char *const *argv) { int retval = 0; int ch, kfd, length; bool base64_transform = false, clear_encryption = false, drive_encryption_status = false, generate_passphrase = false, populate_cache = false, set_encryption = false, show_keydata = false, volume_encryption_status = false, wrapped_keys = false; char *keyfile = NULL; char *cache_file = NULL; char *wrap_keyfile = NULL; char keydata[64]; char wrapdata[64]; setlocale(LC_ALL, ""); bindtextdomain("bareos", LOCALEDIR); textdomain("bareos"); while ((ch = getopt(argc, argv, "bcd:eg:k:p:s:vw:?")) != -1) { switch (ch) { case 'b': base64_transform = true; break; case 'c': clear_encryption = true; break; case 'd': debug_level = atoi(optarg); if (debug_level <= 0) { debug_level = 1; } break; case 'e': drive_encryption_status = true; break; case 'g': generate_passphrase = true; if (keyfile) { usage(); goto bail_out; } keyfile = bstrdup(optarg); break; case 'k': show_keydata = true; if (keyfile) { usage(); goto bail_out; } keyfile = bstrdup(optarg); break; case 'p': populate_cache = true; cache_file = bstrdup(optarg); break; case 's': set_encryption = true; if (keyfile) { usage(); goto bail_out; } keyfile = bstrdup(optarg); break; case 'v': volume_encryption_status = true; break; case 'w': wrapped_keys = true; wrap_keyfile = bstrdup(optarg); break; case '?': default: usage(); goto bail_out; } } argc -= optind; argv += optind; if (!generate_passphrase && !show_keydata && !populate_cache && argc < 1) { fprintf(stderr, _("Missing device_name argument for this option\n")); usage(); retval = 1; goto bail_out; } if (generate_passphrase && show_keydata) { fprintf(stderr, _("Either use -g or -k not both\n")); retval = 1; goto bail_out; } if (clear_encryption && set_encryption) { fprintf(stderr, _("Either use -c or -s not both\n")); retval = 1; goto bail_out; } if ((clear_encryption || set_encryption) && (drive_encryption_status || volume_encryption_status)) { fprintf(stderr, _("Either set or clear the crypto key or ask for status not both\n")); retval = 1; goto bail_out; } if ((clear_encryption || set_encryption || drive_encryption_status || volume_encryption_status) && (generate_passphrase || show_keydata || populate_cache)) { fprintf(stderr, _("Don't mix operations which are incompatible " "e.g. generate/show vs set/clear etc.\n")); retval = 1; goto bail_out; } OSDependentInit(); init_msg(NULL, NULL); if (populate_cache) { char *VolumeName, *EncrKey; char new_cache_entry[256]; /* * Load any keys currently in the cache. */ read_crypto_cache(cache_file); /* * Read new entries from stdin and parse them to update * the cache. */ fprintf(stdout, _("Enter cache entrie(s) (close with ^D): ")); fflush(stdout); while (read(1, new_cache_entry, sizeof(new_cache_entry)) > 0) { strip_trailing_junk(new_cache_entry); /* * Try to parse the entry. */ VolumeName = new_cache_entry; EncrKey = strchr(new_cache_entry, '\t'); if (!EncrKey) { break; } *EncrKey++ = '\0'; update_crypto_cache(VolumeName, EncrKey); } /* * Write out the new cache entries. */ write_crypto_cache(cache_file); goto bail_out; } memset(keydata, 0, sizeof(keydata)); memset(wrapdata, 0, sizeof(wrapdata)); if (wrapped_keys) { /* * Read the key bits from the keyfile. * - == stdin */ if (bstrcmp(wrap_keyfile, "-")) { kfd = 0; fprintf(stdout, _("Enter Key Encryption Key: ")); fflush(stdout); } else { kfd = open(wrap_keyfile, O_RDONLY); if (kfd < 0) { fprintf(stderr, _("Cannot open keyfile %s\n"), wrap_keyfile); retval = 1; goto bail_out; } } read(kfd, wrapdata, sizeof(wrapdata)); if (kfd > 0) { close(kfd); } strip_trailing_junk(wrapdata); Dmsg1(10, "Wrapped keydata = %s\n", wrapdata); } /* * Generate a new passphrase allow it to be wrapped using the given wrapkey * and base64 if specified or when wrapped. */ if (generate_passphrase) { int cnt; char *passphrase; passphrase = generate_crypto_passphrase(DEFAULT_PASSPHRASE_LENGTH); if (!passphrase) { retval = 1; goto bail_out; } Dmsg1(10, "Generated passphrase = %s\n", passphrase); /* * See if we need to wrap the passphrase. */ if (wrapped_keys) { char *wrapped_passphrase; length = DEFAULT_PASSPHRASE_LENGTH + 8; wrapped_passphrase = (char *)malloc(length); memset(wrapped_passphrase, 0, length); aes_wrap((unsigned char *)wrapdata, DEFAULT_PASSPHRASE_LENGTH / 8, (unsigned char *)passphrase, (unsigned char *)wrapped_passphrase); free(passphrase); passphrase = wrapped_passphrase; } else { length = DEFAULT_PASSPHRASE_LENGTH; } /* * See where to write the key. * - == stdout */ if (bstrcmp(keyfile, "-")) { kfd = 1; } else { kfd = open(keyfile, O_WRONLY | O_CREAT, 0644); if (kfd < 0) { fprintf(stderr, _("Cannot open keyfile %s\n"), keyfile); free(passphrase); retval = 1; goto bail_out; } } if (base64_transform || wrapped_keys) { cnt = bin_to_base64(keydata, sizeof(keydata), passphrase, length, true); if (write(kfd, keydata, cnt) != cnt) { fprintf(stderr, _("Failed to write %d bytes to keyfile %s\n"), cnt, keyfile); } } else { cnt = DEFAULT_PASSPHRASE_LENGTH; if (write(kfd, passphrase, cnt) != cnt) { fprintf(stderr, _("Failed to write %d bytes to keyfile %s\n"), cnt, keyfile); } } Dmsg1(10, "Keydata = %s\n", keydata); if (kfd > 1) { close(kfd); } else { write(kfd, "\n", 1); } free(passphrase); goto bail_out; } if (show_keydata) { char *passphrase; /* * Read the key bits from the keyfile. * - == stdin */ if (bstrcmp(keyfile, "-")) { kfd = 0; fprintf(stdout, _("Enter Encryption Key: ")); fflush(stdout); } else { kfd = open(keyfile, O_RDONLY); if (kfd < 0) { fprintf(stderr, _("Cannot open keyfile %s\n"), keyfile); retval = 1; goto bail_out; } } read(kfd, keydata, sizeof(keydata)); if (kfd > 0) { close(kfd); } strip_trailing_junk(keydata); Dmsg1(10, "Keydata = %s\n", keydata); /* * See if we need to unwrap the passphrase. */ if (wrapped_keys) { char *wrapped_passphrase; /* * A wrapped key is base64 encoded after it was wrapped so first * convert it from base64 to bin. As we first go from base64 to bin * and the base64_to_bin has a check if the decoded string will fit * we need to alocate some more bytes for the decoded buffer to be * sure it will fit. */ length = DEFAULT_PASSPHRASE_LENGTH + 12; wrapped_passphrase = (char *)malloc(length); memset(wrapped_passphrase, 0, length); if (base64_to_bin(wrapped_passphrase, length, keydata, strlen(keydata)) == 0) { fprintf(stderr, _("Failed to base64 decode the keydata read from %s, aborting...\n"), keyfile); free(wrapped_passphrase); goto bail_out; } length = DEFAULT_PASSPHRASE_LENGTH; passphrase = (char *)malloc(length); memset(passphrase, 0, length); if (aes_unwrap((unsigned char *)wrapdata, length / 8, (unsigned char *)wrapped_passphrase, (unsigned char *)passphrase) == -1) { fprintf(stderr, _("Failed to aes unwrap the keydata read from %s using the wrap data from %s, aborting...\n"), keyfile, wrap_keyfile); free(wrapped_passphrase); goto bail_out; } free(wrapped_passphrase); } else { if (base64_transform) { /* * As we first go from base64 to bin and the base64_to_bin has a check * if the decoded string will fit we need to alocate some more bytes * for the decoded buffer to be sure it will fit. */ length = DEFAULT_PASSPHRASE_LENGTH + 4; passphrase = (char *)malloc(length); memset(passphrase, 0, length); base64_to_bin(passphrase, length, keydata, strlen(keydata)); } else { length = DEFAULT_PASSPHRASE_LENGTH; passphrase = (char *)malloc(length); memset(passphrase, 0, length); bstrncpy(passphrase, keydata, length); } } Dmsg1(10, "Unwrapped passphrase = %s\n", passphrase); fprintf(stdout, "%s\n", passphrase); free(passphrase); goto bail_out; } /* * Clear the loaded encryption key of the given drive. */ if (clear_encryption) { if (clear_scsi_encryption_key(-1, argv[0])) { goto bail_out; } else { retval = 1; goto bail_out; } } /* * Get the drive encryption status of the given drive. */ if (drive_encryption_status) { POOLMEM *encryption_status = get_pool_memory(PM_MESSAGE); if (get_scsi_drive_encryption_status(-1, argv[0], encryption_status, 0)) { fprintf(stdout, "%s", encryption_status); free_pool_memory(encryption_status); } else { retval = 1; free_pool_memory(encryption_status); goto bail_out; } } /* * Load a new encryption key onto the given drive. */ if (set_encryption) { /* * Read the key bits from the keyfile. * - == stdin */ if (bstrcmp(keyfile, "-")) { kfd = 0; fprintf(stdout, _("Enter Encryption Key (close with ^D): ")); fflush(stdout); } else { kfd = open(keyfile, O_RDONLY); if (kfd < 0) { fprintf(stderr, _("Cannot open keyfile %s\n"), keyfile); retval = 1; goto bail_out; } } read(kfd, keydata, sizeof(keydata)); if (kfd > 0) { close(kfd); } strip_trailing_junk(keydata); if (set_scsi_encryption_key(-1, argv[0], keydata)) { goto bail_out; } else { retval = 1; goto bail_out; } } /* * Get the volume encryption status of volume currently loaded in the given drive. */ if (volume_encryption_status) { POOLMEM *encryption_status = get_pool_memory(PM_MESSAGE); if (get_scsi_volume_encryption_status(-1, argv[0], encryption_status, 0)) { fprintf(stdout, "%s", encryption_status); free_pool_memory(encryption_status); } else { retval = 1; free_pool_memory(encryption_status); goto bail_out; } } bail_out: if (cache_file) { free(cache_file); } if (keyfile) { free(keyfile); } if (wrap_keyfile) { free(wrap_keyfile); } exit(retval); }