From: Andre Noll Date: Sun, 16 Apr 2017 18:15:35 +0000 (+0200) Subject: Merge branch 'refs/heads/t/rm_rc4' X-Git-Tag: v0.6.0~11 X-Git-Url: http://git.tuebingen.mpg.de/?a=commitdiff_plain;h=a826152ba51fd4813f715e5fa30e7d70407dc846;hp=9090ef9c56f488ea019b8cb8a40f22112bc3311a;p=paraslash.git Merge branch 'refs/heads/t/rm_rc4' This patch removes support for RC4, making the AES-based stream cipher mandadory. The aes_ctr128 server feature is made a no-op, breaking support with very old clients (<= 0.5.1). Cooking for three months. * refs/heads/t/rm_rc4: crypt: Remove RC4 support. --- diff --git a/NEWS.md b/NEWS.md index fb666529..08acd22c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,6 +13,9 @@ NEWS ssh-keygen(1). - If libgcrypt is used as the crypto library, we now require version 1.5.0 (released in 2011) or later. +- The insecure RC4 stream cipher has been removed. It was superseded + by aes_ctr128 three years ago but the RC4 code had been kept for + backwards compatibility. Downloads: [tarball](./releases/paraslash-git.tar.bz2), diff --git a/client_common.c b/client_common.c index eea7510f..ac53b9b5 100644 --- a/client_common.c +++ b/client_common.c @@ -241,11 +241,6 @@ out: return ret; } -static bool has_feature(const char *feature, struct client_task *ct) -{ - return find_arg(feature, ct->features) >= 0? true : false; -} - static int send_sb_command(struct client_task *ct) { int i; @@ -297,8 +292,8 @@ static int client_post_select(struct sched *s, void *context) case CL_RECEIVED_WELCOME: /* send auth command */ if (!FD_ISSET(ct->scc.fd, &s->wfds)) return 0; - sprintf(buf, AUTH_REQUEST_MSG "%s sideband%s", ct->user, - has_feature("aes_ctr128", ct)? ",aes_ctr128" : ""); + sprintf(buf, AUTH_REQUEST_MSG "%s sideband,aes_ctr128", + ct->user); PARA_INFO_LOG("--> %s\n", buf); ret = write_buffer(ct->scc.fd, buf); if (ret < 0) @@ -314,7 +309,6 @@ static int client_post_select(struct sched *s, void *context) /* decrypted challenge/session key buffer */ unsigned char crypt_buf[1024]; struct sb_buffer sbb; - bool use_aes; ret = recv_sb(ct, &s->rfds, &sbb); if (ret <= 0) @@ -333,10 +327,9 @@ static int client_post_select(struct sched *s, void *context) goto out; ct->challenge_hash = para_malloc(HASH_SIZE); hash_function((char *)crypt_buf, CHALLENGE_SIZE, ct->challenge_hash); - use_aes = has_feature("aes_ctr128", ct); - ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN, use_aes); + ct->scc.send = sc_new(crypt_buf + CHALLENGE_SIZE, SESSION_KEY_LEN); ct->scc.recv = sc_new(crypt_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, - SESSION_KEY_LEN, use_aes); + SESSION_KEY_LEN); hash_to_asc(ct->challenge_hash, buf); PARA_INFO_LOG("--> %s\n", buf); ct->status = CL_RECEIVED_CHALLENGE; diff --git a/command.c b/command.c index fe4b9232..58441b02 100644 --- a/command.c +++ b/command.c @@ -807,7 +807,7 @@ static void reset_signals(void) } struct connection_features { - bool aes_ctr128_requested; + int dummy; /* none at the moment */ }; static int parse_auth_request(char *buf, int len, struct user **u, @@ -836,7 +836,7 @@ static int parse_auth_request(char *buf, int len, struct user **u, if (strcmp(features[i], "sideband") == 0) continue; if (strcmp(features[i], "aes_ctr128") == 0) - cf->aes_ctr128_requested = true; + continue; else { ret = -E_BAD_FEATURE; goto out; @@ -994,10 +994,9 @@ __noreturn void handle_connect(int fd, const char *peername) alarm(0); PARA_INFO_LOG("good auth for %s\n", cc->u->name); /* init stream cipher keys with the second part of the random buffer */ - cc->scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN, - cf.aes_ctr128_requested); + cc->scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN); cc->scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, - SESSION_KEY_LEN, cf.aes_ctr128_requested); + SESSION_KEY_LEN); ret = send_sb(&cc->scc, NULL, 0, SBD_PROCEED, false); if (ret < 0) goto net_err; diff --git a/crypt.c b/crypt.c index 29a1c955..f1e42d4a 100644 --- a/crypt.c +++ b/crypt.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -245,26 +244,16 @@ int pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, } struct stream_cipher { - bool use_aes; - union { - RC4_KEY rc4_key; - EVP_CIPHER_CTX *aes; - } context; + EVP_CIPHER_CTX *aes; }; -struct stream_cipher *sc_new(const unsigned char *data, int len, - bool use_aes) +struct stream_cipher *sc_new(const unsigned char *data, int len) { struct stream_cipher *sc = para_malloc(sizeof(*sc)); - sc->use_aes = use_aes; - if (!use_aes) { - RC4_set_key(&sc->context.rc4_key, len, data); - return sc; - } assert(len >= 2 * AES_CRT128_BLOCK_SIZE); - sc->context.aes = EVP_CIPHER_CTX_new(); - EVP_EncryptInit_ex(sc->context.aes, EVP_aes_128_ctr(), NULL, data, + sc->aes = EVP_CIPHER_CTX_new(); + EVP_EncryptInit_ex(sc->aes, EVP_aes_128_ctr(), NULL, data, data + AES_CRT128_BLOCK_SIZE); return sc; } @@ -273,40 +262,10 @@ void sc_free(struct stream_cipher *sc) { if (!sc) return; - EVP_CIPHER_CTX_free(sc->context.aes); + EVP_CIPHER_CTX_free(sc->aes); free(sc); } -/** - * The RC4() implementation of openssl apparently reads and writes data in - * blocks of 8 bytes. So we have to make sure our buffer sizes are a multiple - * of this. - */ -#define RC4_ALIGN 8 - -static void rc4_crypt(RC4_KEY *key, struct iovec *src, struct iovec *dst) -{ - size_t len = src->iov_len, l1, l2; - - assert(len > 0); - assert(len < ((typeof(src->iov_len))-1) / 2); - l1 = ROUND_DOWN(len, RC4_ALIGN); - l2 = ROUND_UP(len, RC4_ALIGN); - - *dst = (typeof(*dst)) { - /* Add one for the terminating zero byte. */ - .iov_base = para_malloc(l2 + 1), - .iov_len = len - }; - RC4(key, l1, src->iov_base, dst->iov_base); - if (len > l1) { - unsigned char remainder[RC4_ALIGN] = ""; - memcpy(remainder, src->iov_base + l1, len - l1); - RC4(key, len - l1, remainder, dst->iov_base + l1); - } - ((char *)dst->iov_base)[len] = '\0'; -} - static void aes_ctr128_crypt(EVP_CIPHER_CTX *ctx, struct iovec *src, struct iovec *dst) { @@ -328,9 +287,7 @@ static void aes_ctr128_crypt(EVP_CIPHER_CTX *ctx, struct iovec *src, void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst) { - if (sc->use_aes) - return aes_ctr128_crypt(sc->context.aes, src, dst); - return rc4_crypt(&sc->context.rc4_key, src, dst); + return aes_ctr128_crypt(sc->aes, src, dst); } void hash_function(const char *data, unsigned long len, unsigned char *hash) diff --git a/crypt.h b/crypt.h index 6f3befdb..5e25748c 100644 --- a/crypt.h +++ b/crypt.h @@ -118,16 +118,14 @@ struct stream_cipher_context { }; /** - * Allocate and initialize a stream cipher structure. + * Allocate and initialize an aes_ctr128 stream cipher structure. * * \param data The key. * \param len The size of the key. - * \param use_aes True: Use the aes_ctr128 stream cipher, false: Use RC4. * * \return A new stream cipher structure. */ -struct stream_cipher *sc_new(const unsigned char *data, int len, - bool use_aes); +struct stream_cipher *sc_new(const unsigned char *data, int len); /** * Encrypt or decrypt a buffer using a stream cipher. diff --git a/gcrypt.c b/gcrypt.c index 0ba8d526..1fde479e 100644 --- a/gcrypt.c +++ b/gcrypt.c @@ -617,33 +617,20 @@ struct stream_cipher { gcry_cipher_hd_t handle; }; -struct stream_cipher *sc_new(const unsigned char *data, int len, - bool use_aes) +struct stream_cipher *sc_new(const unsigned char *data, int len) { gcry_error_t gret; struct stream_cipher *sc = para_malloc(sizeof(*sc)); - if (use_aes) { - assert(len >= 2 * AES_CRT128_BLOCK_SIZE); - gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_AES128, - GCRY_CIPHER_MODE_CTR, 0); - assert(gret == 0); - gret = gcry_cipher_setkey(sc->handle, data, - AES_CRT128_BLOCK_SIZE); - assert(gret == 0); - gret = gcry_cipher_setctr(sc->handle, - data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE); - assert(gret == 0); - return sc; - } - gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_ARCFOUR, - GCRY_CIPHER_MODE_STREAM, 0); - if (gret) { - PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret)); - free(sc); - return NULL; - } - gret = gcry_cipher_setkey(sc->handle, data, (size_t)len); + assert(len >= 2 * AES_CRT128_BLOCK_SIZE); + gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_AES128, + GCRY_CIPHER_MODE_CTR, 0); + assert(gret == 0); + gret = gcry_cipher_setkey(sc->handle, data, + AES_CRT128_BLOCK_SIZE); + assert(gret == 0); + gret = gcry_cipher_setctr(sc->handle, + data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE); assert(gret == 0); return sc; } diff --git a/web/manual.md b/web/manual.md index e7bb4afc..fef8123a 100644 --- a/web/manual.md +++ b/web/manual.md @@ -447,9 +447,9 @@ User management para_server uses a challenge-response mechanism to authenticate requests from incoming connections, similar to ssh's public key authentication method. Authenticated connections are encrypted using -a stream cipher, either RC4 or AES in integer counter mode. +the AES stream cipher in integer counter mode. -In this chapter we briefly describe RSA, RC4 and AES, and sketch the +In this chapter we briefly describe RSA and AES, and sketch the [authentication handshake](#Client-server.authentication) between para_client and para_server. User management is discussed in the section on [the user_list file](#The.user_list.file). @@ -457,33 +457,33 @@ These sections are all about communication between the client and the server. Connecting para_audiod is a different matter and is described in a [separate section](#Connecting.para_audiod). -RSA, RC4, AES -------------- +RSA and AES +----------- -RSA is an asymmetric block cipher which is used in many applications, -including ssh and gpg. An RSA key consists in fact of two keys, +A block cipher is a transformation which operates on fixed-length +blocks. For symmetric block ciphers the transformation is determined +by a single key for both encryption and decryption. For asymmetric +block ciphers, on the other hand, the key consists of two parts, called the public key and the private key. A message can be encrypted -with either key and only the counterpart of that key can decrypt -the message. While RSA can be used for both signing and encrypting -a message, paraslash uses RSA only for the latter purpose. The -RSA public key encryption and signatures algorithms are defined in -detail in RFC 2437. - -RC4 is a stream cipher, i.e. the input is XORed with a pseudo-random -key stream to produce the output. Decryption uses the same function -calls as encryption. While RC4 supports variable key lengths, -paraslash uses a fixed length of 256 bits, which is considered a -strong encryption by today's standards. Since the same key must never -be used twice, a different, randomly-generated key is used for every -new connection. +with either key and only the counterpart of that key can decrypt the +message. Asymmetric block ciphers can be used for both signing and +encrypting a message. + +RSA is an asymmetric block cipher which is used in many applications, +including ssh and gpg. The RSA public key encryption and signatures +algorithms are defined in detail in RFC 2437. Paraslash relies on +RSA for authentication. + +Stream ciphers XOR the input with a pseudo-random key stream to produce +the output. Decryption uses the same function calls as encryption. +Any block cipher can be turned into a stream cipher by generating the +pseudo-random key stream by encrypting successive values of a counter +(counter mode). AES, the advanced encryption standard, is a well-known symmetric block -cipher, i.e. a transformation operating on fixed-length blocks which -is determined by a single key for both encryption and decryption. Any -block cipher can be turned into a stream cipher by generating -a pseudo-random key stream by encrypting successive values of a -counter. The AES_CTR128 stream cipher used in paraslash is obtained -in this way from the AES block cipher with a 128 bit block size. +cipher. Paraslash employs AES in counter mode as described above to +encrypt communications. Since a stream cipher key must not be used +twice, a random key is generated for every new connection. Client-server authentication ---------------------------- @@ -523,8 +523,8 @@ point on the communication is encrypted using the stream cipher with the session key known to both peers. paraslash relies on the quality of the pseudo-random bytes provided -by the crypto library (openssl or libgcrypt), on the security of the -implementation of the RSA, RC4 and AES crypto routines and on the +by the crypto library (openssl or libgcrypt), on the security of +the implementation of the RSA and AES crypto routines and on the infeasibility to invert the SHA1 function. Neither para_server or para_client create RSA keys on their