bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 1/4] sha1sum: use AF_ALG when available


From: Matteo Croce
Subject: [PATCH 1/4] sha1sum: use AF_ALG when available
Date: Mon, 23 Apr 2018 13:17:16 +0200

Linux supports accessing kernel cryptographic API via AF_ALG since
version 2.6.38. Coreutils uses libcrypto when available and fallbacks to
generic C implementation of various hashing functions.

Add a generic afalg_stream() function which uses AF_ALG to calculate the
hash of a stream and use sendfile() when possible (regular file with size
less or equal than 0x7ffff000 (2,147,479,552) bytes, AKA MAX_RW_COUNT).

Use afalg_stream() only in sha1sum for now, but other hashes are possible.
The speed gain really depends on the CPU type, on systems which doesn't use
libcrypto ranges from ~10% to 320%.

This is a test on a Intel(R) Xeon(R) CPU E3-1265L V2 and Debian stretch:

    $ truncate -s 2GB 2g.bin
    $ time sha1sum 2g.bin
    752ef2367f479e79e4f0cded9c270c2890506ab0  2g.bin

    real    0m4.829s
    user    0m4.437s
    sys     0m0.391s
    $ time ./sha1sum-afalg 2g.bin
    752ef2367f479e79e4f0cded9c270c2890506ab0  2g.bin

    real    0m3.164s
    user    0m0.000s
    sys     0m3.162s

Signed-off-by: Matteo Croce <address@hidden>
---
 lib/af_alg.c        | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/af_alg.h        |  46 ++++++++++++++++++++++++
 lib/sha1.c          |  13 ++++++-
 modules/crypto/sha1 |   5 ++-
 4 files changed, 164 insertions(+), 2 deletions(-)
 create mode 100644 lib/af_alg.c
 create mode 100644 lib/af_alg.h

diff --git a/lib/af_alg.c b/lib/af_alg.c
new file mode 100644
index 000000000..0a1437d6c
--- /dev/null
+++ b/lib/af_alg.c
@@ -0,0 +1,102 @@
+/* AF_ALG support
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include "af_alg.h"
+
+/* from linux/include/linux/fs.h: (INT_MAX & PAGE_MASK) */
+#define MAX_RW_COUNT 0x7FFFF000
+#define BLOCKSIZE 32768
+
+int
+afalg_stream (FILE * stream, void *resblock, const char *alg, int hashlen)
+{
+  struct sockaddr_alg salg = {
+    .salg_family = AF_ALG,
+    .salg_type = "hash",
+  };
+  int ret, cfd, ofd;
+  static char buf[BLOCKSIZE];
+  ssize_t size;
+  struct stat st;
+
+  strcpy((char *)salg.salg_name, alg);
+  cfd = socket (AF_ALG, SOCK_SEQPACKET, 0);
+  if (cfd < 0)
+      return -EAFNOSUPPORT;
+
+  ret = bind (cfd, (struct sockaddr *) &salg, sizeof (salg));
+  if (ret < 0)
+    {
+      ret = -EAFNOSUPPORT;
+      goto out_cfd;
+    }
+
+  ofd = accept (cfd, NULL, 0);
+  if (ofd < 0)
+    {
+      ret = -EAFNOSUPPORT;
+      goto out_ofd;
+    }
+
+  /* if file is a regular file, attempt sendfile() to pipe the data */
+  if (!fstat(fileno(stream), &st) && S_ISREG(st.st_mode) &&
+      st.st_size <= MAX_RW_COUNT)
+    {
+      if (sendfile(ofd, fileno(stream), NULL, st.st_size) == -1)
+        ret = -EIO;
+      else
+        ret = 0;
+    } else {
+      /* sendfile() not possible, do a classic read-write loop */
+      while ((size = fread (buf, 1, sizeof (buf), stream)))
+        {
+          if (send (ofd, buf, size, size == sizeof (buf) ? MSG_MORE : 0) == -1)
+            {
+              ret = -EIO;
+              goto out_ofd;
+            }
+        }
+  }
+
+  size = read (ofd, resblock, hashlen);
+  if (size != hashlen)
+    {
+      fprintf (stderr, "Error from read (%zd vs %d bytes): %s\n",
+               size, hashlen, strerror (errno));
+      ret = -EIO;
+    }
+  else
+    {
+      ret = 0;
+    }
+out_ofd:
+  close (ofd);
+out_cfd:
+  close (cfd);
+  return ret;
+}
+
+# ifdef __cplusplus
+}
+# endif
+
+/*
+ * Hey Emacs!
+ * Local Variables:
+ * coding: utf-8
+ * End:
+ */
diff --git a/lib/af_alg.h b/lib/af_alg.h
new file mode 100644
index 000000000..678c03aad
--- /dev/null
+++ b/lib/af_alg.h
@@ -0,0 +1,46 @@
+/* AF_ALG support
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
+
+#ifndef AF_ALG_H
+# define AF_ALG_H 1
+
+# include <unistd.h>
+# include <stdio.h>
+# include <string.h>
+# include <errno.h>
+# include <linux/if_alg.h>
+# include <sys/socket.h>
+# include <sys/stat.h>
+# include <sys/sendfile.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+int
+afalg_stream (FILE * stream, void *resblock, const char *alg, int hashlen);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
+
+/*
+ * Hey Emacs!
+ * Local Variables:
+ * coding: utf-8
+ * End:
+ */
diff --git a/lib/sha1.c b/lib/sha1.c
index 37d46b68e..dac6cac8a 100644
--- a/lib/sha1.c
+++ b/lib/sha1.c
@@ -37,6 +37,8 @@
 # include "unlocked-io.h"
 #endif
 
+#include "af_alg.h"
+
 #ifdef WORDS_BIGENDIAN
 # define SWAP(n) (n)
 #else
@@ -130,8 +132,17 @@ sha1_stream (FILE *stream, void *resblock)
 {
   struct sha1_ctx ctx;
   size_t sum;
+  int ret;
+  char *buffer;
+
+  ret = afalg_stream(stream, resblock, "sha1", SHA1_DIGEST_SIZE);
+  if (!ret)
+      return 0;
+
+  if (ret == -EIO)
+      return 1;
 
-  char *buffer = malloc (BLOCKSIZE + 72);
+  buffer = malloc (BLOCKSIZE + 72);
   if (!buffer)
     return 1;
 
diff --git a/modules/crypto/sha1 b/modules/crypto/sha1
index d65f99418..a2b7df211 100644
--- a/modules/crypto/sha1
+++ b/modules/crypto/sha1
@@ -5,6 +5,8 @@ Files:
 lib/gl_openssl.h
 lib/sha1.h
 lib/sha1.c
+lib/af_alg.h
+lib/af_alg.c
 m4/gl-openssl.m4
 m4/sha1.m4
 
@@ -17,10 +19,11 @@ configure.ac:
 gl_SHA1
 
 Makefile.am:
-lib_SOURCES += sha1.c
+lib_SOURCES += sha1.c af_alg.c
 
 Include:
 "sha1.h"
+"af_alg.h"
 
 Link:
 $(LIB_CRYPTO)
-- 
2.14.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]