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