"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/lib/utils_benchmark.c" (13 Jan 2022, 6091 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "utils_benchmark.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.3.6_vs_2.4.0.

    1 /*
    2  * libcryptsetup - cryptsetup library, cipher benchmark
    3  *
    4  * Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
    5  * Copyright (C) 2012-2021 Milan Broz
    6  *
    7  * This program is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU General Public License
    9  * as published by the Free Software Foundation; either version 2
   10  * of the License, or (at your option) any later version.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   20  */
   21 
   22 #include <stdlib.h>
   23 #include <errno.h>
   24 
   25 #include "internal.h"
   26 
   27 int crypt_benchmark(struct crypt_device *cd,
   28     const char *cipher,
   29     const char *cipher_mode,
   30     size_t volume_key_size,
   31     size_t iv_size,
   32     size_t buffer_size,
   33     double *encryption_mbs,
   34     double *decryption_mbs)
   35 {
   36     void *buffer = NULL;
   37     char *iv = NULL, *key = NULL, mode[MAX_CIPHER_LEN], *c;
   38     int r;
   39 
   40     if (!cipher || !cipher_mode || !volume_key_size || !encryption_mbs || !decryption_mbs)
   41         return -EINVAL;
   42 
   43     r = init_crypto(cd);
   44     if (r < 0)
   45         return r;
   46 
   47     r = -ENOMEM;
   48     if (posix_memalign(&buffer, crypt_getpagesize(), buffer_size))
   49         goto out;
   50 
   51     r = crypt_cipher_ivsize(cipher, cipher_mode);
   52     if (r >= 0 && iv_size != (size_t)r) {
   53         log_dbg(cd, "IV length for benchmark adjusted to %i bytes (requested %zu).", r, iv_size);
   54         iv_size = r;
   55     }
   56 
   57     if (iv_size) {
   58         iv = malloc(iv_size);
   59         if (!iv)
   60             goto out;
   61         crypt_random_get(cd, iv, iv_size, CRYPT_RND_NORMAL);
   62     }
   63 
   64     key = malloc(volume_key_size);
   65     if (!key)
   66         goto out;
   67 
   68     crypt_random_get(cd, key, volume_key_size, CRYPT_RND_NORMAL);
   69 
   70     strncpy(mode, cipher_mode, sizeof(mode)-1);
   71     /* Ignore IV generator */
   72     if ((c  = strchr(mode, '-')))
   73         *c = '\0';
   74 
   75     r = crypt_cipher_perf_kernel(cipher, cipher_mode, buffer, buffer_size, key, volume_key_size,
   76                      iv, iv_size, encryption_mbs, decryption_mbs);
   77 
   78     if (r == -ERANGE)
   79         log_dbg(cd, "Measured cipher runtime is too low.");
   80     else if (r)
   81         log_dbg(cd, "Cannot initialize cipher %s, mode %s, key size %zu, IV size %zu.",
   82             cipher, cipher_mode, volume_key_size, iv_size);
   83 out:
   84     free(buffer);
   85     free(key);
   86     free(iv);
   87 
   88     return r;
   89 }
   90 
   91 int crypt_benchmark_pbkdf(struct crypt_device *cd,
   92     struct crypt_pbkdf_type *pbkdf,
   93     const char *password,
   94     size_t password_size,
   95     const char *salt,
   96     size_t salt_size,
   97     size_t volume_key_size,
   98     int (*progress)(uint32_t time_ms, void *usrptr),
   99     void *usrptr)
  100 {
  101     int r;
  102     const char *kdf_opt;
  103 
  104     if (!pbkdf || (!password && password_size))
  105         return -EINVAL;
  106 
  107     r = init_crypto(cd);
  108     if (r < 0)
  109         return r;
  110 
  111     kdf_opt = !strcmp(pbkdf->type, CRYPT_KDF_PBKDF2) ? pbkdf->hash : "";
  112 
  113     log_dbg(cd, "Running %s(%s) benchmark.", pbkdf->type, kdf_opt);
  114 
  115     r = crypt_pbkdf_perf(pbkdf->type, pbkdf->hash, password, password_size,
  116                  salt, salt_size, volume_key_size, pbkdf->time_ms,
  117                  pbkdf->max_memory_kb, pbkdf->parallel_threads,
  118                  &pbkdf->iterations, &pbkdf->max_memory_kb, progress, usrptr);
  119 
  120     if (!r)
  121         log_dbg(cd, "Benchmark returns %s(%s) %u iterations, %u memory, %u threads (for %zu-bits key).",
  122             pbkdf->type, kdf_opt, pbkdf->iterations, pbkdf->max_memory_kb,
  123             pbkdf->parallel_threads, volume_key_size * 8);
  124     return r;
  125 }
  126 
  127 struct benchmark_usrptr {
  128     struct crypt_device *cd;
  129     struct crypt_pbkdf_type *pbkdf;
  130 };
  131 
  132 static int benchmark_callback(uint32_t time_ms, void *usrptr)
  133 {
  134     struct benchmark_usrptr *u = usrptr;
  135 
  136     log_dbg(u->cd, "PBKDF benchmark: memory cost = %u, iterations = %u, "
  137         "threads = %u (took %u ms)", u->pbkdf->max_memory_kb,
  138         u->pbkdf->iterations, u->pbkdf->parallel_threads, time_ms);
  139 
  140     return 0;
  141 }
  142 
  143 /*
  144  * Used in internal places to benchmark crypt_device context PBKDF.
  145  * Once requested parameters are benchmarked, iterations attribute is set,
  146  * and the benchmarked values can be reused.
  147  * Note that memory cost can be changed after benchmark (if used).
  148  * NOTE: You need to check that you are benchmarking for the same key size.
  149  */
  150 int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
  151                    struct crypt_pbkdf_type *pbkdf,
  152                    size_t volume_key_size)
  153 {
  154     struct crypt_pbkdf_limits pbkdf_limits;
  155     double PBKDF2_tmp;
  156     uint32_t ms_tmp;
  157     int r = -EINVAL;
  158     struct benchmark_usrptr u = {
  159         .cd = cd,
  160         .pbkdf = pbkdf
  161     };
  162 
  163     r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
  164     if (r)
  165         return r;
  166 
  167     if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
  168         if (pbkdf->iterations) {
  169             log_dbg(cd, "Reusing PBKDF values (no benchmark flag is set).");
  170             return 0;
  171         }
  172         log_err(cd, _("PBKDF benchmark disabled but iterations not set."));
  173         return -EINVAL;
  174     }
  175 
  176     /* For PBKDF2 run benchmark always. Also note it depends on volume_key_size! */
  177     if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
  178         /*
  179          * For PBKDF2 it is enough to run benchmark for only 1 second
  180          * and interpolate final iterations value from it.
  181          */
  182         ms_tmp = pbkdf->time_ms;
  183         pbkdf->time_ms = 1000;
  184         pbkdf->parallel_threads = 0; /* N/A in PBKDF2 */
  185         pbkdf->max_memory_kb = 0; /* N/A in PBKDF2 */
  186 
  187         r = crypt_benchmark_pbkdf(cd, pbkdf, "foo", 3, "bar", 3,
  188                     volume_key_size, &benchmark_callback, &u);
  189         pbkdf->time_ms = ms_tmp;
  190         if (r < 0) {
  191             log_err(cd, _("Not compatible PBKDF2 options (using hash algorithm %s)."),
  192                 pbkdf->hash);
  193             return r;
  194         }
  195 
  196         PBKDF2_tmp = ((double)pbkdf->iterations * pbkdf->time_ms / 1000.);
  197         if (PBKDF2_tmp > (double)UINT32_MAX)
  198             return -EINVAL;
  199         pbkdf->iterations = AT_LEAST((uint32_t)PBKDF2_tmp, pbkdf_limits.min_iterations);
  200     } else {
  201         /* Already benchmarked */
  202         if (pbkdf->iterations) {
  203             log_dbg(cd, "Reusing PBKDF values.");
  204             return 0;
  205         }
  206 
  207         r = crypt_benchmark_pbkdf(cd, pbkdf, "foo", 3,
  208             "0123456789abcdef0123456789abcdef", 32,
  209             volume_key_size, &benchmark_callback, &u);
  210         if (r < 0)
  211             log_err(cd, _("Not compatible PBKDF options."));
  212     }
  213 
  214     return r;
  215 }