Blame crypt/sha512-crypt.c

Packit 6c4009
/* One way encryption based on SHA512 sum.
Packit 6c4009
   Copyright (C) 2007-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
Packit 6c4009
#include "sha512.h"
Packit 6c4009
#include "crypt-private.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef USE_NSS
Packit 6c4009
typedef int PRBool;
Packit 6c4009
# include <hasht.h>
Packit 6c4009
# include <nsslowhash.h>
Packit 6c4009
Packit 6c4009
# define sha512_init_ctx(ctxp, nss_ctxp) \
Packit 6c4009
  do									      \
Packit 6c4009
    {									      \
Packit 6c4009
      if (((nss_ctxp = NSSLOWHASH_NewContext (nss_ictx, HASH_AlgSHA512))      \
Packit 6c4009
	   == NULL))							      \
Packit 6c4009
	{								      \
Packit 6c4009
	  if (nss_ctx != NULL)						      \
Packit 6c4009
	    NSSLOWHASH_Destroy (nss_ctx);				      \
Packit 6c4009
	  if (nss_alt_ctx != NULL)					      \
Packit 6c4009
	    NSSLOWHASH_Destroy (nss_alt_ctx);				      \
Packit 6c4009
	  return NULL;							      \
Packit 6c4009
	}								      \
Packit 6c4009
      NSSLOWHASH_Begin (nss_ctxp);					      \
Packit 6c4009
    }									      \
Packit 6c4009
  while (0)
Packit 6c4009
Packit 6c4009
# define sha512_process_bytes(buf, len, ctxp, nss_ctxp) \
Packit 6c4009
  NSSLOWHASH_Update (nss_ctxp, (const unsigned char *) buf, len)
Packit 6c4009
Packit 6c4009
# define sha512_finish_ctx(ctxp, nss_ctxp, result) \
Packit 6c4009
  do									      \
Packit 6c4009
    {									      \
Packit 6c4009
      unsigned int ret;							      \
Packit 6c4009
      NSSLOWHASH_End (nss_ctxp, result, &ret, sizeof (result));		      \
Packit 6c4009
      assert (ret == sizeof (result));					      \
Packit 6c4009
      NSSLOWHASH_Destroy (nss_ctxp);					      \
Packit 6c4009
      nss_ctxp = NULL;							      \
Packit 6c4009
    }									      \
Packit 6c4009
  while (0)
Packit 6c4009
#else
Packit 6c4009
# define sha512_init_ctx(ctxp, nss_ctxp) \
Packit 6c4009
  __sha512_init_ctx (ctxp)
Packit 6c4009
Packit 6c4009
# define sha512_process_bytes(buf, len, ctxp, nss_ctxp) \
Packit 6c4009
  __sha512_process_bytes(buf, len, ctxp)
Packit 6c4009
Packit 6c4009
# define sha512_finish_ctx(ctxp, nss_ctxp, result) \
Packit 6c4009
  __sha512_finish_ctx (ctxp, result)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Define our magic string to mark salt for SHA512 "encryption"
Packit 6c4009
   replacement.  */
Packit 6c4009
static const char sha512_salt_prefix[] = "$6$";
Packit 6c4009
Packit 6c4009
/* Prefix for optional rounds specification.  */
Packit 6c4009
static const char sha512_rounds_prefix[] = "rounds=";
Packit 6c4009
Packit 6c4009
/* Maximum salt string length.  */
Packit 6c4009
#define SALT_LEN_MAX 16
Packit 6c4009
/* Default number of rounds if not explicitly specified.  */
Packit 6c4009
#define ROUNDS_DEFAULT 5000
Packit 6c4009
/* Minimum number of rounds.  */
Packit 6c4009
#define ROUNDS_MIN 1000
Packit 6c4009
/* Maximum number of rounds.  */
Packit 6c4009
#define ROUNDS_MAX 999999999
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Prototypes for local functions.  */
Packit 6c4009
extern char *__sha512_crypt_r (const char *key, const char *salt,
Packit 6c4009
			       char *buffer, int buflen);
