mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-11 02:38:09 +09: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:
committed by
Andreas Schneider
parent
a2120e168b
commit
72bd2fe197
@@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
|
#elif defined(HAVE_LIBMBEDCRYPTO)
|
||||||
|
#include <mbedtls/gcm.h>
|
||||||
#endif
|
#endif
|
||||||
#include "libssh/wrapper.h"
|
#include "libssh/wrapper.h"
|
||||||
|
|
||||||
@@ -152,6 +154,10 @@ struct ssh_cipher_struct {
|
|||||||
mbedtls_cipher_context_t encrypt_ctx;
|
mbedtls_cipher_context_t encrypt_ctx;
|
||||||
mbedtls_cipher_context_t decrypt_ctx;
|
mbedtls_cipher_context_t decrypt_ctx;
|
||||||
mbedtls_cipher_type_t type;
|
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
|
#endif
|
||||||
struct chacha20_poly1305_keysched *chacha20_schedule;
|
struct chacha20_poly1305_keysched *chacha20_schedule;
|
||||||
unsigned int keysize; /* bytes of key used. != keylen */
|
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);
|
int ssh_match_group(const char *group, const char *object);
|
||||||
|
|
||||||
|
void uint64_inc(unsigned char *counter);
|
||||||
|
|
||||||
#endif /* MISC_H_ */
|
#endif /* MISC_H_ */
|
||||||
|
|||||||
@@ -48,7 +48,13 @@
|
|||||||
|
|
||||||
#elif defined HAVE_LIBMBEDCRYPTO
|
#elif defined HAVE_LIBMBEDCRYPTO
|
||||||
# define BLOWFISH "blowfish-cbc,"
|
# 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 "3des-cbc"
|
||||||
# define DES_SUPPORTED "3des-cbc"
|
# define DES_SUPPORTED "3des-cbc"
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "libssh/crypto.h"
|
#include "libssh/crypto.h"
|
||||||
#include "libssh/wrapper.h"
|
#include "libssh/wrapper.h"
|
||||||
#include "libssh/string.h"
|
#include "libssh/string.h"
|
||||||
|
#include "libssh/misc.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
@@ -429,19 +430,6 @@ aes_aead_get_length(struct ssh_cipher_struct *cipher,
|
|||||||
return SSH_OK;
|
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
|
static void
|
||||||
aes_gcm_encrypt(struct ssh_cipher_struct *cipher,
|
aes_gcm_encrypt(struct ssh_cipher_struct *cipher,
|
||||||
void *in,
|
void *in,
|
||||||
|
|||||||
@@ -26,9 +26,13 @@
|
|||||||
#include "libssh/wrapper.h"
|
#include "libssh/wrapper.h"
|
||||||
#include "libssh/crypto.h"
|
#include "libssh/crypto.h"
|
||||||
#include "libssh/priv.h"
|
#include "libssh/priv.h"
|
||||||
|
#include "libssh/misc.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBMBEDCRYPTO
|
#ifdef HAVE_LIBMBEDCRYPTO
|
||||||
#include <mbedtls/md.h>
|
#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_entropy_context ssh_mbedtls_entropy;
|
||||||
static mbedtls_ctr_drbg_context ssh_mbedtls_ctr_drbg;
|
static mbedtls_ctr_drbg_context ssh_mbedtls_ctr_drbg;
|
||||||
@@ -616,6 +620,37 @@ error:
|
|||||||
return SSH_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
|
static int
|
||||||
cipher_set_decrypt_key(struct ssh_cipher_struct *cipher,
|
cipher_set_decrypt_key(struct ssh_cipher_struct *cipher,
|
||||||
void *key,
|
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)
|
static void cipher_cleanup(struct ssh_cipher_struct *cipher)
|
||||||
{
|
{
|
||||||
mbedtls_cipher_free(&cipher->encrypt_ctx);
|
mbedtls_cipher_free(&cipher->encrypt_ctx);
|
||||||
mbedtls_cipher_free(&cipher->decrypt_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[] = {
|
static struct ssh_cipher_struct ssh_ciphertab[] = {
|
||||||
@@ -894,6 +1023,36 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
|||||||
.decrypt = cipher_decrypt_cbc,
|
.decrypt = cipher_decrypt_cbc,
|
||||||
.cleanup = cipher_cleanup
|
.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",
|
.name = "3des-cbc",
|
||||||
.blocksize = 8,
|
.blocksize = 8,
|
||||||
|
|||||||
13
src/misc.c
13
src/misc.c
@@ -1105,4 +1105,17 @@ char *strndup(const char *s, size_t n)
|
|||||||
}
|
}
|
||||||
#endif /* ! HAVE_STRNDUP */
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|||||||
Reference in New Issue
Block a user