summary refs log tree commit diff stats
path: root/libotr/libgcrypt-1.8.7/cipher/hash-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'libotr/libgcrypt-1.8.7/cipher/hash-common.c')
-rw-r--r--libotr/libgcrypt-1.8.7/cipher/hash-common.c167
1 files changed, 167 insertions, 0 deletions
diff --git a/libotr/libgcrypt-1.8.7/cipher/hash-common.c b/libotr/libgcrypt-1.8.7/cipher/hash-common.c
new file mode 100644
index 0000000..a750d64
--- /dev/null
+++ b/libotr/libgcrypt-1.8.7/cipher/hash-common.c
@@ -0,0 +1,167 @@
+/* hash-common.c - Common code for hash algorithms
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt 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.
+ *
+ * Libgcrypt 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#include "g10lib.h"
+#include "hash-common.h"
+
+
+/* Run a selftest for hash algorithm ALGO.  If the resulting digest
+   matches EXPECT/EXPECTLEN and everything else is fine as well,
+   return NULL.  If an error occurs, return a static text string
+   describing the error.
+
+   DATAMODE controls what will be hashed according to this table:
+
+     0 - Hash the supplied DATA of DATALEN.
+     1 - Hash one million times a 'a'.  DATA and DATALEN are ignored.
+
+*/
+const char *
+_gcry_hash_selftest_check_one (int algo,
+                               int datamode, const void *data, size_t datalen,
+                               const void *expect, size_t expectlen)
+{
+  const char *result = NULL;
+  gcry_error_t err = 0;
+  gcry_md_hd_t hd;
+  unsigned char *digest;
+  char aaa[1000];
+  int xof = 0;
+
+  if (_gcry_md_get_algo_dlen (algo) == 0)
+    xof = 1;
+  else if (_gcry_md_get_algo_dlen (algo) != expectlen)
+    return "digest size does not match expected size";
+
+  err = _gcry_md_open (&hd, algo, 0);
+  if (err)
+    return "gcry_md_open failed";
+
+  switch (datamode)
+    {
+    case 0:
+      _gcry_md_write (hd, data, datalen);
+      break;
+
+    case 1: /* Hash one million times an "a". */
+      {
+        int i;
+
+        /* Write in odd size chunks so that we test the buffering.  */
+        memset (aaa, 'a', 1000);
+        for (i = 0; i < 1000; i++)
+          _gcry_md_write (hd, aaa, 1000);
+      }
+      break;
+
+    default:
+      result = "invalid DATAMODE";
+    }
+
+  if (!result)
+    {
+      if (!xof)
+	{
+	  digest = _gcry_md_read (hd, algo);
+
+	  if ( memcmp (digest, expect, expectlen) )
+	    result = "digest mismatch";
+	}
+      else
+	{
+	  gcry_assert(expectlen <= sizeof(aaa));
+
+	  err = _gcry_md_extract (hd, algo, aaa, expectlen);
+	  if (err)
+	    result = "error extracting output from XOF";
+	  else if ( memcmp (aaa, expect, expectlen) )
+	    result = "digest mismatch";
+	}
+    }
+
+  _gcry_md_close (hd);
+
+  return result;
+}
+
+
+/* Common function to write a chunk of data to the transform function
+   of a hash algorithm.  Note that the use of the term "block" does
+   not imply a fixed size block.  Note that we explicitly allow to use
+   this function after the context has been finalized; the result does
+   not have any meaning but writing after finalize is sometimes
+   helpful to mitigate timing attacks. */
+void
+_gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen)
+{
+  const unsigned char *inbuf = inbuf_arg;
+  gcry_md_block_ctx_t *hd = context;
+  unsigned int stack_burn = 0;
+  const unsigned int blocksize = hd->blocksize;
+  size_t inblocks;
+
+  if (sizeof(hd->buf) < blocksize)
+    BUG();
+
+  if (!hd->bwrite)
+    return;
+
+  if (hd->count == blocksize)  /* Flush the buffer. */
+    {
+      stack_burn = hd->bwrite (hd, hd->buf, 1);
+      _gcry_burn_stack (stack_burn);
+      stack_burn = 0;
+      hd->count = 0;
+      if (!++hd->nblocks)
+        hd->nblocks_high++;
+    }
+  if (!inbuf)
+    return;
+
+  if (hd->count)
+    {
+      for (; inlen && hd->count < blocksize; inlen--)
+        hd->buf[hd->count++] = *inbuf++;
+      _gcry_md_block_write (hd, NULL, 0);
+      if (!inlen)
+        return;
+    }
+
+  if (inlen >= blocksize)
+    {
+      inblocks = inlen / blocksize;
+      stack_burn = hd->bwrite (hd, inbuf, inblocks);
+      hd->count = 0;
+      hd->nblocks_high += (hd->nblocks + inblocks < inblocks);
+      hd->nblocks += inblocks;
+      inlen -= inblocks * blocksize;
+      inbuf += inblocks * blocksize;
+    }
+  _gcry_burn_stack (stack_burn);
+  for (; inlen && hd->count < blocksize; inlen--)
+    hd->buf[hd->count++] = *inbuf++;
+}