Packit 6c4009
extern char *__sha512_crypt (const char *key, const char *salt);
Packit 6c4009
Packit 6c4009
Packit 6c4009
char *
Packit 6c4009
__sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
Packit 6c4009
{
Packit 6c4009
  unsigned char alt_result[64]
Packit 6c4009
    __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
Packit 6c4009
  unsigned char temp_result[64]
Packit 6c4009
    __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
Packit 6c4009
  size_t salt_len;
Packit 6c4009
  size_t key_len;
Packit 6c4009
  size_t cnt;
Packit 6c4009
  char *cp;
Packit 6c4009
  char *copied_key = NULL;
Packit 6c4009
  char *copied_salt = NULL;
Packit 6c4009
  char *p_bytes;
Packit 6c4009
  char *s_bytes;
Packit 6c4009
  /* Default number of rounds.  */
Packit 6c4009
  size_t rounds = ROUNDS_DEFAULT;
Packit 6c4009
  bool rounds_custom = false;
Packit 6c4009
  size_t alloca_used = 0;
Packit 6c4009
  char *free_key = NULL;
Packit 6c4009
  char *free_pbytes = NULL;
Packit 6c4009
Packit 6c4009
  /* Find beginning of salt string.  The prefix should normally always
Packit 6c4009
     be present.  Just in case it is not.  */
Packit 6c4009
  if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0)
Packit 6c4009
    /* Skip salt prefix.  */
Packit 6c4009
    salt += sizeof (sha512_salt_prefix) - 1;
Packit 6c4009
Packit 6c4009
  if (strncmp (salt, sha512_rounds_prefix, sizeof (sha512_rounds_prefix) - 1)
Packit 6c4009
      == 0)
Packit 6c4009
    {
Packit 6c4009
      const char *num = salt + sizeof (sha512_rounds_prefix) - 1;
Packit 6c4009
      char *endp;
Packit 6c4009
      unsigned long int srounds = strtoul (num, &endp, 10);
Packit 6c4009
      if (*endp == '$')
Packit 6c4009
	{
Packit 6c4009
	  salt = endp + 1;
Packit 6c4009
	  rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
Packit 6c4009
	  rounds_custom = true;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
Packit 6c4009
  key_len = strlen (key);
Packit 6c4009
Packit 6c4009
  if ((key - (char *) 0) % __alignof__ (uint64_t) != 0)
Packit 6c4009
    {
Packit 6c4009
      char *tmp;
Packit 6c4009
Packit 6c4009
      if (__libc_use_alloca (alloca_used + key_len + __alignof__ (uint64_t)))
Packit 6c4009
	tmp = alloca_account (key_len + __alignof__ (uint64_t), alloca_used);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  free_key = tmp = (char *) malloc (key_len + __alignof__ (uint64_t));
Packit 6c4009
	  if (tmp == NULL)
Packit 6c4009
	    return NULL;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      key = copied_key =
Packit 6c4009
	memcpy (tmp + __alignof__ (uint64_t)
Packit 6c4009
		- (tmp - (char *) 0) % __alignof__ (uint64_t),
Packit 6c4009
		key, key_len);
Packit 6c4009
      assert ((key - (char *) 0) % __alignof__ (uint64_t) == 0);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0)
Packit 6c4009
    {
Packit 6c4009
      char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t));
Packit 6c4009
      salt = copied_salt =
Packit 6c4009
	memcpy (tmp + __alignof__ (uint64_t)
Packit 6c4009
		- (tmp - (char *) 0) % __alignof__ (uint64_t),
Packit 6c4009
		salt, salt_len);
Packit 6c4009
      assert ((salt - (char *) 0) % __alignof__ (uint64_t) == 0);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#ifdef USE_NSS
Packit 6c4009
  /* Initialize libfreebl3.  */
Packit 6c4009
  NSSLOWInitContext *nss_ictx = NSSLOW_Init ();
Packit 6c4009
  if (nss_ictx == NULL)
Packit 6c4009
    {
Packit 6c4009
      free (free_key);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  NSSLOWHASHContext *nss_ctx = NULL;
Packit 6c4009
  NSSLOWHASHContext *nss_alt_ctx = NULL;
Packit 6c4009
#else
Packit 6c4009
  struct sha512_ctx ctx;
Packit 6c4009
  struct sha512_ctx alt_ctx;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Prepare for the real work.  */
Packit 6c4009
  sha512_init_ctx (&ctx, nss_ctx);
Packit 6c4009
Packit 6c4009
  /* Add the key string.  */
Packit 6c4009
  sha512_process_bytes (key, key_len, &ctx, nss_ctx);
Packit 6c4009
Packit 6c4009
  /* The last part is the salt string.  This must be at most 16
Packit 6c4009
     characters and it ends at the first `$' character.  */
Packit 6c4009
  sha512_process_bytes (salt, salt_len, &ctx, nss_ctx);
Packit 6c4009
Packit 6c4009
Packit 6c4009
  /* Compute alternate SHA512 sum with input KEY, SALT, and KEY.  The
Packit 6c4009
     final result will be added to the first context.  */
Packit 6c4009
  sha512_init_ctx (&alt_ctx, nss_alt_ctx);
Packit 6c4009
Packit 6c4009
  /* Add key.  */
Packit 6c4009
  sha512_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
Packit 6c4009
Packit 6c4009
  /* Add salt.  */
Packit 6c4009
  sha512_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx);
Packit 6c4009
Packit 6c4009
  /* Add key again.  */
Packit 6c4009
  sha512_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
Packit 6c4009
Packit 6c4009
  /* Now get result of this (64 bytes) and add it to the other
Packit 6c4009
     context.  */
Packit 6c4009
  sha512_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result);
