File indexing completed on 2024-04-28 04:43:43

0001 /* pkcs5.c     Partial Password-Based Cryptography (PKCS#5) implementation
0002  * Copyright (C) 2002 Free Software Foundation, Inc.
0003  *
0004  * This file is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) any later version.
0008  *
0009  * This file is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Lesser General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Lesser General Public
0015  * License along with this file; if not, write to the Free Software
0016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
0017  *
0018  */
0019 
0020 #include "gcrypt.h"
0021 
0022 /*
0023  * 5.2 PBKDF2
0024  *
0025  *  PBKDF2 applies a pseudorandom function (see Appendix B.1 for an
0026  *  example) to derive keys. The length of the derived key is essentially
0027  *  unbounded. (However, the maximum effective search space for the
0028  *  derived key may be limited by the structure of the underlying
0029  *  pseudorandom function. See Appendix B.1 for further discussion.)
0030  *  PBKDF2 is recommended for new applications.
0031  *
0032  *  PBKDF2 (P, S, c, dkLen)
0033  *
0034  *  Options:        PRF        underlying pseudorandom function (hLen
0035  *                             denotes the length in octets of the
0036  *                             pseudorandom function output)
0037  *
0038  *  Input:          P          password, an octet string
0039  *                  S          salt, an octet string
0040  *                  c          iteration count, a positive integer
0041  *                  dkLen      intended length in octets of the derived
0042  *                             key, a positive integer, at most
0043  *                             (2^32 - 1) * hLen
0044  *
0045  *  Output:         DK         derived key, a dkLen-octet string
0046  */
0047 
0048 static gcry_error_t gcry_pbkdf2(int          PRF,
0049                                 const char  *P,
0050                                 size_t       Plen,
0051                                 const char  *S,
0052                                 size_t       Slen,
0053                                 unsigned int c,
0054                                 unsigned int dkLen,
0055                                 char        *DK)
0056 {
0057     gcry_md_hd_t   prf;
0058     gcry_error_t   rc;
0059     char          *U;
0060     unsigned int   u;
0061     unsigned int   hLen;
0062     unsigned int   l;
0063     unsigned int   r;
0064     unsigned char *p;
0065     unsigned int   i;
0066     unsigned int   k;
0067 
0068     hLen = gcry_md_get_algo_dlen(PRF);
0069     if (hLen == 0)
0070         return GPG_ERR_UNSUPPORTED_ALGORITHM;
0071 
0072     if (c == 0)
0073         return GPG_ERR_INV_ARG;
0074 
0075     if (dkLen == 0)
0076         return GPG_ERR_TOO_SHORT;
0077 
0078     /*
0079      *
0080      *  Steps:
0081      *
0082      *     1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and
0083      *        stop.
0084      */
0085 
0086     if (dkLen > 4294967295U)
0087         return GPG_ERR_TOO_LARGE;
0088 
0089     /*
0090      *     2. Let l be the number of hLen-octet blocks in the derived key,
0091      *        rounding up, and let r be the number of octets in the last
0092      *        block:
0093      *
0094      *                  l = CEIL (dkLen / hLen) ,
0095      *                  r = dkLen - (l - 1) * hLen .
0096      *
0097      *        Here, CEIL (x) is the "ceiling" function, i.e. the smallest
0098      *        integer greater than, or equal to, x.
0099      */
0100 
0101     l = dkLen / hLen;
0102     if (dkLen % hLen)
0103         l++;
0104     r = dkLen - (l - 1) * hLen;
0105 
0106     /*
0107      *     3. For each block of the derived key apply the function F defined
0108      *        below to the password P, the salt S, the iteration count c, and
0109      *        the block index to compute the block:
0110      *
0111      *                  T_1 = F (P, S, c, 1) ,
0112      *                  T_2 = F (P, S, c, 2) ,
0113      *                  ...
0114      *                  T_l = F (P, S, c, l) ,
0115      *
0116      *        where the function F is defined as the exclusive-or sum of the
0117      *        first c iterates of the underlying pseudorandom function PRF
0118      *        applied to the password P and the concatenation of the salt S
0119      *        and the block index i:
0120      *
0121      *                  F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
0122      *
0123      *        where
0124      *
0125      *                  U_1 = PRF (P, S || INT (i)) ,
0126      *                  U_2 = PRF (P, U_1) ,
0127      *                  ...
0128      *                  U_c = PRF (P, U_{c-1}) .
0129      *
0130      *        Here, INT (i) is a four-octet encoding of the integer i, most
0131      *        significant octet first.
0132      *
0133      *     4. Concatenate the blocks and extract the first dkLen octets to
0134      *        produce a derived key DK:
0135      *
0136      *                  DK = T_1 || T_2 ||  ...  || T_l<0..r-1>
0137      *
0138      *     5. Output the derived key DK.
0139      *
0140      *  Note. The construction of the function F follows a "belt-and-
0141      *  suspenders" approach. The iterates U_i are computed recursively to
0142      *  remove a degree of parallelism from an opponent; they are exclusive-
0143      *  ored together to reduce concerns about the recursion degenerating
0144      *  into a small set of values.
0145      *
0146      */
0147     rc = gcry_md_open(&prf, PRF, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE);
0148     if (rc != GPG_ERR_NO_ERROR)
0149         return rc;
0150 
0151     U = (char *)gcry_malloc(hLen);
0152     if (!U) {
0153         rc = GPG_ERR_ENOMEM;
0154         goto done;
0155     }
0156 
0157     for (i = 1; i <= l; i++) {
0158         memset(DK + (i - 1) * hLen, 0, i == l ? r : hLen);
0159 
0160         for (u = 1; u <= c; u++) {
0161             gcry_md_reset(prf);
0162 
0163             rc = gcry_md_setkey(prf, P, Plen);
0164             if (rc != GPG_ERR_NO_ERROR) {
0165                 goto done;
0166             }
0167             if (u == 1) {
0168                 char tmp[4];
0169                 gcry_md_write(prf, S, Slen);
0170                 tmp[0] = (i & 0xff000000) >> 24;
0171                 tmp[1] = (i & 0x00ff0000) >> 16;
0172                 tmp[2] = (i & 0x0000ff00) >> 8;
0173                 tmp[3] = (i & 0x000000ff) >> 0;
0174                 gcry_md_write(prf, tmp, 4);
0175             } else
0176                 gcry_md_write(prf, U, hLen);
0177 
0178             p = gcry_md_read(prf, PRF);
0179             if (p == nullptr) {
0180                 rc = GPG_ERR_CONFIGURATION;
0181                 goto done;
0182             }
0183 
0184             memcpy(U, p, hLen);
0185             for (k = 0; k < (i == l ? r : hLen); k++)
0186                 DK[(i - 1) * hLen + k] ^= U[k];
0187         }
0188     }
0189 
0190     rc = GPG_ERR_NO_ERROR;
0191 done:
0192     gcry_md_close(prf);
0193     gcry_free(U);
0194     return rc;
0195 }