Blame crypt/md5.c

Packit 6c4009
/* Functions to compute MD5 message digest of files or memory blocks.
Packit 6c4009
   according to the definition of MD5 in RFC 1321 from April 1992.
Packit 6c4009
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
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
/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
Packit 6c4009
Packit 6c4009
#ifdef HAVE_CONFIG_H
Packit 6c4009
# include <config.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
Packit 6c4009
#if STDC_HEADERS || defined _LIBC
Packit 6c4009
# include <stdlib.h>
Packit 6c4009
# include <string.h>
Packit 6c4009
#else
Packit 6c4009
# ifndef HAVE_MEMCPY
Packit 6c4009
#  define memcpy(d, s, n) (bcopy ((s), (d), (n)), (d))
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include "md5.h"
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
# include <endian.h>
Packit 6c4009
# if __BYTE_ORDER == __BIG_ENDIAN
Packit 6c4009
#  define WORDS_BIGENDIAN 1
Packit 6c4009
# endif
Packit 6c4009
/* We need to keep the namespace clean so define the MD5 function
Packit 6c4009
   protected using leading __ .  */
Packit 6c4009
# define md5_init_ctx __md5_init_ctx
Packit 6c4009
# define md5_process_bytes __md5_process_bytes
Packit 6c4009
# define md5_finish_ctx __md5_finish_ctx
Packit 6c4009
# define md5_read_ctx __md5_read_ctx
Packit 6c4009
# define md5_stream __md5_stream
Packit 6c4009
# define md5_buffer __md5_buffer
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef WORDS_BIGENDIAN
Packit 6c4009
# define SWAP(n)							\
Packit 6c4009
    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
Packit 6c4009
#else
Packit 6c4009
# define SWAP(n) (n)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* This array contains the bytes used to pad the buffer to the next
Packit 6c4009
   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
Packit 6c4009
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Initialize structure containing state of computation.
Packit 6c4009
   (RFC 1321, 3.3: Step 3)  */
