[patch 2/2] use poly1305 from openssl (1.1.1+) when possible

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

 



On 01/16/19 13:21 , Yuriy M. Kaminskiy wrote:
On some cpu's optimized chacha implementation in openssl (1.1.0+) is
notably faster (and on others it is just faster) than generic C
implementation in openssh.

OpenSSL 1.1.1+ also exports "raw" poly1305 primitive, but I
have not tried it yet (it was not in 1.1.0).

And here it is.

Trivial benchmark:
time ssh -c chacha20-poly1305@xxxxxxxxxxx -S none -o Compression=no \
localhost 'dd if=/dev/zero bs=100000 count=10000' >/dev/null
(comparing "user time")

openssh: 7.9p1, self-compiled, based on upstream package from
> debian/unstable, hostkey - ecdsa/p256, pubkey auth key - ecdh/p256

Machine: pretty old amd k8 (SSE2, but no SSSE3/AVX/AESNI)
OS: debian linux stretch, openssl 1.1.0j-1deb9u1
i386: +8%
amd64: +10%

Machine: raspberry pi 3b+ (BCM2837B0, 4-core Cortex-A53 @1.4GHz)
OS: raspbian/stretch

baseline: armhf/raspbian: unpatched ssh-7.9p1: 30.8s

with openssl 1.1.0j-1deb9u1 from raspbian (compiled for armv6 without
neon):
armhf/raspbian: 24.7 seconds, speed: +23%

with openssl 1.1.0j-1deb9u1 from debian/stretch/armhf (compiled for
armv7 with neon autodetection):
armhf: 22.2 seconds, speed: +39%

openssh: 7.9p1, self-compiled, based on upstream package from
debian/unstable, with both chacha20 and poly1305 patches applied, compiled against:

openssl: 1.1.1a, self-compiled, based on upstream package from debian/unstable.

armhf: 12.0 seconds, speed: +155% against original, +85% against chacha20-only version.

