/*
- * Copyright (C) 2005-2011 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2005 Andre Noll <maan@tuebingen.mpg.de>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
/** \file crypt.c Openssl-based encryption/decryption routines. */
#include <regex.h>
-#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <openssl/rand.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/bn.h>
+#include <openssl/aes.h>
#include "para.h"
#include "error.h"
RSA *rsa;
};
-/**
- * Fill a buffer with random content.
- *
- * \param buf The buffer to fill.
- * \param num The size of \a buf in bytes.
- *
- * This function puts \a num cryptographically strong pseudo-random bytes into
- * buf. If libssl can not guarantee an unpredictable byte sequence (for example
- * because the PRNG has not been seeded with enough randomness) the function
- * logs an error message and calls exit().
- */
void get_random_bytes_or_die(unsigned char *buf, int num)
{
unsigned long err;
exit(EXIT_FAILURE);
}
-/**
- * Seed pseudo random number generators.
- *
- * This function reads 64 bytes from /dev/urandom and adds them to the SSL
- * PRNG. It also seeds the PRNG used by random() with a random seed obtained
- * from SSL. If /dev/random could not be read, an error message is logged and
- * the function calls exit().
+/*
+ * Read 64 bytes from /dev/urandom and adds them to the SSL PRNG. Seed the PRNG
+ * used by random() with a random seed obtained from SSL. If /dev/random is not
+ * readable the function calls exit().
*
* \sa RAND_load_file(3), \ref get_random_bytes_or_die(), srandom(3),
* random(3), \ref para_random().
*result = rsa;
return 1;
fail:
- if (rsa)
- RSA_free(rsa);
+ RSA_free(rsa);
return ret;
}
-/**
- * Read an asymmetric key from a file.
- *
- * \param key_file The file containing the key.
- * \param private if non-zero, read the private key, otherwise the public key.
- * \param result The key structure is returned here.
- *
- * \return The size of the key on success, negative on errors.
- *
- * \sa openssl(1), rsa(1).
- */
int get_asymmetric_key(const char *key_file, int private,
struct asymmetric_key **result)
{
PARA_INFO_LOG("decoding public rsa-ssh key %s\n", key_file);
ret = -ERRNO_TO_PARA_ERROR(EOVERFLOW);
if (map_size > INT_MAX / 4)
- goto out;
+ goto out_unmap;
blob_size = 2 * map_size;
blob = para_malloc(blob_size);
ret = uudecode(cp, blob, blob_size);
if (ret < 0)
- goto out;
+ goto out_unmap;
decoded_size = ret;
ret = check_ssh_key_header(blob, decoded_size);
if (ret < 0)
- goto out;
+ goto out_unmap;
ret = read_rsa_bignums(blob + ret, decoded_size - ret, &key->rsa);
if (ret < 0)
- goto out;
+ goto out_unmap;
ret = RSA_size(key->rsa);
-out:
+out_unmap:
ret2 = para_munmap(map, map_size);
if (ret >= 0 && ret2 < 0)
ret = ret2;
+out:
if (ret < 0) {
free(key);
- result = NULL;
+ *result = NULL;
PARA_ERROR_LOG("key %s: %s\n", key_file, para_strerror(-ret));
} else
*result = key;
return ret;
}
-/**
- * Deallocate an asymmetric key structure.
- *
- * \param key Pointer to the key structure to free.
- *
- * This must be called for any key obtained by get_asymmetric_key().
- */
void free_asymmetric_key(struct asymmetric_key *key)
{
if (!key)
free(key);
}
-/**
- * Decrypt a buffer using a private key.
- *
- * \param key_file Full path of the key.
- * \param outbuf The output buffer.
- * \param inbuf The encrypted input buffer.
- * \param inlen The length of \a inbuf in bytes.
- *
- * The \a outbuf must be large enough to hold at least \a rsa_inlen bytes.
- *
- * \return The size of the recovered plaintext on success, negative on errors.
- *
- * \sa RSA_private_decrypt(3)
- **/
int priv_decrypt(const char *key_file, unsigned char *outbuf,
unsigned char *inbuf, int inlen)
{
return ret;
}
-/**
- * Encrypt a buffer using an RSA key
- *
- * \param pub: The public key.
- * \param inbuf The input buffer.
- * \param len The length of \a inbuf.
- * \param outbuf The output buffer.
- *
- * \return The size of the encrypted data on success, negative on errors.
- *
- * \sa RSA_public_encrypt(3)
- */
int pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
unsigned len, unsigned char *outbuf)
{
return ret < 0? -E_ENCRYPT : ret;
}
+struct aes_ctr_128_context {
+ AES_KEY key;
+ unsigned char ivec[AES_CRT128_BLOCK_SIZE];
+ unsigned char ecount[AES_CRT128_BLOCK_SIZE];
+ unsigned int num;
+};
+
struct stream_cipher {
- RC4_KEY key;
+ bool use_aes;
+ union {
+ RC4_KEY rc4_key;
+ struct aes_ctr_128_context aes;
+ } context;
};
-/**
- * Allocate and initialize a stream cipher structure.
- *
- * \param data The key.
- * \param len The size of the key.
- *
- * \return A new stream cipher structure.
- */
-struct stream_cipher *sc_new(const unsigned char *data, int len)
+struct stream_cipher *sc_new(const unsigned char *data, int len,
+ bool use_aes)
{
+ int ret;
struct stream_cipher *sc = para_malloc(sizeof(*sc));
- RC4_set_key(&sc->key, len, data);
+ struct aes_ctr_128_context *aes;
+
+ 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);
+ aes = &sc->context.aes;
+ ret = AES_set_encrypt_key(data, AES_CRT128_BLOCK_SIZE * 8 /* bits */,
+ &aes->key);
+ assert(ret == 0);
+ memcpy(aes->ivec, data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE);
+ aes->num = 0;
return sc;
}
-/**
- * Deallocate a stream cipher structure.
- *
- * \param sc A stream cipher previously obtained by sc_new().
- */
void sc_free(struct stream_cipher *sc)
{
free(sc);
*/
#define RC4_ALIGN 8
-/**
- * Encrypt and send a buffer.
- *
- * \param scc The context.
- * \param buf The buffer to send.
- * \param len The size of \a buf in bytes.
- *
- * \return The return value of the underyling call to write_all().
- *
- * \sa \ref write_all(), RC4(3).
- */
-int sc_send_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t len)
+static void rc4_crypt(RC4_KEY *key, struct iovec *src, struct iovec *dst)
{
- int ret;
- unsigned char *tmp;
- static unsigned char remainder[RC4_ALIGN];
- size_t l1 = ROUND_DOWN(len, RC4_ALIGN), l2 = ROUND_UP(len, RC4_ALIGN);
-
- assert(len);
- tmp = para_malloc(l2);
- RC4(&scc->send->key, l1, (const unsigned char *)buf, tmp);
+ 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) {
- memcpy(remainder, buf + l1, len - l1);
- RC4(&scc->send->key, len - l1, remainder, tmp + l1);
+ unsigned char remainder[RC4_ALIGN] = "";
+ memcpy(remainder, src->iov_base + l1, len - l1);
+ RC4(key, len - l1, remainder, dst->iov_base + l1);
}
- ret = write_all(scc->fd, (char *)tmp, &len);
- free(tmp);
- return ret;
+ ((char *)dst->iov_base)[len] = '\0';
}
-/**
- * Receive a buffer and decrypt it.
- *
- * \param scc The context.
- * \param buf The buffer to write the decrypted data to.
- * \param size The size of \a buf.
- *
- * \return The number of bytes received on success, negative on errors, zero if
- * the peer has performed an orderly shutdown.
- *
- * \sa recv(2), RC4(3).
- */
-int sc_recv_bin_buffer(struct stream_cipher_context *scc, char *buf,
- size_t size)
+static void aes_ctr128_crypt(struct aes_ctr_128_context *aes, struct iovec *src,
+ struct iovec *dst)
{
- unsigned char *tmp = para_malloc(size);
- ssize_t ret = recv(scc->fd, tmp, size, 0);
-
- if (ret > 0)
- RC4(&scc->recv->key, ret, tmp, (unsigned char *)buf);
- else if (ret < 0)
- ret = -ERRNO_TO_PARA_ERROR(errno);
- free(tmp);
- return ret;
+ size_t len = src->iov_len;
+
+ *dst = (typeof(*dst)) {
+ /* Add one for the terminating zero byte. */
+ .iov_base = para_malloc(len + 1),
+ .iov_len = len
+ };
+ AES_ctr128_encrypt(src->iov_base, dst->iov_base, len,
+ &aes->key, aes->ivec, aes->ecount, &aes->num);
+ ((char *)dst->iov_base)[len] = '\0';
+}
+
+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);
}
-/**
- * Compute the hash of the given input data.
- *
- * \param data Pointer to the data to compute the hash value from.
- * \param len The length of \a data in bytes.
- * \param hash Result pointer.
- *
- * \a hash must point to an area at least \p HASH_SIZE bytes large.
- *
- * \sa sha(3), openssl(1).
- * */
void hash_function(const char *data, unsigned long len, unsigned char *hash)
{
SHA_CTX c;