1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-11-30 13:01:23 +03:00

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

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Jakub Jelen
2018-10-04 15:21:36 +02:00
committed by Andreas Schneider
parent a2120e168b
commit 72bd2fe197
6 changed files with 188 additions and 14 deletions

View File

@@ -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,