[PATCH] Updated: EVP_MAC interface for Poly1305
Chris Rapier
rapier at psc.edu
Tue Nov 1 03:16:30 AEDT 2022
I've updated the patch to allow for the use of the EVP_MAC interface
under OpenSSL 3.0. The test is now in configure and explicitly tests to
see if the poly1305 algorithm can be loaded via EVP_MAC_fetch. I've also
move the EVP calls to poly1305.c. To do this I had to extend the
poly1305_auth interface to include another parameter. If the poly1305
MAC is available it will pass in the mac context. Otherwise it will pass
a NULL. Throughput performance, in my test bed is, a bit more than
double in comparison to baseline. Obviously results will vary but there
is a significantly reduction in CPU utilization.
I was told that my mailer (thunderbird) was breaking patches so I've
include the patch both inline and attached.
diff --git a/cipher-chachapoly-libcrypto.c b/cipher-chachapoly-libcrypto.c
index 719f9c843..7dbbe7ee1 100644
--- a/cipher-chachapoly-libcrypto.c
+++ b/cipher-chachapoly-libcrypto.c
@@ -35,8 +35,18 @@
#include "ssherr.h"
#include "cipher-chachapoly.h"
+
+/* using the EVP_MAC interface for poly1305 is significantly
+ * faster than the version bundled with OpenSSH. However,
+ * this interface is only available in OpenSSL 3.0+
+ * -cjr 10/21/2022 */
struct chachapoly_ctx {
EVP_CIPHER_CTX *main_evp, *header_evp;
+#ifdef OPENSSL_HAVE_POLY_EVP
+ EVP_MAC_CTX *poly_ctx;
+#else
+ char *poly_ctx;
+#endif
};
struct chachapoly_ctx *
@@ -57,6 +67,15 @@ chachapoly_new(const u_char *key, u_int keylen)
goto fail;
if (EVP_CIPHER_CTX_iv_length(ctx->header_evp) != 16)
goto fail;
+#ifdef OPENSSL_HAVE_POLY_EVP
+ EVP_MAC *mac = NULL;
+ if ((mac = EVP_MAC_fetch(NULL, "POLY1305", NULL)) == NULL)
+ goto fail;
+ if ((ctx->poly_ctx = EVP_MAC_CTX_new(mac)) == NULL)
+ goto fail;
+#else
+ ctx->poly_ctx = NULL;
+#endif
return ctx;
fail:
chachapoly_free(ctx);
@@ -70,6 +89,9 @@ chachapoly_free(struct chachapoly_ctx *cpctx)
return;
EVP_CIPHER_CTX_free(cpctx->main_evp);
EVP_CIPHER_CTX_free(cpctx->header_evp);
+#ifdef OPENSSL_HAVE_POLY_EVP
+ EVP_MAC_CTX_free(cpctx->poly_ctx);
+#endif
freezero(cpctx, sizeof(*cpctx));
}
@@ -107,8 +129,7 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int
seqnr, u_char *dest,
/* If decrypting, check tag before anything else */
if (!do_encrypt) {
const u_char *tag = src + aadlen + len;
-
- poly1305_auth(expected_tag, src, aadlen + len, poly_key);
+ poly1305_auth(ctx->poly_ctx, expected_tag, src, aadlen + len, poly_key);
if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
r = SSH_ERR_MAC_INVALID;
goto out;
@@ -134,8 +155,8 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int
seqnr, u_char *dest,
/* If encrypting, calculate and append tag */
if (do_encrypt) {
- poly1305_auth(dest + aadlen + len, dest, aadlen + len,
- poly_key);
+ poly1305_auth(ctx->poly_ctx, dest + aadlen + len, dest, aadlen + len,
+ poly_key);
}
r = 0;
out:
diff --git a/cipher-chachapoly.c b/cipher-chachapoly.c
index 716f8d426..136d2d502 100644
--- a/cipher-chachapoly.c
+++ b/cipher-chachapoly.c
@@ -89,7 +89,7 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int
seqnr, u_char *dest,
if (!do_encrypt) {
const u_char *tag = src + aadlen + len;
- poly1305_auth(expected_tag, src, aadlen + len, poly_key);
+ poly1305_auth(NULL, expected_tag, src, aadlen + len, poly_key);
if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
r = SSH_ERR_MAC_INVALID;
goto out;
@@ -109,7 +109,7 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int
seqnr, u_char *dest,
/* If encrypting, calculate and append tag */
if (do_encrypt) {
- poly1305_auth(dest + aadlen + len, dest, aadlen + len,
+ poly1305_auth(NULL, dest + aadlen + len, dest, aadlen + len,
poly_key);
}
r = 0;
diff --git a/configure.ac b/configure.ac
index 8a18f8381..5fe3ae74c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2932,6 +2933,30 @@ if test "x$openssl" = "xyes" ; then
EVP_chacha20 \
])
+ # OpenSSL 3.0 API
+ # Does OpenSSL support the EVP_MAC functions for Poly1305?
+ AC_MSG_CHECKING([whether OpenSSL supports Poly1305 MAC EVP])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <openssl/evp.h>
+ ]], [[
+ EVP_MAC *mac = EVP_MAC_fetch(NULL, "poly1305", NULL);
+ if (mac == NULL)
+ exit(1);
+ ]])],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([OPENSSL_HAVE_POLY_EVP], [1],
+ [Libcrypto supports Poly1305 MAC EVP])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ]
+ )
+
+
if test "x$openssl_engine" = "xyes" ; then
AC_MSG_CHECKING([for OpenSSL ENGINE support])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
diff --git a/poly1305.c b/poly1305.c
index 6fd1fc8cd..53ebff884 100644
--- a/poly1305.c
+++ b/poly1305.c
@@ -13,6 +13,15 @@
#endif
#include "poly1305.h"
+#ifdef OPENSSL_HAVE_POLY_EVP
+void
+poly1305_auth(EVP_MAC_CTX *poly_ctx, unsigned char
out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const
unsigned char key[POLY1305_KEYLEN]) {
+ size_t poly_out_len;
+ EVP_MAC_init(poly_ctx, (const u_char *)key, POLY1305_KEYLEN, NULL);
+ EVP_MAC_update(poly_ctx, m, inlen);
+ EVP_MAC_final(poly_ctx, out, &poly_out_len, (size_t)POLY1305_TAGLEN);
+}
+#else
#define mul32x32_64(a,b) ((uint64_t)(a) * (b))
@@ -31,7 +42,7 @@
} while (0)
void
-poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char
*m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) {
+poly1305_auth(char *unused, unsigned char out[POLY1305_TAGLEN], const
unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) {
uint32_t t0,t1,t2,t3;
uint32_t h0,h1,h2,h3,h4;
uint32_t r0,r1,r2,r3,r4;
@@ -158,3 +169,4 @@ poly1305_donna_finish:
U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32);
U32TO8_LE(&out[12], f3);
}
+#endif /* OPENSSL_HAVE_POLY_EVP */
diff --git a/poly1305.h b/poly1305.h
index f7db5f8d7..db2524b24 100644
--- a/poly1305.h
+++ b/poly1305.h
@@ -13,8 +13,15 @@
#define POLY1305_KEYLEN 32
#define POLY1305_TAGLEN 16
-void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t
inlen,
+#ifdef OPENSSL_HAVE_POLY_EVP
+#include <openssl/evp.h>
+
+void poly1305_auth(EVP_MAC_CTX *poly_key, u_char out[POLY1305_TAGLEN],
const u_char *m, size_t inlen,
+ const u_char key[POLY1305_KEYLEN])
+#else
+void poly1305_auth(char *unused, u_char out[POLY1305_TAGLEN], const
u_char *m, size_t inlen,
const u_char key[POLY1305_KEYLEN])
+#endif
__attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN)))
__attribute__((__bounded__(__buffer__, 2, 3)))
__attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN)));
-------------- next part --------------
diff --git a/cipher-chachapoly-libcrypto.c b/cipher-chachapoly-libcrypto.c
index 719f9c843..7dbbe7ee1 100644
--- a/cipher-chachapoly-libcrypto.c
+++ b/cipher-chachapoly-libcrypto.c
@@ -35,8 +35,18 @@
#include "ssherr.h"
#include "cipher-chachapoly.h"
+
+/* using the EVP_MAC interface for poly1305 is significantly
+ * faster than the version bundled with OpenSSH. However,
+ * this interface is only available in OpenSSL 3.0+
+ * -cjr 10/21/2022 */
struct chachapoly_ctx {
EVP_CIPHER_CTX *main_evp, *header_evp;
+#ifdef OPENSSL_HAVE_POLY_EVP
+ EVP_MAC_CTX *poly_ctx;
+#else
+ char *poly_ctx;
+#endif
};
struct chachapoly_ctx *
@@ -57,6 +67,15 @@ chachapoly_new(const u_char *key, u_int keylen)
goto fail;
if (EVP_CIPHER_CTX_iv_length(ctx->header_evp) != 16)
goto fail;
+#ifdef OPENSSL_HAVE_POLY_EVP
+ EVP_MAC *mac = NULL;
+ if ((mac = EVP_MAC_fetch(NULL, "POLY1305", NULL)) == NULL)
+ goto fail;
+ if ((ctx->poly_ctx = EVP_MAC_CTX_new(mac)) == NULL)
+ goto fail;
+#else
+ ctx->poly_ctx = NULL;
+#endif
return ctx;
fail:
chachapoly_free(ctx);
@@ -70,6 +89,9 @@ chachapoly_free(struct chachapoly_ctx *cpctx)
return;
EVP_CIPHER_CTX_free(cpctx->main_evp);
EVP_CIPHER_CTX_free(cpctx->header_evp);
+#ifdef OPENSSL_HAVE_POLY_EVP
+ EVP_MAC_CTX_free(cpctx->poly_ctx);
+#endif
freezero(cpctx, sizeof(*cpctx));
}
@@ -107,8 +129,7 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
/* If decrypting, check tag before anything else */
if (!do_encrypt) {
const u_char *tag = src + aadlen + len;
-
- poly1305_auth(expected_tag, src, aadlen + len, poly_key);
+ poly1305_auth(ctx->poly_ctx, expected_tag, src, aadlen + len, poly_key);
if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
r = SSH_ERR_MAC_INVALID;
goto out;
@@ -134,8 +155,8 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
/* If encrypting, calculate and append tag */
if (do_encrypt) {
- poly1305_auth(dest + aadlen + len, dest, aadlen + len,
- poly_key);
+ poly1305_auth(ctx->poly_ctx, dest + aadlen + len, dest, aadlen + len,
+ poly_key);
}
r = 0;
out:
diff --git a/cipher-chachapoly.c b/cipher-chachapoly.c
index 716f8d426..136d2d502 100644
--- a/cipher-chachapoly.c
+++ b/cipher-chachapoly.c
@@ -89,7 +89,7 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
if (!do_encrypt) {
const u_char *tag = src + aadlen + len;
- poly1305_auth(expected_tag, src, aadlen + len, poly_key);
+ poly1305_auth(NULL, expected_tag, src, aadlen + len, poly_key);
if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
r = SSH_ERR_MAC_INVALID;
goto out;
@@ -109,7 +109,7 @@ chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest,
/* If encrypting, calculate and append tag */
if (do_encrypt) {
- poly1305_auth(dest + aadlen + len, dest, aadlen + len,
+ poly1305_auth(NULL, dest + aadlen + len, dest, aadlen + len,
poly_key);
}
r = 0;
diff --git a/configure.ac b/configure.ac
index 8a18f8381..5fe3ae74c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2932,6 +2933,30 @@ if test "x$openssl" = "xyes" ; then
EVP_chacha20 \
])
+ # OpenSSL 3.0 API
+ # Does OpenSSL support the EVP_MAC functions for Poly1305?
+ AC_MSG_CHECKING([whether OpenSSL supports Poly1305 MAC EVP])
+ AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <openssl/evp.h>
+ ]], [[
+ EVP_MAC *mac = EVP_MAC_fetch(NULL, "poly1305", NULL);
+ if (mac == NULL)
+ exit(1);
+ ]])],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([OPENSSL_HAVE_POLY_EVP], [1],
+ [Libcrypto supports Poly1305 MAC EVP])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ]
+ )
+
+
if test "x$openssl_engine" = "xyes" ; then
AC_MSG_CHECKING([for OpenSSL ENGINE support])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
diff --git a/poly1305.c b/poly1305.c
index 6fd1fc8cd..53ebff884 100644
--- a/poly1305.c
+++ b/poly1305.c
@@ -13,6 +13,15 @@
#endif
#include "poly1305.h"
+#ifdef OPENSSL_HAVE_POLY_EVP
+void
+poly1305_auth(EVP_MAC_CTX *poly_ctx, unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) {
+ size_t poly_out_len;
+ EVP_MAC_init(poly_ctx, (const u_char *)key, POLY1305_KEYLEN, NULL);
+ EVP_MAC_update(poly_ctx, m, inlen);
+ EVP_MAC_final(poly_ctx, out, &poly_out_len, (size_t)POLY1305_TAGLEN);
+}
+#else
#define mul32x32_64(a,b) ((uint64_t)(a) * (b))
@@ -31,7 +42,7 @@
} while (0)
void
-poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) {
+poly1305_auth(char *unused, unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) {
uint32_t t0,t1,t2,t3;
uint32_t h0,h1,h2,h3,h4;
uint32_t r0,r1,r2,r3,r4;
@@ -158,3 +169,4 @@ poly1305_donna_finish:
U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32);
U32TO8_LE(&out[12], f3);
}
+#endif /* OPENSSL_HAVE_POLY_EVP */
diff --git a/poly1305.h b/poly1305.h
index f7db5f8d7..db2524b24 100644
--- a/poly1305.h
+++ b/poly1305.h
@@ -13,8 +13,15 @@
#define POLY1305_KEYLEN 32
#define POLY1305_TAGLEN 16
-void poly1305_auth(u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen,
+#ifdef OPENSSL_HAVE_POLY_EVP
+#include <openssl/evp.h>
+
+void poly1305_auth(EVP_MAC_CTX *poly_key, u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen,
+ const u_char key[POLY1305_KEYLEN])
+#else
+void poly1305_auth(char *unused, u_char out[POLY1305_TAGLEN], const u_char *m, size_t inlen,
const u_char key[POLY1305_KEYLEN])
+#endif
__attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN)))
__attribute__((__bounded__(__buffer__, 2, 3)))
__attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN)));
More information about the openssh-unix-dev
mailing list