]> Savannah Git Hosting - gnulib.git/commitdiff
af_alg: Add ability to use Linux kernel crypto API on data in memory.
authorBruno Haible <bruno@clisp.org>
Sun, 6 May 2018 15:04:25 +0000 (17:04 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 6 May 2018 15:10:45 +0000 (17:10 +0200)
* lib/af_alg.h (afalg_buffer): New declaration.
* lib/af_alg.c (afalg_buffer): New function.

ChangeLog
lib/af_alg.c
lib/af_alg.h

index 60f65f4c26ac7ecec26f1e216d97867233ff6b33..ab3143c536e57d061304f2c192b2a37254e39e14 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2018-05-06  Bruno Haible  <bruno@clisp.org>
+
+       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.
+
 2018-05-06  Bruno Haible  <bruno@clisp.org>
 
        af_alg: Avoid warnings.
index 0319459496a598a0a4cf83880484260316cb4df8..08d6659271403a0087188a27a9b2ac67864fb15f 100644 (file)
 #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)
index 45c2c125d3e58bb1a179cb2779b3961fcb4cbdd4..018fa221a0da109e2b8291d58368a914c3baefcc 100644 (file)
@@ -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;
 }