Beispiel #1
0
/* Test md5 in a single md5_process_bytes call.  */
static int
test_single (void *buf, size_t len, const char *ref)
{
  char sum[16];
  struct md5_ctx ctx;

  __md5_init_ctx (&ctx);
  __md5_process_bytes (buf, len, &ctx);
  __md5_finish_ctx (&ctx, sum);

  return report ("single", sum, len, ref);
}
Beispiel #2
0
/* Test md5 with two md5_process_bytes calls to trigger a
   different path in md5_process_block for sizes > 2 GB.  */
static int
test_double (void *buf, size_t len, const char *ref)
{
  char sum[16];
  struct md5_ctx ctx;

  __md5_init_ctx (&ctx);
  if (len >= CONST_2G)
    {
      __md5_process_bytes (buf, CONST_2G, &ctx);
      __md5_process_bytes (buf + CONST_2G, len - CONST_2G, &ctx);
    }
  else
    __md5_process_bytes (buf, len, &ctx);

  __md5_finish_ctx (&ctx, sum);

  return report ("double", sum, len, ref);
}
Beispiel #3
0
/* This entry point is equivalent to the `crypt' function in Unix
   libcs.  */
char *
__md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
{
  unsigned char alt_result[16]
    __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
  size_t salt_len;
  size_t key_len;
  size_t cnt;
  char *cp;
  char *copied_key = NULL;
  char *copied_salt = NULL;
  char *free_key = NULL;
  size_t alloca_used = 0;

  /* Find beginning of salt string.  The prefix should normally always
     be present.  Just in case it is not.  */
  if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
    /* Skip salt prefix.  */
    salt += sizeof (md5_salt_prefix) - 1;

  salt_len = MIN (strcspn (salt, "$"), 8);
  key_len = strlen (key);

  if ((key - (char *) 0) % __alignof__ (md5_uint32) != 0)
    {
      char *tmp;

      if (__libc_use_alloca (alloca_used + key_len + __alignof__ (md5_uint32)))
	tmp = (char *) alloca (key_len + __alignof__ (md5_uint32));
      else
	{
	  free_key = tmp = (char *) malloc (key_len + __alignof__ (md5_uint32));
	  if (tmp == NULL)
	    return NULL;
	}

      key = copied_key =
	memcpy (tmp + __alignof__ (md5_uint32)
		- (tmp - (char *) 0) % __alignof__ (md5_uint32),
		key, key_len);
      assert ((key - (char *) 0) % __alignof__ (md5_uint32) == 0);
    }

  if ((salt - (char *) 0) % __alignof__ (md5_uint32) != 0)
    {
      char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32));
      salt = copied_salt =
	memcpy (tmp + __alignof__ (md5_uint32)
		- (tmp - (char *) 0) % __alignof__ (md5_uint32),
		salt, salt_len);
      assert ((salt - (char *) 0) % __alignof__ (md5_uint32) == 0);
    }

#ifdef USE_NSS
  /* Initialize libfreebl3.  */
  NSSLOWInitContext *nss_ictx = NSSLOW_Init ();
  if (nss_ictx == NULL)
    {
      free (free_key);
      return NULL;
    }
  NSSLOWHASHContext *nss_ctx = NULL;
  NSSLOWHASHContext *nss_alt_ctx = NULL;
#else
  struct md5_ctx ctx;
  struct md5_ctx alt_ctx;
