bug-gnulib
[Top][All Lists]
Advanced

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

af_alg: Add ability to use Linux kernel crypto API on data in memory


From: Bruno Haible
Subject: af_alg: Add ability to use Linux kernel crypto API on data in memory
Date: Sun, 06 May 2018 17:12:51 +0200
User-agent: KMail/5.1.3 (Linux/4.4.0-119-generic; KDE/5.18.0; x86_64; ; )

It is to be expected that crypto hardware would not only speed up
sha1_stream but also sha1_buffer (where the input is in memory).

The second step is to add to 'af_alg' a function that can be used by each of
md5_buffer, sha1_buffer, etc.


2018-05-06  Bruno Haible  <address@hidden>

        af_alg: Add ability to use Linux kernel crypto API on data in memory.
        * lib/af_alg.h (afalg_buffer): New declaration.
        * lib/af_alg.c (afalg_buffer): New function.

diff --git a/lib/af_alg.h b/lib/af_alg.h
index 45c2c12..018fa22 100644
--- a/lib/af_alg.h
+++ b/lib/af_alg.h
@@ -37,6 +37,30 @@ extern "C" {
 
 # if USE_LINUX_CRYPTO_API
 
+/* Compute a message digest of a memory region.
+
+   The memory region starts at BUFFER and is LEN bytes long.
+
+   ALG is the message digest algorithm; see the file /proc/crypto.
+
+   RESBLOCK points to a block of HASHLEN bytes, for the result.
+   HASHLEN must be the length of the message digest, in bytes, in particular:
+
+      alg    | hashlen
+      -------+--------
+      md5    | 16
+      sha1   | 20
+      sha224 | 28
+      sha256 | 32
+      sha384 | 48
+      sha512 | 64
+
+   If successful, fill RESBLOCK and return 0.
+   Upon failure, return a negated error number.  */
+int
+afalg_buffer (const char *buffer, size_t len, const char *alg,
+              void *resblock, ssize_t hashlen);
+
 /* Compute a message digest of the contents of a file.
 
    STREAM is an open file stream.  Regular files are handled more efficiently.
@@ -60,12 +84,21 @@ extern "C" {
    If successful, fill RESBLOCK and return 0.
    Upon failure, return a negated error number.  */
 int
-afalg_stream (FILE *stream, const char *alg, void *resblock, ssize_t hashlen);
+afalg_stream (FILE *stream, const char *alg,
+              void *resblock, ssize_t hashlen);
 
 # else
 
 static inline int
-afalg_stream (FILE *stream, const char *alg, void *resblock, ssize_t hashlen)
+afalg_buffer (const char *buffer, size_t len, const char *alg,
+              void *resblock, ssize_t hashlen)
+{
+  return -EAFNOSUPPORT;
+}
+
+static inline int
+afalg_stream (FILE *stream, const char *alg,
+              void *resblock, ssize_t hashlen)
 {
   return -EAFNOSUPPORT;
 }
diff --git a/lib/af_alg.c b/lib/af_alg.c
index 0319459..08d6659 100644
--- a/lib/af_alg.c
+++ b/lib/af_alg.c
@@ -37,7 +37,73 @@
 #define BLOCKSIZE 32768
 
 int
-afalg_stream (FILE *stream, const char *alg, void *resblock, ssize_t hashlen)
+afalg_buffer (const char *buffer, size_t len, const char *alg,
+              void *resblock, ssize_t hashlen)
+{
+  /* On Linux < 4.9, the value for an empty stream is wrong (all zeroes).
+     See <https://patchwork.kernel.org/patch/9434741/>.  */
+  if (len == 0)
+    return -EAFNOSUPPORT;
+
+  int cfd = socket (AF_ALG, SOCK_SEQPACKET, 0);
+  if (cfd < 0)
+    return -EAFNOSUPPORT;
+
+  int result;
+  struct sockaddr_alg salg = {
+    .salg_family = AF_ALG,
+    .salg_type = "hash",
+  };
+  /* Avoid calling both strcpy and strlen.  */
+  for (int i = 0; (salg.salg_name[i] = alg[i]); i++)
+    if (i == sizeof salg.salg_name - 1)
+      {
+        result = -EINVAL;
+        goto out_cfd;
+      }
+
+  int ret = bind (cfd, (struct sockaddr *) &salg, sizeof salg);
+  if (ret != 0)
+    {
+      result = -EAFNOSUPPORT;
+      goto out_cfd;
+    }
+
+  int ofd = accept (cfd, NULL, 0);
+  if (ofd < 0)
+    {
+      result = -EAFNOSUPPORT;
+      goto out_cfd;
+    }
+
+  do
+    {
+      ssize_t size = (len > BLOCKSIZE ? BLOCKSIZE : len);
+      if (send (ofd, buffer, size, MSG_MORE) != size)
+        {
+          result = -EIO;
+          goto out_ofd;
+        }
+      buffer += size;
+      len -= size;
+    }
+  while (len > 0);
+
+  if (read (ofd, resblock, hashlen) != hashlen)
+    result = -EIO;
+  else
+    result = 0;
+
+out_ofd:
+  close (ofd);
+out_cfd:
+  close (cfd);
+  return result;
+}
+
+int
+afalg_stream (FILE *stream, const char *alg,
+              void *resblock, ssize_t hashlen)
 {
   int cfd = socket (AF_ALG, SOCK_SEQPACKET, 0);
   if (cfd < 0)




reply via email to

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