diff options
Diffstat (limited to 'libs/libssh2/src/crypt.c')
-rw-r--r-- | libs/libssh2/src/crypt.c | 166 |
1 files changed, 160 insertions, 6 deletions
diff --git a/libs/libssh2/src/crypt.c b/libs/libssh2/src/crypt.c index 2fb661fd60..6c816eb447 100644 --- a/libs/libssh2/src/crypt.c +++ b/libs/libssh2/src/crypt.c @@ -39,6 +39,9 @@ */ #include "libssh2_priv.h" +#include "cipher-chachapoly.h" + +#include <assert.h> #if defined(LIBSSH2DEBUG) && defined(LIBSSH2_CRYPT_NONE_INSECURE) /* crypt_none_crypt @@ -55,8 +58,12 @@ * */ static int -crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf, - void **abstract, int firstlast) +crypt_none_crypt(LIBSSH2_SESSION * session, + unsigned int seqno, + unsigned char *buf, + size_t buf_len, + void **abstract, + int firstlast) { /* Do nothing to the data! */ return 0; @@ -80,6 +87,7 @@ struct crypt_ctx int encrypt; _libssh2_cipher_type(algo); _libssh2_cipher_ctx h; + struct chachapoly_ctx chachapoly_ctx; }; static int @@ -107,13 +115,18 @@ crypt_init(LIBSSH2_SESSION * session, } static int -crypt_encrypt(LIBSSH2_SESSION * session, unsigned char *block, - size_t blocksize, void **abstract, int firstlast) +crypt_encrypt(LIBSSH2_SESSION * session, + unsigned int seqno, + unsigned char *buf, + size_t buf_len, + void **abstract, + int firstlast) { struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract; (void) session; - return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block, - blocksize, firstlast); + (void) seqno; + return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, buf, + buf_len, firstlast); } static int @@ -135,8 +148,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_gcm = { 16, /* blocksize */ 12, /* initial value length */ 32, /* secret length -- 32*8 == 256bit */ + 16, /* length of the authentication tag */ LIBSSH2_CRYPT_FLAG_INTEGRATED_MAC | LIBSSH2_CRYPT_FLAG_PKTLEN_AAD, &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes256gcm @@ -148,8 +163,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_gcm = { 16, /* blocksize */ 12, /* initial value length */ 16, /* secret length -- 16*8 == 128bit */ + 16, /* length of the authentication tag */ LIBSSH2_CRYPT_FLAG_INTEGRATED_MAC | LIBSSH2_CRYPT_FLAG_PKTLEN_AAD, &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes128gcm @@ -163,8 +180,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = { 16, /* blocksize */ 16, /* initial value length */ 16, /* secret length -- 16*8 == 128bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes128ctr @@ -176,8 +195,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_ctr = { 16, /* blocksize */ 16, /* initial value length */ 24, /* secret length -- 24*8 == 192bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes192ctr @@ -189,8 +210,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_ctr = { 16, /* blocksize */ 16, /* initial value length */ 32, /* secret length -- 32*8 == 256bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes256ctr @@ -204,8 +227,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = { 16, /* blocksize */ 16, /* initial value length */ 16, /* secret length -- 16*8 == 128bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes128 @@ -217,8 +242,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = { 16, /* blocksize */ 16, /* initial value length */ 24, /* secret length -- 24*8 == 192bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes192 @@ -230,8 +257,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = { 16, /* blocksize */ 16, /* initial value length */ 32, /* secret length -- 32*8 == 256bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes256 @@ -245,8 +274,10 @@ static const LIBSSH2_CRYPT_METHOD 16, /* blocksize */ 16, /* initial value length */ 32, /* secret length -- 32*8 == 256bit */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_aes256 @@ -260,8 +291,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_blowfish @@ -275,8 +308,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_arcfour @@ -312,8 +347,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour128 = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init_arcfour128, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_arcfour @@ -327,8 +364,10 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = { 8, /* blocksize */ 8, /* initial value length */ 16, /* secret length */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_cast5 @@ -342,17 +381,132 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = { 8, /* blocksize */ 8, /* initial value length */ 24, /* secret length */ + 0, /* length of the authentication tag */ 0, /* flags */ &crypt_init, + NULL, &crypt_encrypt, &crypt_dtor, _libssh2_cipher_3des }; #endif +static int +crypt_init_chacha20_poly(LIBSSH2_SESSION * session, + const LIBSSH2_CRYPT_METHOD * method, + unsigned char *iv, int *free_iv, + unsigned char *secret, int *free_secret, + int encrypt, void **abstract) +{ + struct crypt_ctx *ctx = LIBSSH2_ALLOC(session, + sizeof(struct crypt_ctx)); + + (void)iv; + + if(!ctx) + return LIBSSH2_ERROR_ALLOC; + + ctx->encrypt = encrypt; + ctx->algo = method->algo; + + if(chachapoly_init(&ctx->chachapoly_ctx, secret, method->secret_len)) { + LIBSSH2_FREE(session, ctx); + return -1; + } + + *abstract = ctx; + *free_iv = 1; + *free_secret = 1; + return 0; +} + + +static int +crypt_encrypt_chacha20_poly_buffer(LIBSSH2_SESSION * session, + unsigned int seqno, + unsigned char *buf, + size_t buf_len, + void **abstract, + int firstlast) +{ + int ret = 1; + struct crypt_ctx *ctx = *(struct crypt_ctx **) abstract; + + (void)session; + (void)firstlast; + + if(ctx) { + if(ctx->encrypt) { + /* requires out_buf to be large enough to hold encrypted output + plus auth tag (auth len) + + buf is a full packet so we need to subtract packet length from + length + */ + ret = chachapoly_crypt(&ctx->chachapoly_ctx, seqno, buf, buf, + ((u_int)buf_len) - 4, 4, ctx->encrypt); + } + else { + /* buf is full packet including size and auth tag but buf_len + doesn't include size */ + ret = chachapoly_crypt(&ctx->chachapoly_ctx, seqno, buf, buf, + ((u_int)buf_len), 4, ctx->encrypt); + + /* the api expects the size field to already be removed + from the decrypted packet so we'll help it out */ + if(ret == 0) { + memmove(buf, buf + 4, buf_len - 4); + } + } + } + + return (ret == 0 ? 0 : 1); +} + +static int +crypt_get_length_chacha20_poly(LIBSSH2_SESSION * session, unsigned int seqno, + unsigned char *data, size_t data_size, + unsigned int *len, void **abstract) +{ + struct crypt_ctx *ctx = *(struct crypt_ctx **) abstract; + + (void)session; + + return chachapoly_get_length(&ctx->chachapoly_ctx, len, seqno, data, + (u_int)data_size); +} + +static int +crypt_dtor_chacha20_poly(LIBSSH2_SESSION * session, void **abstract) +{ + struct crypt_ctx **cctx = (struct crypt_ctx **) abstract; + if(cctx && *cctx) { + LIBSSH2_FREE(session, *cctx); + *abstract = NULL; + } + return 0; +} + +static const LIBSSH2_CRYPT_METHOD + libssh2_crypt_method_chacha20_poly1305_openssh = { + "chacha20-poly1305@openssh.com", + "", + 8, /* blocksize */ + 0, /* initial value length */ + 64, /* secret length */ + 16, /* length of the auth_tag */ + LIBSSH2_CRYPT_FLAG_REQUIRES_FULL_PACKET, /* flags */ + &crypt_init_chacha20_poly, + &crypt_get_length_chacha20_poly, + &crypt_encrypt_chacha20_poly_buffer, + &crypt_dtor_chacha20_poly, + _libssh2_cipher_chacha20 /* not actually used */ +}; + /* These are the crypt methods that are available to be negotiated. Methods towards the start are chosen in preference to ones further down the list. */ static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = { + &libssh2_crypt_method_chacha20_poly1305_openssh, #if LIBSSH2_AES_GCM &libssh2_crypt_method_aes256_gcm, &libssh2_crypt_method_aes128_gcm, |