diff options
-rw-r--r-- | ConfigureChecks.cmake | 9 | ||||
-rw-r--r-- | config.h.cmake | 6 | ||||
-rw-r--r-- | include/libssh/crypto.h | 1 | ||||
-rw-r--r-- | src/libcrypto.c | 92 |
4 files changed, 108 insertions, 0 deletions
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake index c0326c20..0d068b9c 100644 --- a/ConfigureChecks.cmake +++ b/ConfigureChecks.cmake @@ -89,6 +89,15 @@ if (OPENSSL_FOUND) set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) check_include_file(openssl/ecdsa.h HAVE_OPENSSL_ECDSA_H) + + set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) + set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY}) + check_symbol_exists(EVP_aes_128_ctr openssl/evp.h HAVE_OPENSSL_EVP_AES_CTR) + + set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) + set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY}) + check_symbol_exists(EVP_aes_128_cbc openssl/evp.h HAVE_OPENSSL_EVP_AES_CBC) + endif() if (CMAKE_HAVE_PTHREAD_H) diff --git a/config.h.cmake b/config.h.cmake index 0685f10c..8d9bfd21 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -76,6 +76,12 @@ /*************************** FUNCTIONS ***************************/ +/* Define to 1 if you have the `EVP_aes128_ctr' function. */ +#cmakedefine HAVE_OPENSSL_EVP_AES_CTR 1 + +/* Define to 1 if you have the `EVP_aes128_cbc' function. */ +#cmakedefine HAVE_OPENSSL_EVP_AES_CBC 1 + /* Define to 1 if you have the `snprintf' function. */ #cmakedefine HAVE_SNPRINTF 1 diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h index eed93710..e370c748 100644 --- a/include/libssh/crypto.h +++ b/include/libssh/crypto.h @@ -124,6 +124,7 @@ struct ssh_cipher_struct { gcry_cipher_hd_t *key; #elif defined HAVE_LIBCRYPTO struct ssh_3des_key_schedule *des3_key; + struct ssh_aes_key_schedule *aes_key; const EVP_CIPHER *cipher; EVP_CIPHER_CTX ctx; #endif diff --git a/src/libcrypto.c b/src/libcrypto.c index 4524628b..bf75f261 100644 --- a/src/libcrypto.c +++ b/src/libcrypto.c @@ -438,6 +438,7 @@ static void evp_cipher_init(struct ssh_cipher_struct *cipher) { case SSH_AES256_CBC: cipher->cipher = EVP_aes_256_cbc(); break; +#ifdef HAVE_OPENSSL_EVP_AES_CTR case SSH_AES128_CTR: cipher->cipher = EVP_aes_128_ctr(); break; @@ -447,6 +448,13 @@ static void evp_cipher_init(struct ssh_cipher_struct *cipher) { case SSH_AES256_CTR: cipher->cipher = EVP_aes_256_ctr(); break; +#else + case SSH_AES128_CTR: + case SSH_AES192_CTR: + case SSH_AES256_CTR: + SSH_LOG(SSH_LOG_WARNING, "This cipher is not available in evp_cipher_init"); + break; +#endif case SSH_3DES_CBC: cipher->cipher = EVP_des_ede3_cbc(); break; @@ -540,6 +548,54 @@ static void evp_cipher_cleanup(struct ssh_cipher_struct *cipher) { EVP_CIPHER_CTX_cleanup(&cipher->ctx); } +#ifndef HAVE_EVP_AES_CTR +/* Some OS (osx, OpenIndiana, ...) have no support for CTR ciphers in EVP_aes */ + +struct ssh_aes_key_schedule { + AES_KEY key; + uint8_t IV[AES_BLOCK_SIZE]; +}; + +static int aes_ctr_set_key(struct ssh_cipher_struct *cipher, void *key, + void *IV) { + int rc; + + if (cipher->aes_key == NULL) { + cipher->aes_key = malloc(sizeof (struct ssh_aes_key_schedule)); + } + if (cipher->aes_key == NULL) { + return SSH_ERROR; + } + ZERO_STRUCTP(cipher->aes_key); + /* CTR doesn't need a decryption key */ + rc = AES_set_encrypt_key(key, cipher->keysize, &cipher->aes_key->key); + if (rc < 0) { + SAFE_FREE(cipher->aes_key); + return SSH_ERROR; + } + memcpy(cipher->aes_key->IV, IV, AES_BLOCK_SIZE); + return SSH_OK; +} + +static void aes_ctr_encrypt(struct ssh_cipher_struct *cipher, void *in, void *out, + unsigned long len) { + unsigned char tmp_buffer[AES_BLOCK_SIZE]; + unsigned int num=0; + /* Some things are special with ctr128 : + * In this case, tmp_buffer is not being used, because it is used to store temporary data + * when an encryption is made on lengths that are not multiple of blocksize. + * Same for num, which is being used to store the current offset in blocksize in CTR + * function. + */ + AES_ctr128_encrypt(in, out, len, &cipher->aes_key->key, cipher->aes_key->IV, tmp_buffer, &num); +} + +static void aes_ctr_cleanup(struct ssh_cipher_struct *cipher){ + BURN_BUFFER(cipher->aes_key, sizeof(*cipher->aes_key)); + SAFE_FREE(cipher->aes_key); +} + +#endif /* HAVE_EVP_AES_CTR */ #ifdef HAS_DES typedef uint8_t des_iv_t[8]; @@ -647,6 +703,7 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { /* OpenSSL until 0.9.7c has a broken AES_ctr128_encrypt implementation which * increments the counter from 2^64 instead of 1. It's better not to use it */ +#ifdef HAVE_OPENSSL_EVP_AES_CTR { .name = "aes128-ctr", .blocksize = 16, @@ -680,6 +737,41 @@ static struct ssh_cipher_struct ssh_ciphertab[] = { .decrypt = evp_cipher_decrypt, .cleanup = evp_cipher_cleanup }, +#else /* HAVE_OPENSSL_EVP_AES_CTR */ + { + .name = "aes128-ctr", + .blocksize = 16, + .ciphertype = SSH_AES128_CTR, + .keysize = 128, + .set_encrypt_key = aes_ctr_set_key, + .set_decrypt_key = aes_ctr_set_key, + .encrypt = aes_ctr_encrypt, + .decrypt = aes_ctr_encrypt, + .cleanup = aes_ctr_cleanup + }, + { + .name = "aes192-ctr", + .blocksize = 16, + .ciphertype = SSH_AES192_CTR, + .keysize = 192, + .set_encrypt_key = aes_ctr_set_key, + .set_decrypt_key = aes_ctr_set_key, + .encrypt = aes_ctr_encrypt, + .decrypt = aes_ctr_encrypt, + .cleanup = aes_ctr_cleanup + }, + { + .name = "aes256-ctr", + .blocksize = 16, + .ciphertype = SSH_AES256_CTR, + .keysize = 256, + .set_encrypt_key = aes_ctr_set_key, + .set_decrypt_key = aes_ctr_set_key, + .encrypt = aes_ctr_encrypt, + .decrypt = aes_ctr_encrypt, + .cleanup = aes_ctr_cleanup + }, +#endif /* HAVE_OPENSSL_EVP_AES_CTR */ #endif /* BROKEN_AES_CTR */ { .name = "aes128-cbc", |