Packit 6c4009
void
Packit 6c4009
md5_init_ctx (struct md5_ctx *ctx)
Packit 6c4009
{
Packit 6c4009
  ctx->A = 0x67452301;
Packit 6c4009
  ctx->B = 0xefcdab89;
Packit 6c4009
  ctx->C = 0x98badcfe;
Packit 6c4009
  ctx->D = 0x10325476;
Packit 6c4009
Packit 6c4009
  ctx->total[0] = ctx->total[1] = 0;
Packit 6c4009
  ctx->buflen = 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Put result from CTX in first 16 bytes following RESBUF.  The result
Packit 6c4009
   must be in little endian byte order.
Packit 6c4009
Packit 6c4009
   IMPORTANT: On some systems it is required that RESBUF is correctly
Packit 6c4009
   aligned for a 32 bits value.  */
Packit 6c4009
void *
Packit 6c4009
md5_read_ctx (const struct md5_ctx *ctx, void *resbuf)
Packit 6c4009
{
Packit 6c4009
  ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
Packit 6c4009
  ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
Packit 6c4009
  ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
Packit 6c4009
  ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
Packit 6c4009
Packit 6c4009
  return resbuf;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Process the remaining bytes in the internal buffer and the usual
Packit 6c4009
   prolog according to the standard and write the result to RESBUF.
Packit 6c4009
Packit 6c4009
   IMPORTANT: On some systems it is required that RESBUF is correctly
Packit 6c4009
   aligned for a 32 bits value.  */
Packit 6c4009
void *
Packit 6c4009
md5_finish_ctx (struct md5_ctx *ctx, void *resbuf)
Packit 6c4009
{
Packit 6c4009
  /* Take yet unprocessed bytes into account.  */
Packit 6c4009
  md5_uint32 bytes = ctx->buflen;
Packit 6c4009
  size_t pad;
Packit 6c4009
Packit 6c4009
  /* Now count remaining bytes.  */
Packit 6c4009
  ctx->total[0] += bytes;
Packit 6c4009
  if (ctx->total[0] < bytes)
Packit 6c4009
    ++ctx->total[1];
Packit 6c4009
Packit 6c4009
  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
Packit 6c4009
  memcpy (&ctx->buffer[bytes], fillbuf, pad);
Packit 6c4009
Packit 6c4009
  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
Packit 6c4009
  ctx->buffer32[(bytes + pad) / 4] = SWAP (ctx->total[0] << 3);
Packit 6c4009
  ctx->buffer32[(bytes + pad + 4) / 4] = SWAP ((ctx->total[1] << 3) |
Packit 6c4009
					       (ctx->total[0] >> 29));
Packit 6c4009
Packit 6c4009
  /* Process last bytes.  */
Packit 6c4009
  __md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
Packit 6c4009
Packit 6c4009
  return md5_read_ctx (ctx, resbuf);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Compute MD5 message digest for bytes read from STREAM.  The
Packit 6c4009
   resulting message digest number will be written into the 16 bytes
Packit 6c4009
   beginning at RESBLOCK.  */
Packit 6c4009
int
Packit 6c4009
md5_stream (FILE *stream, void *resblock)
Packit 6c4009
{
Packit 6c4009
  /* Important: BLOCKSIZE must be a multiple of 64.  */
Packit 6c4009
#define BLOCKSIZE 4096
Packit 6c4009
  struct md5_ctx ctx;
Packit 6c4009
  char buffer[BLOCKSIZE + 72];
Packit 6c4009
  size_t sum;
Packit 6c4009
Packit 6c4009
  /* Initialize the computation context.  */
Packit 6c4009
  md5_init_ctx (&ctx;;
Packit 6c4009
Packit 6c4009
  /* Iterate over full file contents.  */
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
Packit 6c4009
	 computation function processes the whole buffer so that with the
Packit 6c4009
	 next round of the loop another block can be read.  */
Packit 6c4009
      size_t n;
Packit 6c4009
      sum = 0;
Packit 6c4009
Packit 6c4009
      /* Read block.  Take care for partial reads.  */
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
Packit 6c4009
Packit 6c4009
	  sum += n;
Packit 6c4009
	}
Packit 6c4009
      while (sum < BLOCKSIZE && n != 0);
Packit 6c4009
      if (n == 0 && ferror (stream))
Packit 6c4009
	return 1;
Packit 6c4009
Packit 6c4009
      /* If end of file is reached, end the loop.  */
Packit 6c4009
      if (n == 0)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      /* Process buffer with BLOCKSIZE bytes.  Note that
Packit 6c4009
			BLOCKSIZE % 64 == 0
Packit 6c4009
       */
Packit 6c4009
      __md5_process_block (buffer, BLOCKSIZE, &ctx;;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Add the last bytes if necessary.  */
Packit 6c4009
  if (sum > 0)
Packit 6c4009
    md5_process_bytes (buffer, sum, &ctx;;
Packit 6c4009
Packit 6c4009
  /* Construct result in desired memory.  */
Packit 6c4009
  md5_finish_ctx (&ctx, resblock);
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
Packit 6c4009
   result is always in little endian byte order, so that a byte-wise
Packit 6c4009
   output yields to the wanted ASCII representation of the message
Packit 6c4009
   digest.  */
Packit 6c4009
void *
Packit 6c4009
md5_buffer (const char *buffer, size_t len, void *resblock)
Packit 6c4009
{
Packit 6c4009
  struct md5_ctx ctx;
Packit 6c4009
Packit 6c4009
  /* Initialize the computation context.  */
Packit 6c4009
  md5_init_ctx (&ctx;;
Packit 6c4009
Packit 6c4009
  /* Process whole buffer but last len % 64 bytes.  */
Packit 6c4009
  md5_process_bytes (buffer, len, &ctx;;
Packit 6c4009
Packit 6c4009
  /* Put result in desired memory area.  */
Packit 6c4009
  return md5_finish_ctx (&ctx, resblock);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx)
Packit 6c4009
{
Packit 6c4009
  /* When we already have some bits in our internal buffer concatenate
Packit 6c4009
     both inputs first.  */
Packit 6c4009
  if (ctx->buflen != 0)
Packit 6c4009
    {
Packit 6c4009
      size_t left_over = ctx->buflen;
Packit 6c4009
      size_t add = 128 - left_over > len ? len : 128 - left_over;
Packit 6c4009
Packit 6c4009
      memcpy (&ctx->buffer[left_over], buffer, add);
Packit 6c4009
      ctx->buflen += add;
Packit 6c4009
Packit 6c4009
      if (ctx->buflen > 64)
Packit 6c4009
	{
Packit 6c4009
	  __md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
Packit 6c4009
Packit 6c4009
	  ctx->buflen &= 63;
Packit 6c4009
	  /* The regions in the following copy operation cannot overlap.  */
Packit 6c4009
	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
Packit 6c4009
		  ctx->buflen);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      buffer = (const char *) buffer + add;
Packit 6c4009
      len -= add;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Process available complete blocks.  */
Packit 6c4009
  if (len >= 64)
Packit 6c4009
    {
Packit 6c4009
#if !_STRING_ARCH_unaligned
Packit 6c4009
/* To check alignment gcc has an appropriate operator.  Other
Packit 6c4009
   compilers don't.  */
Packit 6c4009
# if __GNUC__ >= 2
Packit 6c4009
#  define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0)
Packit 6c4009
# else
Packit 6c4009
#  define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0)
Packit 6c4009
# endif
Packit 6c4009
      if (UNALIGNED_P (buffer))
Packit 6c4009
	while (len > 64)
Packit 6c4009
	  {
Packit 6c4009
	    __md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
Packit 6c4009
	    buffer = (const char *) buffer + 64;
Packit 6c4009
	    len -= 64;
Packit 6c4009
	  }
Packit 6c4009
      else
Packit 6c4009
#endif
Packit 6c4009
	{
Packit 6c4009
	  __md5_process_block (buffer, len & ~63, ctx);
Packit 6c4009
	  buffer = (const char *) buffer + (len & ~63);
Packit 6c4009
	  len &= 63;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Move remaining bytes in internal buffer.  */
Packit 6c4009
  if (len > 0)
Packit 6c4009
    {
Packit 6c4009
      size_t left_over = ctx->buflen;
Packit 6c4009
Packit 6c4009
      memcpy (&ctx->buffer[left_over], buffer, len);
Packit 6c4009
      left_over += len;
Packit 6c4009
      if (left_over >= 64)
Packit 6c4009
	{
Packit 6c4009
	  __md5_process_block (ctx->buffer, 64, ctx);
Packit 6c4009
	  left_over -= 64;
Packit 6c4009
	  memcpy (ctx->buffer, &ctx->buffer[64], left_over);
Packit 6c4009
	}
Packit 6c4009
      ctx->buflen = left_over;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#include <md5-block.c>