"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/lib/luks2/luks2_digest_pbkdf2.c" (13 Jan 2022, 6447 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 "luks2_digest_pbkdf2.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
    3  *
    4  * Copyright (C) 2015-2021 Red Hat, Inc. All rights reserved.
    5  * Copyright (C) 2015-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 "luks2_internal.h"
   23 
   24 #define LUKS_DIGESTSIZE 20 // since SHA1
   25 #define LUKS_SALTSIZE 32
   26 #define LUKS_MKD_ITERATIONS_MS 125
   27 
   28 static int PBKDF2_digest_verify(struct crypt_device *cd,
   29     int digest,
   30     const char *volume_key,
   31     size_t volume_key_len)
   32 {
   33     char checkHashBuf[64];
   34     json_object *jobj_digest, *jobj1;
   35     const char *hashSpec;
   36     char *mkDigest = NULL, mkDigestSalt[LUKS_SALTSIZE];
   37     unsigned int mkDigestIterations;
   38     size_t len;
   39     int r;
   40 
   41     /* This can be done only for internally linked digests */
   42     jobj_digest = LUKS2_get_digest_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), digest);
   43     if (!jobj_digest)
   44         return -EINVAL;
   45 
   46     if (!json_object_object_get_ex(jobj_digest, "hash", &jobj1))
   47         return -EINVAL;
   48     hashSpec = json_object_get_string(jobj1);
   49 
   50     if (!json_object_object_get_ex(jobj_digest, "iterations", &jobj1))
   51         return -EINVAL;
   52     mkDigestIterations = json_object_get_int64(jobj1);
   53 
   54     if (!json_object_object_get_ex(jobj_digest, "salt", &jobj1))
   55         return -EINVAL;
   56     len = sizeof(mkDigestSalt);
   57     if (!base64_decode(json_object_get_string(jobj1),
   58                json_object_get_string_len(jobj1), mkDigestSalt, &len))
   59         return -EINVAL;
   60     if (len != LUKS_SALTSIZE)
   61         return -EINVAL;
   62 
   63     if (!json_object_object_get_ex(jobj_digest, "digest", &jobj1))
   64         return -EINVAL;
   65     len = 0;
   66     if (!base64_decode_alloc(json_object_get_string(jobj1),
   67                json_object_get_string_len(jobj1), &mkDigest, &len))
   68         return -EINVAL;
   69     if (len < LUKS_DIGESTSIZE ||
   70         len > sizeof(checkHashBuf) ||
   71         (len != LUKS_DIGESTSIZE && len != (size_t)crypt_hash_size(hashSpec))) {
   72         free(mkDigest);
   73         return -EINVAL;
   74     }
   75 
   76     r = -EPERM;
   77     if (crypt_pbkdf(CRYPT_KDF_PBKDF2, hashSpec, volume_key, volume_key_len,
   78             mkDigestSalt, LUKS_SALTSIZE,
   79             checkHashBuf, len,
   80             mkDigestIterations, 0, 0) < 0) {
   81         r = -EINVAL;
   82     } else {
   83         if (memcmp(checkHashBuf, mkDigest, len) == 0)
   84             r = 0;
   85     }
   86 
   87     free(mkDigest);
   88     return r;
   89 }
   90 
   91 static int PBKDF2_digest_store(struct crypt_device *cd,
   92     int digest,
   93     const char *volume_key,
   94     size_t volume_key_len)
   95 {
   96     json_object *jobj_digest, *jobj_digests;
   97     char salt[LUKS_SALTSIZE], digest_raw[128];
   98     int hmac_size, r;
   99     char *base64_str;
  100     struct luks2_hdr *hdr;
  101     struct crypt_pbkdf_limits pbkdf_limits;
  102     const struct crypt_pbkdf_type *pbkdf_cd;
  103     struct crypt_pbkdf_type pbkdf = {
  104         .type = CRYPT_KDF_PBKDF2,
  105         .time_ms = LUKS_MKD_ITERATIONS_MS,
  106     };
  107 
  108     /* Inherit hash from PBKDF setting */
  109     pbkdf_cd = crypt_get_pbkdf_type(cd);
  110     if (pbkdf_cd)
  111         pbkdf.hash = pbkdf_cd->hash;
  112     if (!pbkdf.hash)
  113         pbkdf.hash = DEFAULT_LUKS1_HASH;
  114 
  115     log_dbg(cd, "Setting PBKDF2 type key digest %d.", digest);
  116 
  117     r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
  118     if (r < 0)
  119         return r;
  120 
  121     r = crypt_pbkdf_get_limits(CRYPT_KDF_PBKDF2, &pbkdf_limits);
  122     if (r < 0)
  123         return r;
  124 
  125     if (crypt_get_pbkdf(cd)->flags & CRYPT_PBKDF_NO_BENCHMARK)
  126         pbkdf.iterations = pbkdf_limits.min_iterations;
  127     else {
  128         r = crypt_benchmark_pbkdf_internal(cd, &pbkdf, volume_key_len);
  129         if (r < 0)
  130             return r;
  131     }
  132 
  133     hmac_size = crypt_hmac_size(pbkdf.hash);
  134     if (hmac_size < 0 || hmac_size > (int)sizeof(digest_raw))
  135         return -EINVAL;
  136 
  137     r = crypt_pbkdf(CRYPT_KDF_PBKDF2, pbkdf.hash, volume_key, volume_key_len,
  138             salt, LUKS_SALTSIZE, digest_raw, hmac_size,
  139             pbkdf.iterations, 0, 0);
  140     if (r < 0)
  141         return r;
  142 
  143     jobj_digest = LUKS2_get_digest_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), digest);
  144     jobj_digests = NULL;
  145     if (!jobj_digest) {
  146         hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
  147         jobj_digest = json_object_new_object();
  148         json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
  149     }
  150 
  151     json_object_object_add(jobj_digest, "type", json_object_new_string("pbkdf2"));
  152     json_object_object_add(jobj_digest, "keyslots", json_object_new_array());
  153     json_object_object_add(jobj_digest, "segments", json_object_new_array());
  154     json_object_object_add(jobj_digest, "hash", json_object_new_string(pbkdf.hash));
  155     json_object_object_add(jobj_digest, "iterations", json_object_new_int(pbkdf.iterations));
  156 
  157     base64_encode_alloc(salt, LUKS_SALTSIZE, &base64_str);
  158     if (!base64_str) {
  159         json_object_put(jobj_digest);
  160         return -ENOMEM;
  161     }
  162     json_object_object_add(jobj_digest, "salt", json_object_new_string(base64_str));
  163     free(base64_str);
  164 
  165     base64_encode_alloc(digest_raw, hmac_size, &base64_str);
  166     if (!base64_str) {
  167         json_object_put(jobj_digest);
  168         return -ENOMEM;
  169     }
  170     json_object_object_add(jobj_digest, "digest", json_object_new_string(base64_str));
  171     free(base64_str);
  172 
  173     if (jobj_digests)
  174         json_object_object_add_by_uint(jobj_digests, digest, jobj_digest);
  175 
  176     JSON_DBG(cd, jobj_digest, "Digest JSON:");
  177     return 0;
  178 }
  179 
  180 static int PBKDF2_digest_dump(struct crypt_device *cd, int digest)
  181 {
  182     json_object *jobj_digest, *jobj1;
  183 
  184     /* This can be done only for internally linked digests */
  185     jobj_digest = LUKS2_get_digest_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), digest);
  186     if (!jobj_digest)
  187         return -EINVAL;
  188 
  189     json_object_object_get_ex(jobj_digest, "hash", &jobj1);
  190     log_std(cd, "\tHash:       %s\n", json_object_get_string(jobj1));
  191 
  192     json_object_object_get_ex(jobj_digest, "iterations", &jobj1);
  193     log_std(cd, "\tIterations: %" PRIu64 "\n", json_object_get_int64(jobj1));
  194 
  195     json_object_object_get_ex(jobj_digest, "salt", &jobj1);
  196     log_std(cd, "\tSalt:       ");
  197     hexprint_base64(cd, jobj1, " ", "            ");
  198 
  199     json_object_object_get_ex(jobj_digest, "digest", &jobj1);
  200     log_std(cd, "\tDigest:     ");
  201     hexprint_base64(cd, jobj1, " ", "            ");
  202 
  203     return 0;
  204 }
  205 
  206 const digest_handler PBKDF2_digest = {
  207     .name   = "pbkdf2",
  208     .verify = PBKDF2_digest_verify,
  209     .store  = PBKDF2_digest_store,
  210     .dump   = PBKDF2_digest_dump,
  211 };