Пример #1
0
/*
 * 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;
}
Пример #2
0
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);
}