libmbedtls: Support OpenSSH-compatible AES-GCM ciphers using mbedTLS
Signed-off-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Этот коммит содержится в:
родитель
a2120e168b
Коммит
72bd2fe197
@ -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,
|
||||
|
13
src/misc.c
13
src/misc.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user