Packit 6c4009
Packit 6c4009
  /* Add for any character in the key one byte of the alternate sum.  */
Packit 6c4009
  for (cnt = key_len; cnt > 64; cnt -= 64)
Packit 6c4009
    sha512_process_bytes (alt_result, 64, &ctx, nss_ctx);
Packit 6c4009
  sha512_process_bytes (alt_result, cnt, &ctx, nss_ctx);
Packit 6c4009
Packit 6c4009
  /* Take the binary representation of the length of the key and for every
Packit 6c4009
     1 add the alternate sum, for every 0 the key.  */
Packit 6c4009
  for (cnt = key_len; cnt > 0; cnt >>= 1)
Packit 6c4009
    if ((cnt & 1) != 0)
Packit 6c4009
      sha512_process_bytes (alt_result, 64, &ctx, nss_ctx);
Packit 6c4009
    else
Packit 6c4009
      sha512_process_bytes (key, key_len, &ctx, nss_ctx);
Packit 6c4009
Packit 6c4009
  /* Create intermediate result.  */
Packit 6c4009
  sha512_finish_ctx (&ctx, nss_ctx, alt_result);
Packit 6c4009
Packit 6c4009
  /* Start computation of P byte sequence.  */
Packit 6c4009
  sha512_init_ctx (&alt_ctx, nss_alt_ctx);
Packit 6c4009
Packit 6c4009
  /* For every character in the password add the entire password.  */
Packit 6c4009
  for (cnt = 0; cnt < key_len; ++cnt)
Packit 6c4009
    sha512_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);
Packit 6c4009
Packit 6c4009
  /* Finish the digest.  */
Packit 6c4009
  sha512_finish_ctx (&alt_ctx, nss_alt_ctx, temp_result);
Packit 6c4009
Packit 6c4009
  /* Create byte sequence P.  */
Packit 6c4009
  if (__libc_use_alloca (alloca_used + key_len))
Packit 6c4009
    cp = p_bytes = (char *) alloca (key_len);
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      free_pbytes = cp = p_bytes = (char *)malloc (key_len);
Packit 6c4009
      if (free_pbytes == NULL)
Packit 6c4009
	{
Packit 6c4009
	  free (free_key);
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  for (cnt = key_len; cnt >= 64; cnt -= 64)
Packit 6c4009
    cp = mempcpy (cp, temp_result, 64);
Packit 6c4009
  memcpy (cp, temp_result, cnt);
Packit 6c4009
Packit 6c4009
  /* Start computation of S byte sequence.  */
Packit 6c4009
  sha512_init_ctx (&alt_ctx, nss_alt_ctx);
Packit 6c4009
Packit 6c4009
  /* For every character in the password add the entire password.  */
Packit 6c4009
  for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
Packit 6c4009
    sha512_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx);
