1
1

libmbedtls: Support OpenSSH-compatible AES-GCM ciphers using mbedTLS

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Этот коммит содержится в:
Jakub Jelen 2018-10-04 15:21:36 +02:00 коммит произвёл Andreas Schneider
родитель a2120e168b
Коммит 72bd2fe197
6 изменённых файлов: 188 добавлений и 14 удалений

Просмотреть файл

@ -29,6 +29,8 @@
#ifdef HAVE_LIBGCRYPT
#include <gcrypt.h>
#elif defined(HAVE_LIBMBEDCRYPTO)
#include <mbedtls/gcm.h>
#endif
#include "libssh/wrapper.h"
@ -152,6 +154,10 @@ struct ssh_cipher_struct {
mbedtls_cipher_context_t encrypt_ctx;
mbedtls_cipher_context_t decrypt_ctx;
mbedtls_cipher_type_t type;
#ifdef MBEDTLS_GCM_C
mbedtls_gcm_context gcm_ctx;
unsigned char last_iv[AES_GCM_IVLEN];
#endif /* MBEDTLS_GCM_C */
#endif
struct chacha20_poly1305_keysched *chacha20_schedule;
unsigned int keysize; /* bytes of key used. != keylen */

Просмотреть файл

@ -81,4 +81,6 @@ int ssh_timeout_update(struct ssh_timestamp *ts, int timeout);
int ssh_match_group(const char *group, const char *object);
void uint64_inc(unsigned char *counter);
#endif /* MISC_H_ */

Просмотреть файл

@ -48,7 +48,13 @@
#elif defined HAVE_LIBMBEDCRYPTO
# define BLOWFISH "blowfish-cbc,"
# define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
# ifdef MBEDTLS_GCM_C
# define GCM "aes256-gcm@openssh.com,aes128-gcm@openssh.com,"
# else
# define GCM ""
# endif /* MBEDTLS_GCM_C */
# define AES GCM "aes256-ctr,aes192-ctr,aes128-ctr," \
"aes256-cbc,aes192-cbc,aes128-cbc,"
# define DES "3des-cbc"
# define DES_SUPPORTED "3des-cbc"

Просмотреть файл

@ -31,6 +31,7 @@
#include "libssh/crypto.h"
#include "libssh/wrapper.h"
#include "libssh/string.h"
#include "libssh/misc.h"
#ifdef HAVE_LIBGCRYPT
#include <gcrypt.h>
@ -429,19 +430,6 @@ aes_aead_get_length(struct ssh_cipher_struct *cipher,
return SSH_OK;
}
/* Increment 64b integer in network byte order */
static void
uint64_inc(unsigned char *counter)
{
int i;
for (i = 7; i >= 0; i--) {
counter[i]++;
if (counter[i])
return;
}
}
static void
aes_gcm_encrypt(struct ssh_cipher_struct *cipher,
void *in,

Просмотреть файл

@ -26,9 +26,13 @@
#include "libssh/wrapper.h"
#include "libssh/crypto.h"
#include "libssh/priv.h"
#include "libssh/misc.h"
#ifdef HAVE_LIBMBEDCRYPTO
#include <mbedtls/md.h>
#ifdef MBEDTLS_GCM_C
#include <mbedtls/gcm.h>
#endif /* MBEDTLS_GCM_C */
static mbedtls_entropy_context ssh_mbedtls_entropy;
static mbedtls_ctr_drbg_context ssh_mbedtls_ctr_drbg;
@ -616,6 +620,37 @@ error:
return SSH_ERROR;
}
#ifdef MBEDTLS_GCM_C
static int
cipher_set_key_gcm(struct ssh_cipher_struct *cipher,
void *key,
void *IV)
{
const mbedtls_cipher_info_t *cipher_info = NULL;
int rc;
mbedtls_gcm_init(&cipher->gcm_ctx);
cipher_info = mbedtls_cipher_info_from_type(cipher->type);
rc = mbedtls_gcm_setkey(&cipher->gcm_ctx,
MBEDTLS_CIPHER_ID_AES,
key,
cipher_info->key_bitlen);
if (rc != 0) {
SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_setkey failed");
goto error;
}
/* Store the IV so we can increment the packet counter later */
memcpy(cipher->last_iv, IV, AES_GCM_IVLEN);
return 0;
error:
mbedtls_gcm_free(&cipher->gcm_ctx);
return 1;
}
#endif /* MBEDTLS_GCM_C */
static int
cipher_set_decrypt_key(struct ssh_cipher_struct *cipher,
void *key,
@ -810,10 +845,104 @@ static void cipher_decrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void
}
#ifdef MBEDTLS_GCM_C
static int
cipher_gcm_get_length(struct ssh_cipher_struct *cipher,
void *in,
uint8_t *out,
size_t len,
uint64_t seq)
{
(void)seq;
/* The length is not encrypted: Copy it to the result buffer */
memcpy(out, in, len);
return SSH_OK;
}
static void
cipher_encrypt_gcm(struct ssh_cipher_struct *cipher,
void *in,
void *out,
size_t len,
uint8_t *tag,
uint64_t seq)
{
size_t authlen, aadlen;
int rc;
(void) seq;
aadlen = cipher->lenfield_blocksize;
authlen = cipher->tag_size;
/* The length is not encrypted */
memcpy(out, in, aadlen);
rc = mbedtls_gcm_crypt_and_tag(&cipher->gcm_ctx,
MBEDTLS_GCM_ENCRYPT,
len - aadlen, /* encrypted data len */
cipher->last_iv, /* IV */
AES_GCM_IVLEN,
in, /* aad */
aadlen,
(const unsigned char *)in + aadlen, /* input */
(unsigned char *)out + aadlen, /* output */
authlen,
tag); /* tag */
if (rc != 0) {
SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_crypt_and_tag failed");
return;
}
/* Increment the IV for the next invocation */
uint64_inc(cipher->last_iv + 4);
}
static int
cipher_decrypt_gcm(struct ssh_cipher_struct *cipher,
void *complete_packet,
uint8_t *out,
size_t encrypted_size,
uint64_t seq)
{
size_t authlen, aadlen;
int rc;
(void) seq;
aadlen = cipher->lenfield_blocksize;
authlen = cipher->tag_size;
rc = mbedtls_gcm_auth_decrypt(&cipher->gcm_ctx,
encrypted_size, /* encrypted data len */
cipher->last_iv, /* IV */
AES_GCM_IVLEN,
complete_packet, /* aad */
aadlen,
(const u_char *)complete_packet + aadlen + encrypted_size, /* tag */
authlen,
(const u_char *)complete_packet + aadlen, /* input */
(unsigned char *)out); /* output */
if (rc != 0) {
SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_auth_decrypt failed");
return SSH_ERROR;
}
/* Increment the IV for the next invocation */
uint64_inc(cipher->last_iv + 4);
return SSH_OK;
}
#endif /* MBEDTLS_GCM_C */
static void cipher_cleanup(struct ssh_cipher_struct *cipher)
{
mbedtls_cipher_free(&cipher->encrypt_ctx);
mbedtls_cipher_free(&cipher->decrypt_ctx);
#ifdef MBEDTLS_GCM_C
mbedtls_gcm_free(&cipher->gcm_ctx);
#endif /* MBEDTLS_GCM_C */
}
static struct ssh_cipher_struct ssh_ciphertab[] = {
@ -894,6 +1023,36 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
.decrypt = cipher_decrypt_cbc,
.cleanup = cipher_cleanup
},
#ifdef MBEDTLS_GCM_C
{
.name = "aes128-gcm@openssh.com",
.blocksize = 16,
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
.keysize = 128,
.tag_size = AES_GCM_TAGLEN,
.type = MBEDTLS_CIPHER_AES_128_GCM,
.set_encrypt_key = cipher_set_key_gcm,
.set_decrypt_key = cipher_set_key_gcm,
.aead_encrypt = cipher_encrypt_gcm,
.aead_decrypt_length = cipher_gcm_get_length,
.aead_decrypt = cipher_decrypt_gcm,
.cleanup = cipher_cleanup
},
{
.name = "aes256-gcm@openssh.com",
.blocksize = 16,
.lenfield_blocksize = 4, /* not encrypted, but authenticated */
.keysize = 256,
.tag_size = AES_GCM_TAGLEN,
.type = MBEDTLS_CIPHER_AES_256_GCM,
.set_encrypt_key = cipher_set_key_gcm,
.set_decrypt_key = cipher_set_key_gcm,
.aead_encrypt = cipher_encrypt_gcm,
.aead_decrypt_length = cipher_gcm_get_length,
.aead_decrypt = cipher_decrypt_gcm,
.cleanup = cipher_cleanup
},
#endif /* MBEDTLS_GCM_C */
{
.name = "3des-cbc",
.blocksize = 8,

Просмотреть файл

@ -1105,4 +1105,17 @@ char *strndup(const char *s, size_t n)
}
#endif /* ! HAVE_STRNDUP */
/* Increment 64b integer in network byte order */
void
uint64_inc(unsigned char *counter)
{
int i;
for (i = 7; i >= 0; i--) {
counter[i]++;
if (counter[i])
return;
}
}
/** @} */