Bruno Haible
2018-05-06 15:12:51 UTC
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 <***@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.
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)
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 <***@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.
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)