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;
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)
/* 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)
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;
}
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,
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;
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;
#include <sys/socket.h>
#include <openssl/rand.h>
#include <openssl/err.h>
-#include <openssl/rc4.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/bn.h>
}
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;
}
{
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)
{
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)
};
/**
- * 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.
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;
}
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).
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
----------------------------
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