Packit 6c4009
Packit 6c4009
  /* Finish the digest.  */
Packit 6c4009
  sha512_finish_ctx (&alt_ctx, nss_alt_ctx, temp_result);
Packit 6c4009
Packit 6c4009
  /* Create byte sequence S.  */
Packit 6c4009
  cp = s_bytes = alloca (salt_len);
Packit 6c4009
  for (cnt = salt_len; cnt >= 64; cnt -= 64)
Packit 6c4009
    cp = mempcpy (cp, temp_result, 64);
Packit 6c4009
  memcpy (cp, temp_result, cnt);
Packit 6c4009
Packit 6c4009
  /* Repeatedly run the collected hash value through SHA512 to burn
Packit 6c4009
     CPU cycles.  */
Packit 6c4009
  for (cnt = 0; cnt < rounds; ++cnt)
Packit 6c4009
    {
Packit 6c4009
      /* New context.  */
Packit 6c4009
      sha512_init_ctx (&ctx, nss_ctx);
Packit 6c4009
Packit 6c4009
      /* Add key or last result.  */
Packit 6c4009
      if ((cnt & 1) != 0)
Packit 6c4009
	sha512_process_bytes (p_bytes, key_len, &ctx, nss_ctx);
Packit 6c4009
      else
Packit 6c4009
	sha512_process_bytes (alt_result, 64, &ctx, nss_ctx);
Packit 6c4009
Packit 6c4009
      /* Add salt for numbers not divisible by 3.  */
Packit 6c4009
      if (cnt % 3 != 0)
Packit 6c4009
	sha512_process_bytes (s_bytes, salt_len, &ctx, nss_ctx);
Packit 6c4009
Packit 6c4009
      /* Add key for numbers not divisible by 7.  */
Packit 6c4009
      if (cnt % 7 != 0)
Packit 6c4009
	sha512_process_bytes (p_bytes, key_len, &ctx, nss_ctx);
Packit 6c4009
Packit 6c4009
      /* Add key or last result.  */
Packit 6c4009
      if ((cnt & 1) != 0)
Packit 6c4009
	sha512_process_bytes (alt_result, 64, &ctx, nss_ctx);
Packit 6c4009
      else
Packit 6c4009
	sha512_process_bytes (p_bytes, key_len, &ctx, nss_ctx);
Packit 6c4009
Packit 6c4009
      /* Create intermediate result.  */
Packit 6c4009
      sha512_finish_ctx (&ctx, nss_ctx, alt_result);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#ifdef USE_NSS
Packit 6c4009
  /* Free libfreebl3 resources. */
Packit 6c4009
  NSSLOW_Shutdown (nss_ictx);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Now we can construct the result string.  It consists of three
Packit 6c4009
     parts.  */
Packit 6c4009
  cp = __stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen));
Packit 6c4009
  buflen -= sizeof (sha512_salt_prefix) - 1;
Packit 6c4009
Packit 6c4009
  if (rounds_custom)
Packit 6c4009
    {
Packit 6c4009
      int n = __snprintf (cp, MAX (0, buflen), "%s%zu$",
Packit 6c4009
			  sha512_rounds_prefix, rounds);
Packit 6c4009
      cp += n;
Packit 6c4009
      buflen -= n;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
Packit 6c4009
  buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
Packit 6c4009
Packit 6c4009
  if (buflen > 0)
Packit 6c4009
    {
Packit 6c4009
      *cp++ = '$';
Packit 6c4009
      --buflen;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[0], alt_result[21], alt_result[42], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[22], alt_result[43], alt_result[1], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[44], alt_result[2], alt_result[23], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[3], alt_result[24], alt_result[45], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[25], alt_result[46], alt_result[4], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[47], alt_result[5], alt_result[26], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[6], alt_result[27], alt_result[48], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[28], alt_result[49], alt_result[7], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[50], alt_result[8], alt_result[29], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[9], alt_result[30], alt_result[51], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[31], alt_result[52], alt_result[10], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[53], alt_result[11], alt_result[32], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[12], alt_result[33], alt_result[54], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[34], alt_result[55], alt_result[13], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[56], alt_result[14], alt_result[35], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[15], alt_result[36], alt_result[57], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[37], alt_result[58], alt_result[16], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[59], alt_result[17], alt_result[38], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[18], alt_result[39], alt_result[60], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[40], alt_result[61], alt_result[19], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    alt_result[62], alt_result[20], alt_result[41], 4);
Packit 6c4009
  __b64_from_24bit (&cp, &buflen,
Packit 6c4009
		    0, 0, alt_result[63], 2);
Packit 6c4009
Packit 6c4009
  if (buflen <= 0)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ERANGE);