Preliminary patches attached (again, tested against 7.9p1, on the
top of chacha20 patch). I relied on presence of EVP_PKEY_POLY1305 for autodetection; it uses openssl-1.1.0 abi, and can runtime-fallback to builtin openssh implementation.
Index: openssh-7.9p1/cipher-chachapoly.c
===================================================================
--- openssh-7.9p1.orig/cipher-chachapoly.c
+++ openssh-7.9p1/cipher-chachapoly.c
@@ -33,6 +33,11 @@ chachapoly_init(struct chachapoly_ctx *c
     const u_char *key, u_int keylen, int do_encrypt)
 {
 	int ret = 0;
+#if defined(WITH_OPENSSL) && defined(EVP_PKEY_POLY1305)
+	static const u_char poly_key[POLY1305_KEYLEN] = "\xc8\xaf\xaa\xc3\x31\xee\x37\x2c\xd6\x08\x2d\xe1\x34\x94\x3b\x17\x47\x10\x13\x0e\x9f\x6f\xea\x8d\x72\x29\x38\x50\xa6\x67\xd8\x6c";
+	u_char poly_tag[POLY1305_TAGLEN];
+	size_t tag_len = POLY1305_TAGLEN;
+#endif
 
 	if (keylen != (32 + 32)) /* 2 x 256 bit keys */
 		return SSH_ERR_INVALID_ARGUMENT;
@@ -59,6 +64,31 @@ chachapoly_init(struct chachapoly_ctx *c
 	chacha_keysetup(&ctx->main_ctx, key, 256);
 	chacha_keysetup(&ctx->header_ctx, key + 32, 256);
 #endif
+#if defined(WITH_OPENSSL) && defined(EVP_PKEY_POLY1305)
+	if (!(ctx->key = EVP_PKEY_new_mac_key(EVP_PKEY_POLY1305, NULL, poly_key, sizeof(poly_key))))
+		goto out;
+	if (!(ctx->mctx = EVP_MD_CTX_new()))
+		goto out;
+	if (EVP_DigestSignInit(ctx->mctx, &ctx->pctx, NULL, NULL, ctx->key) <= 0)
+		goto out;
+	/* Sanity check */
+	if (EVP_DigestSignFinal(ctx->mctx, NULL, &tag_len) <= 0) {
+		ctx->pctx = NULL;
+		goto out; /* pretend openssl/poly1305 is not supported */
+	}
+	if (tag_len != POLY1305_TAGLEN) {
+		ctx->pctx = NULL;
+		goto out;
+	}
+	if (EVP_DigestSignFinal(ctx->mctx, poly_tag, &tag_len) <= 0) {
+		ctx->pctx = NULL;
+		goto out;
+	}
+	if (memcmp(poly_tag, "\x47\x10\x13\x0e\x9f\x6f\xea\x8d\x72\x29\x38\x50\xa6\x67\xd8\x6c", sizeof(poly_tag)) != 0) {
+		ctx->pctx = NULL;
+		goto out;
+	}
+#endif
 out:
 	if (ret != 0)
 		chachapoly_done(ctx);
@@ -111,6 +141,24 @@ chachapoly_crypt(struct chachapoly_ctx *
 	if (!do_encrypt) {
 		const u_char *tag = src + aadlen + len;
 
+#if defined(WITH_OPENSSL) && defined(EVP_PKEY_POLY1305)
+		/* avoid openssl poly1305 setup overhead for short messages */
+		if (aadlen + len >= 512 && ctx->pctx != NULL) {
+			size_t tag_len = POLY1305_TAGLEN;
+			if (EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_MAC_KEY, sizeof(poly_key), (void *)poly_key) <= 0)
+				goto out;
+			if (EVP_DigestSignUpdate(ctx->mctx, src, aadlen + len) <= 0)
+				goto out;
+#if 0
+			if (EVP_DigestSignFinal(ctx->mctx, NULL, &tag_len) <= 0)
+				goto out;
+			if (tag_len != POLY1305_TAGLEN)
+				goto out;
+#endif
+			if (EVP_DigestSignFinal(ctx->mctx, expected_tag, &tag_len) <= 0)
+				goto out;
+		} else
+#endif
 		poly1305_auth(expected_tag, src, aadlen + len, poly_key);
 		if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
 			r = SSH_ERR_MAC_INVALID;
@@ -146,6 +194,25 @@ chachapoly_crypt(struct chachapoly_ctx *
 
 	/* If encrypting, calculate and append tag */
 	if (do_encrypt) {
+#if defined(WITH_OPENSSL) && defined(EVP_PKEY_POLY1305)
+		/* avoid openssl poly1305 setup overhead for short messages */
+		if (aadlen + len >= 512 && ctx->pctx != NULL) {
+			size_t tag_len = POLY1305_TAGLEN;
+
+			if (EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_MAC_KEY, sizeof(poly_key), (void *)poly_key) <= 0)
+				goto out;
+			if (EVP_DigestSignUpdate(ctx->mctx, dest, aadlen + len) <= 0)
+				goto out;
+#if 0
+			if (EVP_DigestSignFinal(ctx->mctx, NULL, &tag_len) <= 0)
+				goto out;
+			if (tag_len != POLY1305_TAGLEN)
+				goto out;
+#endif
+			if (EVP_DigestSignFinal(ctx->mctx, dest + aadlen + len, &tag_len) <= 0)
+				goto out;
+		} else
+#endif
 		poly1305_auth(dest + aadlen + len, dest, aadlen + len,
 		    poly_key);
 	}
@@ -183,6 +249,11 @@ chachapoly_get_length(struct chachapoly_
 }
 
 int	chachapoly_done(struct chachapoly_ctx *cpctx) {
+#if defined(WITH_OPENSSL) && defined(EVP_PKEY_POLY1305)
+	/* cpctx->pctx should not be freed */
+	EVP_MD_CTX_free(cpctx->mctx);
+	EVP_PKEY_free(cpctx->key);
+#endif
 #if defined(WITH_OPENSSL) && defined(HAVE_EVP_CHACHA20)
 	EVP_CIPHER_CTX_free(cpctx->main_evp);
 	EVP_CIPHER_CTX_free(cpctx->header_evp);
Index: openssh-7.9p1/cipher-chachapoly.h
===================================================================
--- openssh-7.9p1.orig/cipher-chachapoly.h
+++ openssh-7.9p1/cipher-chachapoly.h
@@ -34,6 +34,11 @@ struct chachapoly_ctx {
 #else
 	struct chacha_ctx main_ctx, header_ctx;
 #endif
+#if defined(WITH_OPENSSL) && defined(EVP_PKEY_POLY1305)
+	EVP_MD_CTX *mctx;
+	EVP_PKEY_CTX *pctx;
+	EVP_PKEY *key;
+#endif
 };
 
 int	chachapoly_init(struct chachapoly_ctx *cpctx,
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@xxxxxxxxxxx
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux