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)));