Packit 6c4009
      buffer = NULL;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    *cp = '\0';		/* Terminate the string.  */
Packit 6c4009
Packit 6c4009
  /* Clear the buffer for the intermediate result so that people
Packit 6c4009
     attaching to processes or reading core dumps cannot get any
Packit 6c4009
     information.  We do it in this way to clear correct_words[]
Packit 6c4009
     inside the SHA512 implementation as well.  */
Packit 6c4009
#ifndef USE_NSS
Packit 6c4009
  __sha512_init_ctx (&ctx;;
Packit 6c4009
  __sha512_finish_ctx (&ctx, alt_result);
Packit 6c4009
  explicit_bzero (&ctx, sizeof (ctx));
Packit 6c4009
  explicit_bzero (&alt_ctx, sizeof (alt_ctx));
Packit 6c4009
#endif
Packit 6c4009
  explicit_bzero (temp_result, sizeof (temp_result));
Packit 6c4009
  explicit_bzero (p_bytes, key_len);
Packit 6c4009
  explicit_bzero (s_bytes, salt_len);
Packit 6c4009
  if (copied_key != NULL)
Packit 6c4009
    explicit_bzero (copied_key, key_len);
Packit 6c4009
  if (copied_salt != NULL)
Packit 6c4009
    explicit_bzero (copied_salt, salt_len);
Packit 6c4009
Packit 6c4009
  free (free_key);
Packit 6c4009
  free (free_pbytes);
Packit 6c4009
  return buffer;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifndef _LIBC
Packit 6c4009
# define libc_freeres_ptr(decl) decl
Packit 6c4009
#endif
Packit 6c4009
libc_freeres_ptr (static char *buffer);
Packit 6c4009
Packit 6c4009
/* This entry point is equivalent to the `crypt' function in Unix
Packit 6c4009
   libcs.  */
Packit 6c4009
char *
Packit 6c4009
__sha512_crypt (const char *key, const char *salt)
Packit 6c4009
{
Packit 6c4009
  /* We don't want to have an arbitrary limit in the size of the
Packit 6c4009
     password.  We can compute an upper bound for the size of the
Packit 6c4009
     result in advance and so we can prepare the buffer we pass to
Packit 6c4009
     `sha512_crypt_r'.  */
Packit 6c4009
  static int buflen;
Packit 6c4009
  int needed = (sizeof (sha512_salt_prefix) - 1
Packit 6c4009
		+ sizeof (sha512_rounds_prefix) + 9 + 1
Packit 6c4009
		+ strlen (salt) + 1 + 86 + 1);
Packit 6c4009
Packit 6c4009
  if (buflen < needed)
Packit 6c4009
    {
Packit 6c4009
      char *new_buffer = (char *) realloc (buffer, needed);
Packit 6c4009
      if (new_buffer == NULL)
Packit 6c4009
	return NULL;
Packit 6c4009
Packit 6c4009
      buffer = new_buffer;
Packit 6c4009
      buflen = needed;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return __sha512_crypt_r (key, salt, buffer, buflen);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifndef _LIBC
Packit 6c4009
static void
Packit 6c4009
__attribute__ ((__destructor__))
Packit 6c4009
free_mem (void)
Packit 6c4009
{
Packit 6c4009
  free (buffer);
Packit 6c4009
}
Packit 6c4009
#endif