mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-06-03 14:42:01 +03:00
chacha: packet encryption
Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
parent
ebd76bf347
commit
d038c4dee7
@ -128,10 +128,12 @@ struct ssh_cipher_struct {
|
|||||||
const char *name; /* ssh name of the algorithm */
|
const char *name; /* ssh name of the algorithm */
|
||||||
unsigned int blocksize; /* blocksize of the algo */
|
unsigned int blocksize; /* blocksize of the algo */
|
||||||
enum ssh_cipher_e ciphertype;
|
enum ssh_cipher_e ciphertype;
|
||||||
|
uint32_t lenfield_blocksize; /* blocksize of the packet length field */
|
||||||
#ifdef HAVE_LIBGCRYPT
|
#ifdef HAVE_LIBGCRYPT
|
||||||
size_t keylen; /* length of the key structure */
|
size_t keylen; /* length of the key structure */
|
||||||
gcry_cipher_hd_t *key;
|
gcry_cipher_hd_t *key;
|
||||||
#elif defined HAVE_LIBCRYPTO
|
#elif defined HAVE_LIBCRYPTO
|
||||||
|
size_t keylen; /* length of the key structure */
|
||||||
struct ssh_3des_key_schedule *des3_key;
|
struct ssh_3des_key_schedule *des3_key;
|
||||||
struct ssh_aes_key_schedule *aes_key;
|
struct ssh_aes_key_schedule *aes_key;
|
||||||
const EVP_CIPHER *cipher;
|
const EVP_CIPHER *cipher;
|
||||||
@ -141,7 +143,9 @@ struct ssh_cipher_struct {
|
|||||||
mbedtls_cipher_context_t decrypt_ctx;
|
mbedtls_cipher_context_t decrypt_ctx;
|
||||||
mbedtls_cipher_type_t type;
|
mbedtls_cipher_type_t type;
|
||||||
#endif
|
#endif
|
||||||
|
struct chacha20_poly1305_keysched *chacha20_schedule;
|
||||||
unsigned int keysize; /* bytes of key used. != keylen */
|
unsigned int keysize; /* bytes of key used. != keylen */
|
||||||
|
size_t tag_size; /* overhead required for tag */
|
||||||
/* sets the new key for immediate use */
|
/* sets the new key for immediate use */
|
||||||
int (*set_encrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
|
int (*set_encrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
|
||||||
int (*set_decrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
|
int (*set_decrypt_key)(struct ssh_cipher_struct *cipher, void *key, void *IV);
|
||||||
@ -149,6 +153,8 @@ struct ssh_cipher_struct {
|
|||||||
unsigned long len);
|
unsigned long len);
|
||||||
void (*decrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
|
void (*decrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||||
unsigned long len);
|
unsigned long len);
|
||||||
|
void (*aead_encrypt)(struct ssh_cipher_struct *cipher, void *in, void *out,
|
||||||
|
size_t len, uint8_t *mac, uint64_t seq);
|
||||||
void (*cleanup)(struct ssh_cipher_struct *cipher);
|
void (*cleanup)(struct ssh_cipher_struct *cipher);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,6 +95,7 @@ SHA512CTX sha512_init(void);
|
|||||||
void sha512_update(SHA512CTX c, const void *data, unsigned long len);
|
void sha512_update(SHA512CTX c, const void *data, unsigned long len);
|
||||||
void sha512_final(unsigned char *md, SHA512CTX c);
|
void sha512_final(unsigned char *md, SHA512CTX c);
|
||||||
|
|
||||||
|
void libcrypto_init(void);
|
||||||
struct ssh_cipher_struct *ssh_get_ciphertab(void);
|
struct ssh_cipher_struct *ssh_get_ciphertab(void);
|
||||||
|
|
||||||
#endif /* HAVE_LIBCRYPTO */
|
#endif /* HAVE_LIBCRYPTO */
|
||||||
|
@ -39,7 +39,8 @@ enum ssh_hmac_e {
|
|||||||
SSH_HMAC_SHA256,
|
SSH_HMAC_SHA256,
|
||||||
SSH_HMAC_SHA384,
|
SSH_HMAC_SHA384,
|
||||||
SSH_HMAC_SHA512,
|
SSH_HMAC_SHA512,
|
||||||
SSH_HMAC_MD5
|
SSH_HMAC_MD5,
|
||||||
|
SSH_HMAC_AEAD_POLY1305
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ssh_des_e {
|
enum ssh_des_e {
|
||||||
|
@ -122,6 +122,7 @@ set(libssh_SRCS
|
|||||||
bignum.c
|
bignum.c
|
||||||
buffer.c
|
buffer.c
|
||||||
callbacks.c
|
callbacks.c
|
||||||
|
chachapoly.c
|
||||||
channels.c
|
channels.c
|
||||||
client.c
|
client.c
|
||||||
config.c
|
config.c
|
||||||
|
126
src/chachapoly.c
Normal file
126
src/chachapoly.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the SSH Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 by Aris Adamantiadis
|
||||||
|
*
|
||||||
|
* The SSH Library is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* The SSH Library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with the SSH Library; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||||
|
* MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "libssh/libssh.h"
|
||||||
|
#include "libssh/crypto.h"
|
||||||
|
#include "libssh/chacha.h"
|
||||||
|
#include "libssh/poly1305.h"
|
||||||
|
#include "libssh/misc.h"
|
||||||
|
|
||||||
|
/* size of the keys k1 and k2 as defined in specs */
|
||||||
|
#define CHACHA20_KEYLEN 32
|
||||||
|
struct chacha20_poly1305_keysched {
|
||||||
|
/* key used for encrypting the length field*/
|
||||||
|
struct chacha_ctx k1;
|
||||||
|
/* key used for encrypting the packets */
|
||||||
|
struct chacha_ctx k2;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct ssh_packet_header {
|
||||||
|
uint32_t length;
|
||||||
|
uint8_t payload[];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
const uint8_t zero_block_counter[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
const uint8_t payload_block_counter[8] = {1, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
static int chacha20_set_encrypt_key(struct ssh_cipher_struct *cipher,
|
||||||
|
void *key,
|
||||||
|
void *IV)
|
||||||
|
{
|
||||||
|
struct chacha20_poly1305_keysched *sched;
|
||||||
|
uint8_t *u8key = key;
|
||||||
|
(void)IV;
|
||||||
|
|
||||||
|
if (cipher->chacha20_schedule == NULL) {
|
||||||
|
sched = malloc(sizeof *sched);
|
||||||
|
if (sched == NULL){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sched = cipher->chacha20_schedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
chacha_keysetup(&sched->k2, u8key, CHACHA20_KEYLEN * 8);
|
||||||
|
chacha_keysetup(&sched->k1, u8key + CHACHA20_KEYLEN, CHACHA20_KEYLEN * 8);
|
||||||
|
cipher->chacha20_schedule = sched;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @brief encrypts an outgoing packet with chacha20 and authenticate it
|
||||||
|
* with poly1305.
|
||||||
|
*/
|
||||||
|
static void chacha20_poly1305_aead_encrypt(struct ssh_cipher_struct *cipher,
|
||||||
|
void *in,
|
||||||
|
void *out,
|
||||||
|
size_t len,
|
||||||
|
uint8_t *tag,
|
||||||
|
uint64_t seq)
|
||||||
|
{
|
||||||
|
struct ssh_packet_header *in_packet = in, *out_packet = out;
|
||||||
|
uint8_t poly1305_ctx[POLY1305_KEYLEN] = {0};
|
||||||
|
struct chacha20_poly1305_keysched *keys = cipher->chacha20_schedule;
|
||||||
|
|
||||||
|
seq = htonll(seq);
|
||||||
|
/* step 1, prepare the poly1305 key */
|
||||||
|
chacha_ivsetup(&keys->k2, (uint8_t *)&seq, zero_block_counter);
|
||||||
|
chacha_encrypt_bytes(&keys->k2,
|
||||||
|
poly1305_ctx,
|
||||||
|
poly1305_ctx,
|
||||||
|
POLY1305_KEYLEN);
|
||||||
|
|
||||||
|
/* step 2, encrypt length field */
|
||||||
|
chacha_ivsetup(&keys->k1, (uint8_t *)&seq, zero_block_counter);
|
||||||
|
chacha_encrypt_bytes(&keys->k1,
|
||||||
|
(uint8_t *)&in_packet->length,
|
||||||
|
(uint8_t *)&out_packet->length,
|
||||||
|
sizeof(uint32_t));
|
||||||
|
|
||||||
|
/* step 3, encrypt packet payload */
|
||||||
|
chacha_ivsetup(&keys->k2, (uint8_t *)&seq, payload_block_counter);
|
||||||
|
chacha_encrypt_bytes(&keys->k2,
|
||||||
|
in_packet->payload,
|
||||||
|
out_packet->payload,
|
||||||
|
len - sizeof(uint32_t));
|
||||||
|
|
||||||
|
/* step 4, compute the MAC */
|
||||||
|
poly1305_auth(tag, (uint8_t *)out_packet, len, poly1305_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ssh_cipher_struct chacha20poly1305_cipher = {
|
||||||
|
.name = "chacha20-poly1305@openssh.com",
|
||||||
|
.blocksize = 8,
|
||||||
|
.lenfield_blocksize = 4,
|
||||||
|
.keylen = sizeof(struct chacha20_poly1305_keysched),
|
||||||
|
.keysize = 512,
|
||||||
|
.tag_size = POLY1305_TAGLEN,
|
||||||
|
.set_encrypt_key = chacha20_set_encrypt_key,
|
||||||
|
.set_decrypt_key = chacha20_set_encrypt_key,
|
||||||
|
.aead_encrypt = chacha20_poly1305_aead_encrypt,
|
||||||
|
};
|
3
src/dh.c
3
src/dh.c
@ -68,6 +68,7 @@
|
|||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#include "libssh/libcrypto.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static unsigned char p_group1_value[] = {
|
static unsigned char p_group1_value[] = {
|
||||||
@ -210,6 +211,8 @@ int ssh_crypto_init(void) {
|
|||||||
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
|
bignum_bin2bn(p_group14_value, P_GROUP14_LEN, p_group14);
|
||||||
|
|
||||||
OpenSSL_add_all_algorithms();
|
OpenSSL_add_all_algorithms();
|
||||||
|
|
||||||
|
libcrypto_init();
|
||||||
#elif defined HAVE_LIBMBEDCRYPTO
|
#elif defined HAVE_LIBMBEDCRYPTO
|
||||||
p_group1 = bignum_new();
|
p_group1 = bignum_new();
|
||||||
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1);
|
bignum_bin2bn(p_group1_value, P_GROUP1_LEN, p_group1);
|
||||||
|
@ -95,6 +95,8 @@
|
|||||||
#define ECDH ""
|
#define ECDH ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define CHACHA20 "chacha20-poly1305@openssh.com,"
|
||||||
|
|
||||||
#define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
|
#define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
|
||||||
#define KEX_METHODS_SIZE 10
|
#define KEX_METHODS_SIZE 10
|
||||||
|
|
||||||
@ -117,7 +119,7 @@ static const char *default_methods[] = {
|
|||||||
static const char *supported_methods[] = {
|
static const char *supported_methods[] = {
|
||||||
KEY_EXCHANGE,
|
KEY_EXCHANGE,
|
||||||
HOSTKEYS,
|
HOSTKEYS,
|
||||||
AES BLOWFISH DES_SUPPORTED,
|
CHACHA20 AES BLOWFISH DES_SUPPORTED,
|
||||||
AES BLOWFISH DES_SUPPORTED,
|
AES BLOWFISH DES_SUPPORTED,
|
||||||
"hmac-sha2-256,hmac-sha2-512,hmac-sha1",
|
"hmac-sha2-256,hmac-sha2-512,hmac-sha1",
|
||||||
"hmac-sha2-256,hmac-sha2-512,hmac-sha1",
|
"hmac-sha2-256,hmac-sha2-512,hmac-sha1",
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
|
|
||||||
#include "libssh/crypto.h"
|
#include "libssh/crypto.h"
|
||||||
|
|
||||||
|
extern const struct ssh_cipher_struct chacha20poly1305_cipher;
|
||||||
struct ssh_mac_ctx_struct {
|
struct ssh_mac_ctx_struct {
|
||||||
enum ssh_mac_e mac_type;
|
enum ssh_mac_e mac_type;
|
||||||
union {
|
union {
|
||||||
@ -860,11 +861,30 @@ static struct ssh_cipher_struct ssh_ciphertab[] = {
|
|||||||
.cleanup = des_cleanup
|
.cleanup = des_cleanup
|
||||||
},
|
},
|
||||||
#endif /* HAS_DES */
|
#endif /* HAS_DES */
|
||||||
|
{
|
||||||
|
.name = "chacha20-poly1305@openssh.com"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = NULL
|
.name = NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void libcrypto_init(void)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; ssh_ciphertab[i].name != NULL; i++) {
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
cmp = strcmp(ssh_ciphertab[i].name, "chacha20-poly1305@openssh.com");
|
||||||
|
if (cmp == 0) {
|
||||||
|
memcpy(&ssh_ciphertab[i],
|
||||||
|
&chacha20poly1305_cipher,
|
||||||
|
sizeof(struct ssh_cipher_struct));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ssh_cipher_struct *ssh_get_ciphertab(void)
|
struct ssh_cipher_struct *ssh_get_ciphertab(void)
|
||||||
{
|
{
|
||||||
@ -872,4 +892,3 @@ struct ssh_cipher_struct *ssh_get_ciphertab(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif /* LIBCRYPTO */
|
#endif /* LIBCRYPTO */
|
||||||
|
|
||||||
|
43
src/packet.c
43
src/packet.c
@ -555,6 +555,8 @@ static int ssh_packet_write(ssh_session session) {
|
|||||||
static int packet_send2(ssh_session session) {
|
static int packet_send2(ssh_session session) {
|
||||||
unsigned int blocksize = (session->current_crypto ?
|
unsigned int blocksize = (session->current_crypto ?
|
||||||
session->current_crypto->out_cipher->blocksize : 8);
|
session->current_crypto->out_cipher->blocksize : 8);
|
||||||
|
unsigned int lenfield_blocksize = (session->current_crypto ?
|
||||||
|
session->current_crypto->out_cipher->lenfield_blocksize : 0);
|
||||||
enum ssh_hmac_e hmac_type = (session->current_crypto ?
|
enum ssh_hmac_e hmac_type = (session->current_crypto ?
|
||||||
session->current_crypto->out_hmac : session->next_crypto->out_hmac);
|
session->current_crypto->out_hmac : session->next_crypto->out_hmac);
|
||||||
uint32_t currentlen = ssh_buffer_get_len(session->out_buffer);
|
uint32_t currentlen = ssh_buffer_get_len(session->out_buffer);
|
||||||
@ -563,8 +565,7 @@ static int packet_send2(ssh_session session) {
|
|||||||
int rc = SSH_ERROR;
|
int rc = SSH_ERROR;
|
||||||
uint32_t finallen,payloadsize,compsize;
|
uint32_t finallen,payloadsize,compsize;
|
||||||
uint8_t padding;
|
uint8_t padding;
|
||||||
|
ssh_buffer header_buffer = ssh_buffer_new();
|
||||||
uint8_t header[sizeof(padding) + sizeof(finallen)] = { 0 };
|
|
||||||
|
|
||||||
payloadsize = currentlen;
|
payloadsize = currentlen;
|
||||||
#ifdef WITH_ZLIB
|
#ifdef WITH_ZLIB
|
||||||
@ -578,20 +579,30 @@ static int packet_send2(ssh_session session) {
|
|||||||
}
|
}
|
||||||
#endif /* WITH_ZLIB */
|
#endif /* WITH_ZLIB */
|
||||||
compsize = currentlen;
|
compsize = currentlen;
|
||||||
padding = (blocksize - ((currentlen +5) % blocksize));
|
/* compressed payload + packet len (4) + padding len (1) */
|
||||||
|
/* totallen - lenfield_blocksize must be equal to 0 (mod blocksize) */
|
||||||
|
padding = (blocksize - ((blocksize - lenfield_blocksize + currentlen + 5) % blocksize));
|
||||||
if(padding < 4) {
|
if(padding < 4) {
|
||||||
padding += blocksize;
|
padding += blocksize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session->current_crypto) {
|
if (session->current_crypto != NULL) {
|
||||||
ssh_get_random(padstring, padding, 0);
|
ssh_get_random(padstring, padding, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
finallen = htonl(currentlen + padding + 1);
|
if (header_buffer == NULL){
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
finallen = currentlen + padding + 1;
|
||||||
|
rc = ssh_buffer_pack(header_buffer, "db", finallen, padding);
|
||||||
|
if (rc == SSH_ERROR){
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(&header[0], &finallen, sizeof(finallen));
|
rc = ssh_buffer_prepend_data(session->out_buffer,
|
||||||
header[sizeof(finallen)] = padding;
|
ssh_buffer_get(header_buffer),
|
||||||
rc = ssh_buffer_prepend_data(session->out_buffer, &header, sizeof(header));
|
ssh_buffer_get_len(header_buffer));
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -600,10 +611,12 @@ static int packet_send2(ssh_session session) {
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
#ifdef WITH_PCAP
|
#ifdef WITH_PCAP
|
||||||
if(session->pcap_ctx){
|
if (session->pcap_ctx) {
|
||||||
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,
|
ssh_pcap_context_write(session->pcap_ctx,
|
||||||
ssh_buffer_get(session->out_buffer),ssh_buffer_get_len(session->out_buffer)
|
SSH_PCAP_DIR_OUT,
|
||||||
,ssh_buffer_get_len(session->out_buffer));
|
ssh_buffer_get(session->out_buffer),
|
||||||
|
ssh_buffer_get_len(session->out_buffer),
|
||||||
|
ssh_buffer_get_len(session->out_buffer));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
hmac = ssh_packet_encrypt(session, ssh_buffer_get(session->out_buffer),
|
hmac = ssh_packet_encrypt(session, ssh_buffer_get(session->out_buffer),
|
||||||
@ -624,12 +637,14 @@ static int packet_send2(ssh_session session) {
|
|||||||
|
|
||||||
SSH_LOG(SSH_LOG_PACKET,
|
SSH_LOG(SSH_LOG_PACKET,
|
||||||
"packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]",
|
"packet: wrote [len=%d,padding=%hhd,comp=%d,payload=%d]",
|
||||||
ntohl(finallen), padding, compsize, payloadsize);
|
finallen, padding, compsize, payloadsize);
|
||||||
if (ssh_buffer_reinit(session->out_buffer) < 0) {
|
if (ssh_buffer_reinit(session->out_buffer) < 0) {
|
||||||
rc = SSH_ERROR;
|
rc = SSH_ERROR;
|
||||||
}
|
}
|
||||||
error:
|
error:
|
||||||
|
if (header_buffer != NULL) {
|
||||||
|
ssh_buffer_free(header_buffer);
|
||||||
|
}
|
||||||
return rc; /* SSH_OK, AGAIN or ERROR */
|
return rc; /* SSH_OK, AGAIN or ERROR */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len)
|
|||||||
if (!session->current_crypto) {
|
if (!session->current_crypto) {
|
||||||
return NULL; /* nothing to do here */
|
return NULL; /* nothing to do here */
|
||||||
}
|
}
|
||||||
if(len % session->current_crypto->in_cipher->blocksize != 0){
|
if((len - session->current_crypto->out_cipher->lenfield_blocksize) % session->current_crypto->out_cipher->blocksize != 0){
|
||||||
ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
|
ssh_set_error(session, SSH_FATAL, "Cryptographic functions must be set on at least one blocksize (received %d)",len);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -106,26 +106,36 @@ unsigned char *ssh_packet_encrypt(ssh_session session, void *data, uint32_t len)
|
|||||||
seq = ntohl(session->send_seq);
|
seq = ntohl(session->send_seq);
|
||||||
crypto = session->current_crypto->out_cipher;
|
crypto = session->current_crypto->out_cipher;
|
||||||
|
|
||||||
if (session->version == 2) {
|
if (crypto->aead_encrypt != NULL) {
|
||||||
ctx = hmac_init(session->current_crypto->encryptMAC, hmac_digest_len(type), type);
|
crypto->aead_encrypt(crypto, data, out, len,
|
||||||
if (ctx == NULL) {
|
session->current_crypto->hmacbuf, session->send_seq);
|
||||||
SAFE_FREE(out);
|
} else {
|
||||||
return NULL;
|
if (session->version == 2) {
|
||||||
}
|
ctx = hmac_init(session->current_crypto->encryptMAC, hmac_digest_len(type), type);
|
||||||
hmac_update(ctx,(unsigned char *)&seq,sizeof(uint32_t));
|
if (ctx == NULL) {
|
||||||
hmac_update(ctx,data,len);
|
SAFE_FREE(out);
|
||||||
hmac_final(ctx,session->current_crypto->hmacbuf,&finallen);
|
return NULL;
|
||||||
|
}
|
||||||
|
hmac_update(ctx,(unsigned char *)&seq,sizeof(uint32_t));
|
||||||
|
hmac_update(ctx,data,len);
|
||||||
|
hmac_final(ctx,session->current_crypto->hmacbuf,&finallen);
|
||||||
|
|
||||||
|
if (crypto->set_encrypt_key(crypto, session->current_crypto->encryptkey,
|
||||||
|
session->current_crypto->encryptIV) < 0) {
|
||||||
|
SAFE_FREE(out);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_CRYPTO
|
#ifdef DEBUG_CRYPTO
|
||||||
ssh_print_hexa("mac: ",data,hmac_digest_len(type));
|
ssh_print_hexa("mac: ",data,hmac_digest_len(type));
|
||||||
if (finallen != hmac_digest_len(type)) {
|
if (finallen != hmac_digest_len(type)) {
|
||||||
printf("Final len is %d\n",finallen);
|
printf("Final len is %d\n",finallen);
|
||||||
}
|
}
|
||||||
ssh_print_hexa("Packet hmac", session->current_crypto->hmacbuf, hmac_digest_len(type));
|
ssh_print_hexa("Packet hmac", session->current_crypto->hmacbuf, hmac_digest_len(type));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
crypto->encrypt(crypto, data, out, len);
|
crypto->encrypt(crypto, data, out, len);
|
||||||
|
}
|
||||||
memcpy(data, out, len);
|
memcpy(data, out, len);
|
||||||
explicit_bzero(out, len);
|
explicit_bzero(out, len);
|
||||||
SAFE_FREE(out);
|
SAFE_FREE(out);
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "libssh/crypto.h"
|
#include "libssh/crypto.h"
|
||||||
#include "libssh/wrapper.h"
|
#include "libssh/wrapper.h"
|
||||||
#include "libssh/pki.h"
|
#include "libssh/pki.h"
|
||||||
|
#include "libssh/poly1305.h"
|
||||||
|
|
||||||
static struct ssh_hmac_struct ssh_hmac_tab[] = {
|
static struct ssh_hmac_struct ssh_hmac_tab[] = {
|
||||||
{ "hmac-sha1", SSH_HMAC_SHA1 },
|
{ "hmac-sha1", SSH_HMAC_SHA1 },
|
||||||
@ -54,6 +55,7 @@ static struct ssh_hmac_struct ssh_hmac_tab[] = {
|
|||||||
{ "hmac-sha2-384", SSH_HMAC_SHA384 },
|
{ "hmac-sha2-384", SSH_HMAC_SHA384 },
|
||||||
{ "hmac-sha2-512", SSH_HMAC_SHA512 },
|
{ "hmac-sha2-512", SSH_HMAC_SHA512 },
|
||||||
{ "hmac-md5", SSH_HMAC_MD5 },
|
{ "hmac-md5", SSH_HMAC_MD5 },
|
||||||
|
{ "aead-poly1305", SSH_HMAC_AEAD_POLY1305 },
|
||||||
{ NULL, 0}
|
{ NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,6 +75,8 @@ size_t hmac_digest_len(enum ssh_hmac_e type) {
|
|||||||
return SHA512_DIGEST_LEN;
|
return SHA512_DIGEST_LEN;
|
||||||
case SSH_HMAC_MD5:
|
case SSH_HMAC_MD5:
|
||||||
return MD5_DIGEST_LEN;
|
return MD5_DIGEST_LEN;
|
||||||
|
case SSH_HMAC_AEAD_POLY1305:
|
||||||
|
return POLY1305_TAGLEN;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -124,6 +128,9 @@ void ssh_cipher_clear(struct ssh_cipher_struct *cipher){
|
|||||||
if (cipher->cleanup != NULL) {
|
if (cipher->cleanup != NULL) {
|
||||||
cipher->cleanup(cipher);
|
cipher->cleanup(cipher);
|
||||||
}
|
}
|
||||||
|
if (cipher->chacha20_schedule != NULL){
|
||||||
|
SAFE_FREE(cipher->chacha20_schedule);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cipher_free(struct ssh_cipher_struct *cipher) {
|
static void cipher_free(struct ssh_cipher_struct *cipher) {
|
||||||
@ -247,9 +254,14 @@ static int crypt_set_algorithms2(ssh_session session){
|
|||||||
}
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
/* we must scan the kex entries to find hmac algorithms and set their appropriate structure */
|
if (session->next_crypto->out_cipher->aead_encrypt != NULL){
|
||||||
/* out */
|
/* this cipher has integrated MAC */
|
||||||
wanted = session->next_crypto->kex_methods[SSH_MAC_C_S];
|
wanted = "aead-poly1305";
|
||||||
|
} else {
|
||||||
|
/* we must scan the kex entries to find hmac algorithms and set their appropriate structure */
|
||||||
|
/* out */
|
||||||
|
wanted = session->next_crypto->kex_methods[SSH_MAC_C_S];
|
||||||
|
}
|
||||||
while (ssh_hmactab[i].name && strcmp(wanted, ssh_hmactab[i].name)) {
|
while (ssh_hmactab[i].name && strcmp(wanted, ssh_hmactab[i].name)) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -357,7 +369,7 @@ int crypt_set_algorithms(ssh_session session, enum ssh_des_e des_type) {
|
|||||||
|
|
||||||
#ifdef WITH_SERVER
|
#ifdef WITH_SERVER
|
||||||
int crypt_set_algorithms_server(ssh_session session){
|
int crypt_set_algorithms_server(ssh_session session){
|
||||||
char *method = NULL;
|
const char *method = NULL;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
struct ssh_cipher_struct *ssh_ciphertab=ssh_get_ciphertab();
|
struct ssh_cipher_struct *ssh_ciphertab=ssh_get_ciphertab();
|
||||||
struct ssh_hmac_struct *ssh_hmactab=ssh_get_hmactab();
|
struct ssh_hmac_struct *ssh_hmactab=ssh_get_hmactab();
|
||||||
@ -372,9 +384,17 @@ int crypt_set_algorithms_server(ssh_session session){
|
|||||||
*/
|
*/
|
||||||
/* out */
|
/* out */
|
||||||
method = session->next_crypto->kex_methods[SSH_CRYPT_S_C];
|
method = session->next_crypto->kex_methods[SSH_CRYPT_S_C];
|
||||||
while(ssh_ciphertab[i].name && strcmp(method,ssh_ciphertab[i].name))
|
|
||||||
i++;
|
for (i = 0; ssh_ciphertab[i].name != NULL; i++) {
|
||||||
if(!ssh_ciphertab[i].name){
|
int cmp;
|
||||||
|
|
||||||
|
cmp = strcmp(method, ssh_ciphertab[i].name);
|
||||||
|
if (cmp == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssh_ciphertab[i].name == NULL) {
|
||||||
ssh_set_error(session,SSH_FATAL,"crypt_set_algorithms_server : "
|
ssh_set_error(session,SSH_FATAL,"crypt_set_algorithms_server : "
|
||||||
"no crypto algorithm function found for %s",method);
|
"no crypto algorithm function found for %s",method);
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
@ -387,26 +407,16 @@ int crypt_set_algorithms_server(ssh_session session){
|
|||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
i=0;
|
i=0;
|
||||||
/* in */
|
if (session->next_crypto->out_cipher->aead_encrypt != NULL){
|
||||||
method = session->next_crypto->kex_methods[SSH_CRYPT_C_S];
|
/* this cipher has integrated MAC */
|
||||||
while(ssh_ciphertab[i].name && strcmp(method,ssh_ciphertab[i].name))
|
method = "aead-poly1305";
|
||||||
i++;
|
} else {
|
||||||
if(!ssh_ciphertab[i].name){
|
/* we must scan the kex entries to find hmac algorithms and set their appropriate structure */
|
||||||
ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server :"
|
/* out */
|
||||||
"no crypto algorithm function found for %s",method);
|
method = session->next_crypto->kex_methods[SSH_MAC_S_C];
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
}
|
||||||
SSH_LOG(SSH_LOG_PACKET,"Set input algorithm %s",method);
|
|
||||||
|
|
||||||
session->next_crypto->in_cipher = cipher_new(i);
|
|
||||||
if (session->next_crypto->in_cipher == NULL) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
return SSH_ERROR;
|
|
||||||
}
|
|
||||||
i=0;
|
|
||||||
|
|
||||||
/* HMAC algorithm selection */
|
/* HMAC algorithm selection */
|
||||||
method = session->next_crypto->kex_methods[SSH_MAC_S_C];
|
|
||||||
while (ssh_hmactab[i].name && strcmp(method, ssh_hmactab[i].name)) {
|
while (ssh_hmactab[i].name && strcmp(method, ssh_hmactab[i].name)) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -420,11 +430,43 @@ int crypt_set_algorithms_server(ssh_session session){
|
|||||||
SSH_LOG(SSH_LOG_PACKET, "Set HMAC output algorithm to %s", method);
|
SSH_LOG(SSH_LOG_PACKET, "Set HMAC output algorithm to %s", method);
|
||||||
|
|
||||||
session->next_crypto->out_hmac = ssh_hmactab[i].hmac_type;
|
session->next_crypto->out_hmac = ssh_hmactab[i].hmac_type;
|
||||||
|
|
||||||
|
/* in */
|
||||||
|
i=0;
|
||||||
|
method = session->next_crypto->kex_methods[SSH_CRYPT_C_S];
|
||||||
|
|
||||||
|
for (i = 0; ssh_ciphertab[i].name; i++) {
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
cmp = strcmp(method, ssh_ciphertab[i].name);
|
||||||
|
if (cmp == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssh_ciphertab[i].name == NULL) {
|
||||||
|
ssh_set_error(session,SSH_FATAL,"Crypt_set_algorithms_server :"
|
||||||
|
"no crypto algorithm function found for %s",method);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
SSH_LOG(SSH_LOG_PACKET,"Set input algorithm %s",method);
|
||||||
|
|
||||||
|
session->next_crypto->in_cipher = cipher_new(i);
|
||||||
|
if (session->next_crypto->in_cipher == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
i=0;
|
i=0;
|
||||||
|
|
||||||
method = session->next_crypto->kex_methods[SSH_MAC_C_S];
|
method = session->next_crypto->kex_methods[SSH_MAC_C_S];
|
||||||
while (ssh_hmactab[i].name && strcmp(method, ssh_hmactab[i].name)) {
|
|
||||||
i++;
|
for (i = 0; ssh_hmactab[i].name != NULL; i++) {
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
cmp = strcmp(method, ssh_hmactab[i].name);
|
||||||
|
if (cmp == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssh_hmactab[i].name == NULL) {
|
if (ssh_hmactab[i].name == NULL) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user