Edit

kc3-lang/gnulib/lib/gc-pbkdf2.c

Branch :

  • Show log

    Commit

  • Author : Simon Josefsson
    Date : 2024-01-01 10:31:48
    Hash : 5b92dd0a
    Message : maint: run 'make update-copyright'

  • lib/gc-pbkdf2.c
  • /* gc-pbkdf2.c --- Password-Based Key Derivation Function a'la PKCS#5
       Copyright (C) 2002-2006, 2009-2024 Free Software Foundation, Inc.
    
       This file is free software: you can redistribute it and/or modify
       it under the terms of the GNU Lesser General Public License as
       published by the Free Software Foundation; either version 2.1 of the
       License, or (at your option) any later version.
    
       This file is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU Lesser General Public License for more details.
    
       You should have received a copy of the GNU Lesser General Public License
       along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
    
    /* Written by Simon Josefsson. */
    
    #include <config.h>
    
    #include "gc.h"
    
    #include <stdlib.h>
    #include <string.h>
    
    typedef Gc_rc (*gc_prf_func) (const void *key, size_t keylen,
                                  const void *in, size_t inlen, char *resbuf);
    
    static Gc_rc
    gc_pbkdf2_prf (gc_prf_func prf, size_t hLen,
                   const char *P, size_t Plen,
                   const char *S, size_t Slen,
                   unsigned int c,
                   char *DK, size_t dkLen)
    {
      char U[GC_MAX_DIGEST_SIZE];
      char T[GC_MAX_DIGEST_SIZE];
      unsigned int u;
      unsigned int l;
      unsigned int r;
      unsigned int i;
      unsigned int k;
      int rc;
      char *tmp;
      size_t tmplen = Slen + 4;
    
      if (c == 0)
        return GC_PKCS5_INVALID_ITERATION_COUNT;
    
      if (dkLen == 0)
        return GC_PKCS5_INVALID_DERIVED_KEY_LENGTH;
    
      if (dkLen > 4294967295U)
        return GC_PKCS5_DERIVED_KEY_TOO_LONG;
    
      l = ((dkLen - 1) / hLen) + 1;
      r = dkLen - (l - 1) * hLen;
    
      tmp = malloc (tmplen);
      if (tmp == NULL)
        return GC_MALLOC_ERROR;
    
      memcpy (tmp, S, Slen);
    
      for (i = 1; i <= l; i++)
        {
          memset (T, 0, hLen);
    
          for (u = 1; u <= c; u++)
            {
              if (u == 1)
                {
                  tmp[Slen + 0] = (i & 0xff000000) >> 24;
                  tmp[Slen + 1] = (i & 0x00ff0000) >> 16;
                  tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
                  tmp[Slen + 3] = (i & 0x000000ff) >> 0;
    
                  rc = prf (P, Plen, tmp, tmplen, U);
                }
              else
                rc = prf (P, Plen, U, hLen, U);
    
              if (rc != GC_OK)
                {
                  free (tmp);
                  return rc;
                }
    
              for (k = 0; k < hLen; k++)
                T[k] ^= U[k];
            }
    
          memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen);
        }
    
      free (tmp);
    
      return GC_OK;
    }
    
    Gc_rc
    gc_pbkdf2_hmac (Gc_hash hash,
                    const char *P, size_t Plen,
                    const char *S, size_t Slen,
                    unsigned int c, char *DK, size_t dkLen)
    {
      gc_prf_func prf;
      size_t hLen;
    
      switch (hash)
        {
    #if GNULIB_GC_HMAC_SHA1
        case GC_SHA1:
          prf = gc_hmac_sha1;
          hLen = GC_SHA1_DIGEST_SIZE;
          break;
    #endif
    
    #if GNULIB_GC_HMAC_SHA256
        case GC_SHA256:
          prf = gc_hmac_sha256;
          hLen = GC_SHA256_DIGEST_SIZE;
          break;
    #endif
    
    #if GNULIB_GC_HMAC_SHA512
        case GC_SHA512:
          prf = gc_hmac_sha512;
          hLen = GC_SHA512_DIGEST_SIZE;
          break;
    #endif
    
        default:
          return GC_INVALID_HASH;
        }
    
      return gc_pbkdf2_prf (prf, hLen, P, Plen, S, Slen, c, DK, dkLen);
    }