(root)/
libxcrypt-4.4.36/
lib/
crypt-gost-yescrypt.c
       1  /* Copyright (C) 2018 vt@altlinux.org
       2   * Copyright (C) 2018 Björn Esser besser82@fedoraproject.org
       3   *
       4   * Redistribution and use in source and binary forms, with or without
       5   * modification, are permitted.
       6   *
       7   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
       8   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       9   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      10   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      11   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      12   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      13   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      14   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      15   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      16   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      17   * SUCH DAMAGE.
      18   */
      19  
      20  #include "crypt-port.h"
      21  
      22  #if INCLUDE_gost_yescrypt
      23  
      24  #define YESCRYPT_INTERNAL
      25  #include "alg-yescrypt.h"
      26  #undef YESCRYPT_INTERNAL
      27  
      28  #include "alg-gost3411-2012-hmac.h"
      29  
      30  #include <errno.h>
      31  
      32  /* upper level hmac for tests */
      33  #ifndef outer_gost_hmac256
      34  #define outer_gost_hmac256 gost_hmac256
      35  #endif
      36  
      37  /* For use in scratch space by crypt_gost_yescrypt_rn().  */
      38  typedef struct
      39  {
      40    yescrypt_local_t local;
      41    gost_hmac_256_t gostbuf;
      42    uint8_t outbuf[CRYPT_OUTPUT_SIZE];
      43    uint8_t gsetting[CRYPT_OUTPUT_SIZE];
      44    uint8_t hk[32], interm[32], y[32];
      45    uint8_t *retval;
      46  } crypt_gost_yescrypt_internal_t;
      47  
      48  static_assert (sizeof (crypt_gost_yescrypt_internal_t) <= ALG_SPECIFIC_SIZE,
      49                 "ALG_SPECIFIC_SIZE is too small for GOST-YESCRYPT.");
      50  
      51  /*
      52   * As OUTPUT is initialized with a failure token before gensalt_yescrypt_rn
      53   * is called, in case of an error we could just set an appropriate errno
      54   * and return.
      55   */
      56  void
      57  gensalt_gost_yescrypt_rn (unsigned long count,
      58                            const uint8_t *rbytes, size_t nrbytes,
      59                            uint8_t *output, size_t o_size)
      60  {
      61    /* Up to 512 bits (64 bytes) of entropy for computing the salt portion
      62       of the MCF-setting are supported.  */
      63    nrbytes = (nrbytes > 64 ? 64 : nrbytes);
      64  
      65    if (o_size < 4 + 8 * 6 + BASE64_LEN (nrbytes) + 1 ||
      66        CRYPT_GENSALT_OUTPUT_SIZE < 4 + 8 * 6 + BASE64_LEN (nrbytes) + 1)
      67      {
      68        errno = ERANGE;
      69        return;
      70      }
      71  
      72    /* We pass 'o_size - 1' to gensalt, because we need to shift
      73             the prefix by 1 char to insert the gost marker.  */
      74    gensalt_yescrypt_rn (count, rbytes, nrbytes, output, o_size - 1);
      75  
      76    /* Check for failures.  */
      77    if (output[0] == '*')
      78      return;
      79  
      80    /* Shift output one byte further.  */
      81    memmove (output + 1, output, strlen ((const char *) output) + 1);
      82  
      83    /* Insert the gost marker.  */
      84    output[1] = 'g';
      85  }
      86  
      87  void
      88  crypt_gost_yescrypt_rn (const char *phrase, size_t phr_size,
      89                          const char *setting, size_t set_size,
      90                          uint8_t *output, size_t o_size,
      91                          void *scratch, size_t s_size)
      92  {
      93    if (o_size < set_size + 1 + 43 + 1 ||
      94        CRYPT_OUTPUT_SIZE < set_size + 1 + 43 + 1 ||
      95        s_size < sizeof (crypt_gost_yescrypt_internal_t))
      96      {
      97        errno = ERANGE;
      98        return;
      99      }
     100  
     101    /* Fail when called with wrong prefix.  */
     102    if (strncmp (setting, "$gy$", 4))
     103      {
     104        errno = EINVAL;
     105        return;
     106      }
     107  
     108    crypt_gost_yescrypt_internal_t *intbuf = scratch;
     109  
     110    if (yescrypt_init_local (&intbuf->local))
     111      return;
     112  
     113    /* convert gost setting to yescrypt setting */
     114    intbuf->gsetting[0] = '$';
     115    intbuf->gsetting[1] = 'y';
     116    intbuf->gsetting[2] = '$';
     117    strcpy_or_abort (&intbuf->gsetting[3], set_size - 3, setting + 4);
     118  
     119    intbuf->retval = yescrypt_r (NULL, &intbuf->local,
     120                                 (const uint8_t *) phrase, phr_size,
     121                                 intbuf->gsetting, NULL,
     122                                 intbuf->outbuf + 1, o_size - 1);
     123  
     124    if (!intbuf->retval)
     125      errno = EINVAL;
     126  
     127    if (yescrypt_free_local (&intbuf->local) || !intbuf->retval)
     128      return;
     129  
     130    intbuf->outbuf[0] = '$';
     131    intbuf->outbuf[1] = 'g';
     132  
     133    /* extract yescrypt output from "$y$param$salt$output" */
     134    char *hptr = strchr ((const char *) intbuf->retval + 3, '$');
     135    if (!hptr)
     136      {
     137        errno = EINVAL;
     138        return;
     139      }
     140    hptr = strchr (hptr + 1, '$');
     141    if (!hptr)
     142      {
     143        errno = EINVAL;
     144        return;
     145      }
     146    hptr++; /* start of output */
     147  
     148    /* decode yescrypt output into its raw 256-bit form */
     149    size_t ylen = sizeof (intbuf->y);
     150    if (!decode64 (intbuf->y, &ylen, (uint8_t *) hptr, strlen (hptr)) ||
     151        ylen != sizeof (intbuf->y))
     152      {
     153        errno = EINVAL;
     154        return;
     155      }
     156  
     157    /*
     158     * HMAC_GOSTR3411_2012_256(
     159     *   HMAC_GOSTR3411_2012_256(GOST2012_256(K), S),
     160     *   yescrypt(K, S)
     161     * )
     162     * yescrypt output is used in place of message,
     163     * thus, its crypto properties are superseded by GOST.
     164     * Password is always hashed for inner hmac to avoid
     165     * collisions between hashed and unhashed passwords.
     166     */
     167    gost_hash256 ((const uint8_t *) phrase, phr_size, intbuf->hk, &intbuf->gostbuf.ctx);
     168    gost_hmac256 (intbuf->hk, sizeof (intbuf->hk),
     169                  (const uint8_t *) setting,
     170                  (size_t) ((uint8_t *) hptr - intbuf->retval),
     171                  intbuf->interm, &intbuf->gostbuf);
     172    outer_gost_hmac256 (intbuf->interm, sizeof (intbuf->interm),
     173                        intbuf->y, sizeof (intbuf->y), intbuf->y, &intbuf->gostbuf);
     174  
     175    encode64 ((uint8_t *) hptr, o_size - (size_t) ((uint8_t *) hptr - intbuf->retval),
     176              intbuf->y, sizeof (intbuf->y));
     177  
     178    strcpy_or_abort (output, o_size, intbuf->outbuf);
     179    return;
     180  }
     181  
     182  #endif /* INCLUDE_gost_yescrypt */