diff --git a/src/crypt.c b/src/crypt.c index 5cf7134..1d19bab 100644 --- a/src/crypt.c +++ b/src/crypt.c @@ -61,15 +61,66 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = { }; #endif +#define MAKE_INIT(name, cipher) \ + static int name (LIBSSH2_SESSION *session, \ + unsigned char *iv, int *free_iv, \ + unsigned char *secret, int *free_secret, \ + int encrypt, void **abstract) \ + { \ + EVP_CIPHER_CTX *ctx = LIBSSH2_ALLOC(session, sizeof(EVP_CIPHER_CTX)); \ + if (!ctx) \ + return -1; \ + EVP_CIPHER_CTX_init(ctx); \ + EVP_CipherInit(ctx, cipher, secret, iv, encrypt); \ + *abstract = ctx; \ + *free_iv = 1; \ + *free_secret = 1; \ + return 0; \ + } + +MAKE_INIT(aes256_init, EVP_aes_256_cbc()) +MAKE_INIT(aes192_init, EVP_aes_192_cbc()) +MAKE_INIT(aes128_init, EVP_aes_128_cbc()) +MAKE_INIT(blowfish_init, EVP_bf_cbc()) +MAKE_INIT(arcfour_init, EVP_rc4()) +MAKE_INIT(cast128_init, EVP_cast5_cbc()) +MAKE_INIT(des3_init, EVP_des_ede3_cbc()) + +int crypt(LIBSSH2_SESSION *session, unsigned char *block, void **abstract) +{ + EVP_CIPHER_CTX *ctx = *(EVP_CIPHER_CTX **)abstract; + int blocksize = ctx->cipher->block_size; + unsigned char buf[EVP_MAX_BLOCK_LENGTH]; + int ret; + if (blocksize == 1) /* Hack for arcfour. */ + blocksize = 8; + ret = EVP_Cipher(ctx, buf, block, blocksize); + if (ret == 1) + memcpy(block, buf, blocksize); + return ret == 1 ? 0 : 1; +} + +int dtor(LIBSSH2_SESSION *session, void **abstract) +{ + EVP_CIPHER_CTX **ctx = (EVP_CIPHER_CTX **)abstract; + if (ctx && *ctx) + { + EVP_CIPHER_CTX_cleanup(*ctx); + LIBSSH2_FREE(session, *ctx); + *abstract = NULL; + } + return 0; +} + static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = { "3des-cbc", 8, /* blocksize */ 8, /* initial value length */ 24, /* secret length */ - LIBSSH2_CRYPT_METHOD_FLAG_EVP, - NULL, - (void*)EVP_des_ede3_cbc, - NULL, + 0, /* flags */ + &des3_init, + &crypt, + &dtor }; #if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES) @@ -78,10 +129,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = { 16, /* blocksize */ 16, /* initial value length */ 16, /* secret length -- 16*8 == 128bit */ - LIBSSH2_CRYPT_METHOD_FLAG_EVP, - NULL, - (void*)EVP_aes_128_cbc, - NULL, + 0, /* flags */ + &aes128_init, + &crypt, + &dtor }; static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = { @@ -89,10 +140,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = { 16, /* blocksize */ 16, /* initial value length */ 24, /* secret length -- 24*8 == 192bit */ - LIBSSH2_CRYPT_METHOD_FLAG_EVP, - NULL, - (void*)EVP_aes_192_cbc, - NULL, + 0, /* flags */ + &aes192_init, + &crypt, + &dtor }; static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = { @@ -100,10 +151,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = { 16, /* blocksize */ 16, /* initial value length */ 32, /* secret length -- 32*8 == 256bit */ - LIBSSH2_CRYPT_METHOD_FLAG_EVP, - NULL, - (void*)EVP_aes_256_cbc, - NULL, + 0, /* flags */ + &aes256_init, + &crypt, + &dtor }; /* rijndael-cbc@lysator.liu.se == aes256-cbc */ @@ -112,10 +163,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_rijndael_cbc_lysator_liu_se = { 16, /* blocksize */ 16, /* initial value length */ 32, /* secret length -- 32*8 == 256bit */ - LIBSSH2_CRYPT_METHOD_FLAG_EVP, - NULL, - (void*)EVP_aes_256_cbc, - NULL, + 0, /* flags */ + &aes256_init, + &crypt, + &dtor }; #endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)*/ @@ -125,10 +176,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ - LIBSSH2_CRYPT_METHOD_FLAG_EVP, - NULL, - (void*)EVP_bf_cbc, - NULL, + 0, /* flags */ + &blowfish_init, + &crypt, + &dtor }; #endif /* ! OPENSSL_NO_BLOWFISH */ @@ -138,10 +189,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ - LIBSSH2_CRYPT_METHOD_FLAG_EVP, - NULL, - (void*)EVP_cast5_cbc, - NULL, + 0, /* flags */ + &cast128_init, + &crypt, + &dtor }; #endif /* ! OPENSSL_NO_CAST */ @@ -151,10 +202,10 @@ static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ - LIBSSH2_CRYPT_METHOD_FLAG_EVP, - NULL, - (void*)EVP_rc4, - NULL, + 0, /* flags */ + &arcfour_init, + &crypt, + &dtor }; #endif /* ! OPENSSL_NO_RC4 */ diff --git a/src/kex.c b/src/kex.c index 3a15a84..72810b7 100644 --- a/src/kex.c +++ b/src/kex.c @@ -38,7 +38,6 @@ #include "libssh2_priv.h" #include #include -#include #include /* TODO: Switch this to an inline and handle alloc() failures */ @@ -331,45 +330,23 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S #endif } - /* Calculate IV/Secret/Key for each direction */ - if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { - if (session->local.crypt_abstract) { - EVP_CIPHER_CTX_cleanup(session->local.crypt_abstract); - LIBSSH2_FREE(session, session->local.crypt_abstract); - session->local.crypt_abstract = NULL; - } - } else { - if (session->local.crypt->dtor) { - /* Cleanup any existing cipher */ - session->local.crypt->dtor(session, &session->local.crypt_abstract); - } + /* Cleanup any existing cipher */ + if (session->local.crypt->dtor) { + session->local.crypt->dtor(session, &session->local.crypt_abstract); } - if (session->local.crypt->init || (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP)) { + /* Calculate IV/Secret/Key for each direction */ + if (session->local.crypt->init) { unsigned char *iv = NULL, *secret = NULL; int free_iv = 0, free_secret = 0; LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->local.crypt->iv_len, "A"); LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->local.crypt->secret_len, "C"); - if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { - EVP_CIPHER *(*get_cipher)(void) = (void*)session->local.crypt->crypt; - EVP_CIPHER *cipher = get_cipher(); - EVP_CIPHER_CTX *ctx; - - ctx = LIBSSH2_ALLOC(session, sizeof(EVP_CIPHER_CTX)); - if (!ctx) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = -1; - goto clean_exit; - } - EVP_CIPHER_CTX_init(ctx); - EVP_CipherInit(ctx, cipher, secret, iv, 1); - session->local.crypt_abstract = ctx; - free_iv = 1; - free_secret = 1; - } else { - session->local.crypt->init(session, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract); + if (session->local.crypt->init(session, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract)) { + LIBSSH2_FREE(session, iv); + LIBSSH2_FREE(session, secret); + ret = -1; + goto clean_exit; } if (free_iv) { @@ -386,44 +363,22 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S _libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server IV and Key calculated"); #endif - if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { - if (session->remote.crypt_abstract) { - EVP_CIPHER_CTX_cleanup(session->remote.crypt_abstract); - LIBSSH2_FREE(session, session->remote.crypt_abstract); - session->remote.crypt_abstract = NULL; - } - } else { - if (session->remote.crypt->dtor) { - /* Cleanup any existing cipher */ - session->remote.crypt->dtor(session, &session->remote.crypt_abstract); - } + if (session->remote.crypt->dtor) { + /* Cleanup any existing cipher */ + session->remote.crypt->dtor(session, &session->remote.crypt_abstract); } - if (session->remote.crypt->init || (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP)) { + if (session->remote.crypt->init) { unsigned char *iv = NULL, *secret = NULL; int free_iv = 0, free_secret = 0; LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->remote.crypt->iv_len, "B"); LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->remote.crypt->secret_len, "D"); - if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { - EVP_CIPHER *(*get_cipher)(void) = (void*)session->remote.crypt->crypt; - EVP_CIPHER *cipher = get_cipher(); - EVP_CIPHER_CTX *ctx; - - ctx = LIBSSH2_ALLOC(session, sizeof(EVP_CIPHER_CTX)); - if (!ctx) { - LIBSSH2_FREE(session, iv); - LIBSSH2_FREE(session, secret); - ret = -1; - goto clean_exit; - } - EVP_CIPHER_CTX_init(ctx); - EVP_CipherInit(ctx, cipher, secret, iv, 0); - session->remote.crypt_abstract = ctx; - free_iv = 1; - free_secret = 1; - } else { - session->remote.crypt->init(session, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract); + if (session->remote.crypt->init(session, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract)) { + LIBSSH2_FREE(session, iv); + LIBSSH2_FREE(session, secret); + ret = -1; + goto clean_exit; } if (free_iv) { diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h index ff852a6..9edc075 100644 --- a/src/libssh2_priv.h +++ b/src/libssh2_priv.h @@ -282,12 +282,6 @@ struct _LIBSSH2_HOSTKEY_METHOD { int (*dtor)(LIBSSH2_SESSION *session, void **abstract); }; -/* When FLAG_EVP is set, crypt contains a pointer to an EVP_CIPHER generator and init and dtor are ignored - * Yes, I know it's a hack. - */ - -#define LIBSSH2_CRYPT_METHOD_FLAG_EVP 0x0001 - struct _LIBSSH2_CRYPT_METHOD { char *name; diff --git a/src/packet.c b/src/packet.c index d6ef2a6..c829b68 100644 --- a/src/packet.c +++ b/src/packet.c @@ -41,7 +41,6 @@ #ifndef WIN32 #include #endif -#include #include /* Needed for struct iovec on some platforms */ @@ -754,9 +753,6 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block) int macstate; int free_payload = 1; - /* Safely ignored in CUSTOM cipher mode */ - EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->remote.crypt_abstract; - /* Note: If we add any cipher with a blocksize less than 6 we'll need to get more creative with this * For now, all blocksize sizes are 8+ */ @@ -780,14 +776,9 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block) return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1; } - if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { - EVP_Cipher(ctx, block + blocksize, block, blocksize); - memcpy(block, block + blocksize, blocksize); - } else { - if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) { - libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0); - return -1; - } + if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) { + libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0); + return -1; } packet_len = libssh2_ntohu32(block); @@ -838,17 +829,12 @@ int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block) while (s < p) { memcpy(block, s, blocksize); - if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { - EVP_Cipher(ctx, block + blocksize, block, blocksize); - memcpy(s, block + blocksize, blocksize); - } else { - if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) { - libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0); - LIBSSH2_FREE(session, payload); - return -1; - } - memcpy(s, block, blocksize); + if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) { + libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0); + LIBSSH2_FREE(session, payload); + return -1; } + memcpy(s, block, blocksize); s += blocksize; } @@ -1225,9 +1211,6 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned unsigned char *encbuf, *s; int ret, size, written = 0; - /* Safely ignored in CUSTOM cipher mode */ - EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->local.crypt_abstract; - /* include packet_length(4) itself and room for the hash at the end */ encbuf = LIBSSH2_ALLOC(session, 4 + packet_length + session->local.mac->mac_len); if (!encbuf) { @@ -1251,12 +1234,7 @@ int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned /* Encrypt data */ for(s = encbuf; (s - encbuf) < (4 + packet_length) ; s += session->local.crypt->blocksize) { - if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { - EVP_Cipher(ctx, buf, s, session->local.crypt->blocksize); - memcpy(s, buf, session->local.crypt->blocksize); - } else { - session->local.crypt->crypt(session, s, &session->local.crypt_abstract); - } + session->local.crypt->crypt(session, s, &session->local.crypt_abstract); } session->local.seqno++; diff --git a/src/session.c b/src/session.c index 8ec39e7..0911883 100644 --- a/src/session.c +++ b/src/session.c @@ -410,16 +410,8 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session) /* Client to Server */ /* crypt */ - if (session->local.crypt) { - if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { - if (session->local.crypt_abstract) { - EVP_CIPHER_CTX_cleanup(session->local.crypt_abstract); - LIBSSH2_FREE(session, session->local.crypt_abstract); - session->local.crypt_abstract = NULL; - } - } else if (session->local.crypt->dtor) { - session->local.crypt->dtor(session, &session->local.crypt_abstract); - } + if (session->local.crypt && session->local.crypt->dtor) { + session->local.crypt->dtor(session, &session->local.crypt_abstract); } /* comp */ if (session->local.comp && session->local.comp->dtor) { @@ -432,16 +424,8 @@ LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session) /* Server to Client */ /* crypt */ - if (session->remote.crypt) { - if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) { - if (session->remote.crypt_abstract) { - EVP_CIPHER_CTX_cleanup(session->remote.crypt_abstract); - LIBSSH2_FREE(session, session->remote.crypt_abstract); - session->remote.crypt_abstract = NULL; - } - } else if (session->remote.crypt->dtor) { - session->remote.crypt->dtor(session, &session->remote.crypt_abstract); - } + if (session->remote.crypt && session->remote.crypt->dtor) { + session->remote.crypt->dtor(session, &session->remote.crypt_abstract); } /* comp */ if (session->remote.comp && session->remote.comp->dtor) {