diff --git a/COPYING b/COPYING index 9782090..ea01ee6 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,7 @@ /* Copyright (c) 2004-2007 Sara Golemon * Copyright (c) 2006-2007 The Written Word, Inc. * Copyright (c) 2009 Daniel Stenberg + * Copyright (C) 2008, 2009 Simon Josefsson * All rights reserved. * * Redistribution and use in source and binary forms, diff --git a/NEWS b/NEWS index fdc402a..ff83f85 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,10 @@ Version 1.2.2 (unreleased) . By Simon Josefsson. + o Support for the "aes128-ctr", "aes192-ctr", "aes256-ctr" ciphers + as per RFC 4344 for libgcrypt and OpenSSL. They are now the + preferred ciphers. By Simon Josefsson. + o Support for the "arcfour128" cipher as per RFC 4345 for libgcrypt and OpenSSL. It is preferred over the normal "arcfour" cipher which is somewhat broken. By Simon Josefsson. diff --git a/src/crypt.c b/src/crypt.c index 68d9898..34f3cde 100644 --- a/src/crypt.c +++ b/src/crypt.c @@ -1,5 +1,5 @@ -/* Copyright (c) 2004-2007, Sara Golemon - * Copyright (c) 2009 Simon Josefsson +/* Copyright (c) 2009 Simon Josefsson + * Copyright (c) 2004-2007, Sara Golemon * All rights reserved. * * Redistribution and use in source and binary forms, @@ -115,6 +115,44 @@ crypt_dtor(LIBSSH2_SESSION * session, void **abstract) return 0; } +#if LIBSSH2_AES_CTR +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = { + "aes128-ctr", + 16, /* blocksize */ + 16, /* initial value length */ + 16, /* secret length -- 16*8 == 128bit */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes128ctr +}; + +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_ctr = { + "aes192-ctr", + 16, /* blocksize */ + 16, /* initial value length */ + 24, /* secret length -- 24*8 == 192bit */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes192ctr +}; + +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_ctr = { + "aes256-ctr", + 16, /* blocksize */ + 16, /* initial value length */ + 32, /* secret length -- 32*8 == 256bit */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes256ctr +}; +#endif + #if LIBSSH2_AES static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = { "aes128-cbc", @@ -258,6 +296,11 @@ static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = { #endif static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = { +#if LIBSSH2_AES_CTR + &libssh2_crypt_method_aes128_ctr, + &libssh2_crypt_method_aes192_ctr, + &libssh2_crypt_method_aes256_ctr, +#endif /* LIBSSH2_AES */ #if LIBSSH2_AES &libssh2_crypt_method_aes256_cbc, &libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */ diff --git a/src/libgcrypt.c b/src/libgcrypt.c index fa852a4..ba00284 100644 --- a/src/libgcrypt.c +++ b/src/libgcrypt.c @@ -544,8 +544,11 @@ _libssh2_cipher_init(_libssh2_cipher_ctx * h, if (mode != GCRY_CIPHER_MODE_STREAM) { int blklen = gcry_cipher_get_algo_blklen(cipher); - ret = gcry_cipher_setiv(*h, iv, blklen); - if (ret) { + if (mode == GCRY_CIPHER_MODE_CTR) + ret = gcry_cipher_setctr(*h, iv, blklen); + else + ret = gcry_cipher_setiv(*h, iv, blklen); + if (ret) { gcry_cipher_close(*h); return -1; } diff --git a/src/libgcrypt.h b/src/libgcrypt.h index 8bf84cc..b972c35 100644 --- a/src/libgcrypt.h +++ b/src/libgcrypt.h @@ -44,6 +44,7 @@ #define LIBSSH2_HMAC_RIPEMD 1 #define LIBSSH2_AES 1 +#define LIBSSH2_AES_CTR 1 #define LIBSSH2_BLOWFISH 1 #define LIBSSH2_RC4 1 #define LIBSSH2_CAST 1 @@ -160,7 +161,13 @@ int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, #define _libssh2_gcry_cipher(c) (c >> 8) #define _libssh2_gcry_mode(m) (m & 0xFF) -#define _libssh2_cipher_aes256 \ +#define _libssh2_cipher_aes256ctr \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR) +#define _libssh2_cipher_aes192ctr \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR) +#define _libssh2_cipher_aes128ctr \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR) +#define _libssh2_cipher_aes256 \ _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC) #define _libssh2_cipher_aes192 \ _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC) diff --git a/src/openssl.c b/src/openssl.c index b22151b..250ea63 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -1,7 +1,9 @@ -/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. - * Author: Simon Josefsson +/* Copyright (C) 2009 Simon Josefsson + * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. * Copyright (c) 2004-2006, Sara Golemon * + * Author: Simon Josefsson + * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: @@ -197,6 +199,106 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, return ret == 1 ? 0 : 1; } +#include + +typedef struct +{ + AES_KEY key; + unsigned char ctr[AES_BLOCK_SIZE]; +} aes_ctr_ctx; + +static int +aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) /* init key */ +{ + aes_ctr_ctx *c = malloc(sizeof(*c)); + if (c == NULL) + return 0; + + AES_set_encrypt_key(key, 8 * ctx->key_len, &c->key); + memcpy(c->ctr, iv, AES_BLOCK_SIZE); + + EVP_CIPHER_CTX_set_app_data(ctx, c); + + return 1; +} + +static int +aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, + unsigned int inl) /* encrypt/decrypt data */ +{ + aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); + unsigned char b1[AES_BLOCK_SIZE]; + size_t i; + + if (inl != 16) /* libssh2 only ever encrypt one block */ + return 0; + +/* + To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each + blocks of length L), the encryptor first encrypts with + to obtain a block B1. The block B1 is then XORed with P1 to generate + the ciphertext block C1. The counter X is then incremented +*/ + + AES_encrypt(c->ctr, b1, &c->key); + + for (i = 0; i < 16; i++) + *out++ = *in++ ^ b1[i]; + + i = 15; + while (c->ctr[i]++ == 0xFF) { + if (i == 0) + break; + i--; + } + + return 1; +} + +static int +aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */ +{ + free(EVP_CIPHER_CTX_get_app_data(ctx)); + return 1; +} + +static const EVP_CIPHER * +make_ctr_evp (size_t keylen) +{ + static EVP_CIPHER aes_ctr_cipher; + + memset(&aes_ctr_cipher, 0, sizeof(aes_ctr_cipher)); + + aes_ctr_cipher.block_size = 16; + aes_ctr_cipher.key_len = keylen; + aes_ctr_cipher.iv_len = 16; + aes_ctr_cipher.init = aes_ctr_init; + aes_ctr_cipher.do_cipher = aes_ctr_do_cipher; + aes_ctr_cipher.cleanup = aes_ctr_cleanup; + + return &aes_ctr_cipher; +} + +const EVP_CIPHER * +_libssh2_EVP_aes_128_ctr(void) +{ + return make_ctr_evp (16); +} + +const EVP_CIPHER * +_libssh2_EVP_aes_192_ctr(void) +{ + return make_ctr_evp (24); +} + +const EVP_CIPHER * +_libssh2_EVP_aes_256_ctr(void) +{ + return make_ctr_evp (32); +} + /* TODO: Optionally call a passphrase callback specified by the * calling program */ diff --git a/src/openssl.h b/src/openssl.h index 75a6058..66c606a 100644 --- a/src/openssl.h +++ b/src/openssl.h @@ -1,4 +1,6 @@ -/* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. +/* Copyright (C) 2009 Simon Josefsson + * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. + * * Author: Simon Josefsson * * Redistribution and use in source and binary forms, @@ -71,6 +73,7 @@ #endif #if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES) +# define LIBSSH2_AES_CTR 1 # define LIBSSH2_AES 1 #else # define LIBSSH2_AES 0 @@ -194,6 +197,9 @@ int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, #define _libssh2_cipher_aes256 EVP_aes_256_cbc #define _libssh2_cipher_aes192 EVP_aes_192_cbc #define _libssh2_cipher_aes128 EVP_aes_128_cbc +#define _libssh2_cipher_aes128ctr _libssh2_EVP_aes_128_ctr +#define _libssh2_cipher_aes192ctr _libssh2_EVP_aes_192_ctr +#define _libssh2_cipher_aes256ctr _libssh2_EVP_aes_256_ctr #define _libssh2_cipher_blowfish EVP_bf_cbc #define _libssh2_cipher_arcfour EVP_rc4 #define _libssh2_cipher_cast5 EVP_cast5_cbc @@ -223,3 +229,7 @@ int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, #define _libssh2_bn_bytes(bn) BN_num_bytes(bn) #define _libssh2_bn_bits(bn) BN_num_bits(bn) #define _libssh2_bn_free(bn) BN_clear_free(bn) + +const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void); +const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void); +const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void);