#endif

  /* Prepare for the real work.  */
  md5_init_ctx (&ctx, nss_ctx);

  /* Add the key string.  */
  md5_process_bytes (key, key_len, &ctx, nss_ctx);

  /* Because the SALT argument need not always have the salt prefix we
     add it separately.  */
  md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1,
		     &ctx, nss_ctx);

  /* The last part is the salt string.  This must be at most 8
     characters and it ends at the first `$' character (for
     compatibility with existing implementations).  */
  md5_process_bytes (salt, salt_len, &ctx, nss_ctx);


  /* Compute alternate MD5 sum with input KEY, SALT, and KEY.  The
     final result will be added to the first context.  */
  md5_init_ctx (&alt_ctx, nss_alt_ctx);

  /* Add key.  */
  md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);

  /* Add salt.  */
  md5_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx);

  /* Add key again.  */
  md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx);

  /* Now get result of this (16 bytes) and add it to the other
     context.  */
  md5_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result);

  /* Add for any character in the key one byte of the alternate sum.  */
  for (cnt = key_len; cnt > 16; cnt -= 16)
    md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
  md5_process_bytes (alt_result, cnt, &ctx, nss_ctx);

  /* For the following code we need a NUL byte.  */
  *alt_result = '\0';

  /* The original implementation now does something weird: for every 1
     bit in the key the first 0 is added to the buffer, for every 0
     bit the first character of the key.  This does not seem to be
     what was intended but we have to follow this to be compatible.  */
  for (cnt = key_len; cnt > 0; cnt >>= 1)
    md5_process_bytes ((cnt & 1) != 0
		       ? (const void *) alt_result : (const void *) key, 1,
		       &ctx, nss_ctx);

  /* Create intermediate result.  */
  md5_finish_ctx (&ctx, nss_ctx, alt_result);

  /* Now comes another weirdness.  In fear of password crackers here
     comes a quite long loop which just processes the output of the
     previous round again.  We cannot ignore this here.  */
  for (cnt = 0; cnt < 1000; ++cnt)
    {
      /* New context.  */
      md5_init_ctx (&ctx, nss_ctx);

      /* Add key or last result.  */
      if ((cnt & 1) != 0)
	md5_process_bytes (key, key_len, &ctx, nss_ctx);
      else
	md5_process_bytes (alt_result, 16, &ctx, nss_ctx);

      /* Add salt for numbers not divisible by 3.  */
      if (cnt % 3 != 0)
	md5_process_bytes (salt, salt_len, &ctx, nss_ctx);

      /* Add key for numbers not divisible by 7.  */
      if (cnt % 7 != 0)
	md5_process_bytes (key, key_len, &ctx, nss_ctx);

      /* Add key or last result.  */
      if ((cnt & 1) != 0)
	md5_process_bytes (alt_result, 16, &ctx, nss_ctx);
      else
	md5_process_bytes (key, key_len, &ctx, nss_ctx);

      /* Create intermediate result.  */
      md5_finish_ctx (&ctx, nss_ctx, alt_result);
    }

#ifdef USE_NSS
  /* Free libfreebl3 resources. */
  NSSLOW_Shutdown (nss_ictx);
#endif

  /* Now we can construct the result string.  It consists of three
     parts.  */
  cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen));
  buflen -= sizeof (md5_salt_prefix) - 1;

  cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
  buflen -= MIN ((size_t) MAX (0, buflen), salt_len);

  if (buflen > 0)
    {
      *cp++ = '$';
      --buflen;
    }

  __b64_from_24bit (&cp, &buflen,
		    alt_result[0], alt_result[6], alt_result[12], 4);
  __b64_from_24bit (&cp, &buflen,
		    alt_result[1], alt_result[7], alt_result[13], 4);
  __b64_from_24bit (&cp, &buflen,
		    alt_result[2], alt_result[8], alt_result[14], 4);
  __b64_from_24bit (&cp, &buflen,
		    alt_result[3], alt_result[9], alt_result[15], 4);
  __b64_from_24bit (&cp, &buflen,
		    alt_result[4], alt_result[10], alt_result[5], 4);
  __b64_from_24bit (&cp, &buflen,
		    0, 0, alt_result[11], 2);
  if (buflen <= 0)
    {
      __set_errno (ERANGE);
      buffer = NULL;
    }
  else
    *cp = '\0';		/* Terminate the string.  */

  /* Clear the buffer for the intermediate result so that people
     attaching to processes or reading core dumps cannot get any
     information.  We do it in this way to clear correct_words[]
     inside the MD5 implementation as well.  */
#ifndef USE_NSS
  __md5_init_ctx (&ctx);
  __md5_finish_ctx (&ctx, alt_result);
  explicit_bzero (&ctx, sizeof (ctx));
  explicit_bzero (&alt_ctx, sizeof (alt_ctx));
#endif
  if (copied_key != NULL)
    explicit_bzero (copied_key, key_len);
  if (copied_salt != NULL)
    explicit_bzero (copied_salt, salt_len);

  free (free_key);
  return buffer;
}