[PATCH] Use EVP_MAC interface for Poly1305 if supported.

Chris Rapier rapier at psc.edu
Wed Oct 26 05:20:39 AEDT 2022


Newest version of the patch. This includes creating a 
OPENSSL_HAVE_EVP_MAC test in configure and moving the EVP_MAC_functions 
to poly1305.c. There are still 3 ifdefs in cipher-chachapoly_libcrypto.c 
but none in chachapoly_crypt(). I did have to extend the parameters on 
poly1305_auth to include the poly evp context.

diff --git a/cipher-chachapoly-libcrypto.c b/cipher-chachapoly-libcrypto.c
index 719f9c843..52decd427 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_EVP_MAC
+       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_EVP_MAC
+       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_EVP_MAC
+       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/configure.ac b/configure.ac
index 8a18f8381..8493f4bc3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2932,6 +2932,11 @@ if test "x$openssl" = "xyes" ; then
                 EVP_chacha20 \
         ])

+       # OpenSSL 3.0 API
+       # Does OpenSSL support the EVP_MAC functions?
+       AC_CHECK_FUNCS(EVP_MAC_fetch,
+               [AC_DEFINE([OPENSSL_HAVE_EVP_MAC], [1], [EVP_MAC 
Functions])])
+
         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..edc2002eb 100644
--- a/poly1305.c
+++ b/poly1305.c
@@ -14,6 +14,16 @@

  #include "poly1305.h"

+#ifdef OPENSSL_HAVE_EVP_MAC
+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))

  #define U8TO32_LE(p) \
@@ -31,7 +41,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 +168,4 @@ poly1305_donna_finish:
         U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32);
         U32TO8_LE(&out[12], f3);
  }
+#endif /* OPENSSL_HAVE_EVP_MAC */
diff --git a/poly1305.h b/poly1305.h
index f7db5f8d7..b4146f92d 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_EVP_MAC
+#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)));

On 10/24/22 5:08 PM, Chris Rapier wrote:
> 
> 
> On 10/24/22 4:23 PM, Darren Tucker wrote:
>> On Tue, 25 Oct 2022 at 06:23, Chris Rapier <rapier at psc.edu> wrote:
>>
>>> +#if OPENSSL_VERSION_NUMBER >= 0x30000000UL
>>
>> As mentioned by Dmitry Belyavskiy upthread, since this depends on
>> EVP_MAC_fetch() this should probably be checked by configure instead
>> and put inside an ifdef HAVE_EVP_MAC_FETCH.  I'm also wondering if the
>> additional OpenSSL specific code belongs in the poly1305_auth function
>> in cipher-chachapoly-libcrypto.c.
> 
> Okay, I think I'm understanding. We'd still have the #ifdefs in the code 
> but we'd be moving away from actually checking a specific version string 
> to seeing if the function itself exists. I'll work on that tomorrow.
> 
> As for putting it in the poly_auth function itself. I'm concerned that 
> making the parameters work would be difficult and possible confusing if 
> we maintained the current ones for poly1305_auth(). As far as I can 
> figure we'd need 5 parameters and to set ctx->poly_ctx explictly to null 
> in is HAVE_EVP_MAC_FETCH is false. Thoughts?
> 
>>> +       size_t poly_out_len;
>>> +#endif
>>
>> Since poly_out_len is only ever used inside the  "if (!do_encrypt)"
>> block below, you could move this declaration inside the existing ifdef
>> inside that block and reduce this diff by one hunk.
> 
> Good point. I've made that change. I'm going to think about a few more 
> things and work out the configure before I submit a new patch.
> 
> Chris


More information about the openssh-unix-dev mailing list