Hi,
This diff needs testing, particularly on systems that support hardware
acceleration of AES via the OpenSSL EVP layer (e.g. Intel Core i7).
It uses OpenSSL's EVP AES API rather than the lower-level one and should
give an opportunity for the acceleration to work.
A useful benchmark would be
dd if=/dev/arandom bs=100000 count=1000 | time ssh localhost "cat > /dev/null"
before and after (you will need passwordless authentication setup so
as not to stall at the password prompt)
Index: cipher-ctr.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/cipher-ctr.c,v
retrieving revision 1.11
diff -u -p -r1.11 cipher-ctr.c
--- cipher-ctr.c 1 Oct 2010 23:05:32 -0000 1.11
+++ cipher-ctr.c 9 Sep 2011 00:49:18 -0000
@@ -30,7 +30,7 @@ void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, in
struct ssh_aes_ctr_ctx
{
- AES_KEY aes_ctx;
+ EVP_CIPHER_CTX aes_evp_ctx;
u_char aes_counter[AES_BLOCK_SIZE];
};
@@ -64,7 +64,9 @@ ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char
while ((len--) > 0) {
if (n == 0) {
- AES_encrypt(c->aes_counter, buf, &c->aes_ctx);
+ if (EVP_Cipher(&c->aes_evp_ctx, buf, c->aes_counter,
+ AES_BLOCK_SIZE) == 0)
+ fatal("%s: EVP_Cipher failed", __func__);
ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE);
}
*(dest++) = *(src++) ^ buf[n];
@@ -83,9 +85,26 @@ ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, co
c = xmalloc(sizeof(*c));
EVP_CIPHER_CTX_set_app_data(ctx, c);
}
- if (key != NULL)
- AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
- &c->aes_ctx);
+ if (key != NULL) {
+ const EVP_CIPHER *cipher = NULL;
+
+ switch (EVP_CIPHER_CTX_key_length(ctx) * 8) {
+ case 128:
+ cipher = EVP_aes_128_ecb();
+ break;
+ case 192:
+ cipher = EVP_aes_192_ecb();
+ break;
+ case 256:
+ cipher = EVP_aes_256_ecb();
+ break;
+ default:
+ fatal("%s: invalid key length %d", __func__,
+ EVP_CIPHER_CTX_key_length(ctx) * 8);
+ }
+ if (EVP_CipherInit(&c->aes_evp_ctx, cipher, key, NULL, 1) == 0)
+ fatal("%s: EVP_CipherInit failed", __func__);
+ }
if (iv != NULL)
memcpy(c->aes_counter, iv, AES_BLOCK_SIZE);
return (1);
@@ -97,6 +116,8 @@ ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
struct ssh_aes_ctr_ctx *c;
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
+ if (EVP_CIPHER_CTX_cleanup(&c->aes_evp_ctx) == 0)
+ error("%s: EVP_CIPHER_CTX_cleanup failed", __func__);
memset(c, 0, sizeof(*c));
xfree(c);
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
Index: umac.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/umac.c,v
retrieving revision 1.3
diff -u -p -r1.3 umac.c
--- umac.c 12 May 2008 20:52:20 -0000 1.3
+++ umac.c 9 Sep 2011 00:49:18 -0000
@@ -65,9 +65,11 @@
#include <sys/types.h>
#include <sys/endian.h>
+#include <stdarg.h>
#include "xmalloc.h"
#include "umac.h"
+#include "log.h"
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
@@ -167,12 +169,30 @@ static void STORE_UINT32_REVERSED(void *
#define AES_BLOCK_LEN 16
/* OpenSSL's AES */
-#include <openssl/aes.h>
-typedef AES_KEY aes_int_key[1];
-#define aes_encryption(in,out,int_key) \
- AES_encrypt((u_char *)(in),(u_char *)(out),(AES_KEY *)int_key)
-#define aes_key_setup(key,int_key) \
- AES_set_encrypt_key((u_char *)(key),UMAC_KEY_LEN*8,int_key)
+#include <openssl/evp.h>
+typedef EVP_CIPHER_CTX aes_int_key[1];
+
+static void
+aes_encryption(u_char *in, u_char *out, aes_int_key int_key)
+{
+ if (EVP_Cipher((EVP_CIPHER_CTX *)int_key, out, in, AES_BLOCK_LEN) == 0)
+ fatal("%s: EVP_Cipher failed", __func__);
+}
+
+static void
+aes_key_setup(u_char *key, aes_int_key int_key)
+{
+ if (EVP_CipherInit((EVP_CIPHER_CTX *)int_key, EVP_aes_128_ecb(),
+ key, NULL, 1) == 0)
+ fatal("%s: EVP_CipherInit failed", __func__);
+}
+
+static void
+aes_key_cleanup(aes_int_key int_key)
+{
+ if (EVP_CIPHER_CTX_cleanup((EVP_CIPHER_CTX *)int_key) == 0)
+ error("%s: EVP_CIPHER_CTX_cleanup failed", __func__);
+}
/* The user-supplied UMAC key is stretched using AES in a counter
* mode to supply all random bits needed by UMAC. The kdf function takes
@@ -228,6 +248,11 @@ static void pdf_init(pdf_ctx *pc, aes_in
aes_encryption(pc->nonce, pc->cache, pc->prf_key);
}
+static void pdf_cleanup(pdf_ctx *pc)
+{
+ aes_key_cleanup(pc->prf_key);
+}
+
static void pdf_gen_xor(pdf_ctx *pc, UINT8 nonce[8], UINT8 buf[8])
{
/* 'ndx' indicates that we'll be using the 0th or 1st eight bytes
@@ -1194,9 +1219,13 @@ int umac_reset(struct umac_ctx *ctx)
int umac_delete(struct umac_ctx *ctx)
/* Deallocate the ctx structure */
{
+ struct umac_ctx *octx;
if (ctx) {
+ pdf_cleanup(&ctx->pdf);
+ octx = ctx;
if (ALLOC_BOUNDARY)
ctx = (struct umac_ctx *)ctx->free_ptr;
+ bzero(octx, sizeof(*octx));
xfree(ctx);
}
return (1);
@@ -1224,6 +1253,7 @@ struct umac_ctx *umac_new(u_char key[])
aes_key_setup(key,prf_key);
pdf_init(&ctx->pdf, prf_key);
uhash_init(&ctx->hash, prf_key);
+ aes_key_cleanup(prf_key);
}
return (ctx);