X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=crypt.c;h=8116fb6eeacdbeaa0f1f22d14cfcc3726ee3bbbf;hb=refs%2Fheads%2Fmaint;hp=f1e42d4a228f7c0c498ac505575b6a0f3667bf27;hpb=bd28ec9a64884d70917c4fdea1a3a70c91758f83;p=paraslash.git diff --git a/crypt.c b/crypt.c deleted file mode 100644 index f1e42d4a..00000000 --- a/crypt.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (C) 2005 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ - -/** \file crypt.c Openssl-based encryption/decryption routines. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "para.h" -#include "error.h" -#include "string.h" -#include "crypt.h" -#include "fd.h" -#include "crypt_backend.h" -#include "base64.h" - -struct asymmetric_key { - RSA *rsa; -}; - -void get_random_bytes_or_die(unsigned char *buf, int num) -{ - unsigned long err; - - /* RAND_bytes() returns 1 on success, 0 otherwise. */ - if (RAND_bytes(buf, num) == 1) - return; - err = ERR_get_error(); - PARA_EMERG_LOG("%s\n", ERR_reason_error_string(err)); - exit(EXIT_FAILURE); -} - -/* - * 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(). - */ -void init_random_seed_or_die(void) -{ - int seed, ret = RAND_load_file("/dev/urandom", 64); - - if (ret != 64) { - PARA_EMERG_LOG("could not seed PRNG (ret = %d)\n", ret); - exit(EXIT_FAILURE); - } - get_random_bytes_or_die((unsigned char *)&seed, sizeof(seed)); - srandom(seed); -} - -static int get_private_key(const char *path, RSA **rsa) -{ - EVP_PKEY *pkey; - BIO *bio = BIO_new(BIO_s_file()); - - *rsa = NULL; - if (!bio) - return -E_PRIVATE_KEY; - if (BIO_read_filename(bio, path) <= 0) - goto bio_free; - pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - if (!pkey) - goto bio_free; - *rsa = EVP_PKEY_get1_RSA(pkey); - EVP_PKEY_free(pkey); -bio_free: - BIO_free(bio); - return *rsa? RSA_size(*rsa) : -E_PRIVATE_KEY; -} - -/* - * The public key loading functions below were inspired by corresponding code - * of openssh-5.2p1, Copyright (c) 1995 Tatu Ylonen , Espoo, - * Finland. However, not much of the original code remains. - */ - -static int read_bignum(const unsigned char *buf, size_t len, BIGNUM **result) -{ - const unsigned char *p = buf, *end = buf + len; - uint32_t bnsize; - BIGNUM *bn; - - if (p + 4 < p) - return -E_BIGNUM; - if (p + 4 > end) - return -E_BIGNUM; - bnsize = read_ssh_u32(p); - PARA_DEBUG_LOG("bnsize: %u\n", bnsize); - p += 4; - if (p + bnsize < p) - return -E_BIGNUM; - if (p + bnsize > end) - return -E_BIGNUM; - if (bnsize > 8192) - return -E_BIGNUM; - bn = BN_bin2bn(p, bnsize, NULL); - if (!bn) - return -E_BIGNUM; - *result = bn; - return bnsize + 4; -} - -static int read_rsa_bignums(const unsigned char *blob, int blen, RSA **result) -{ - int ret; - RSA *rsa; - BIGNUM *n, *e; - const unsigned char *p = blob, *end = blob + blen; - - rsa = RSA_new(); - if (!rsa) - return -E_BIGNUM; - ret = read_bignum(p, end - p, &e); - if (ret < 0) - goto fail; - p += ret; - ret = read_bignum(p, end - p, &n); - if (ret < 0) - goto fail; -#ifdef HAVE_RSA_SET0_KEY - RSA_set0_key(rsa, n, e, NULL); -#else - rsa->n = n; - rsa->e = e; -#endif - *result = rsa; - return 1; -fail: - RSA_free(rsa); - return ret; -} - -int get_public_key(const char *key_file, struct asymmetric_key **result) -{ - struct asymmetric_key *key = NULL; - void *map = NULL; - unsigned char *blob = NULL; - size_t map_size, encoded_size, decoded_size; - int ret, ret2; - char *cp; - - key = para_malloc(sizeof(*key)); - ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL); - if (ret < 0) - goto out; - ret = is_ssh_rsa_key(map, map_size); - if (!ret) { - para_munmap(map, map_size); - return -E_SSH_PARSE; - } - cp = map + ret; - encoded_size = map_size - ret; - PARA_INFO_LOG("decoding public rsa-ssh key %s\n", key_file); - ret = uudecode(cp, encoded_size, (char **)&blob, &decoded_size); - if (ret < 0) - goto out_unmap; - ret = check_ssh_key_header(blob, decoded_size); - if (ret < 0) - goto out_unmap; - ret = read_rsa_bignums(blob + ret, decoded_size - ret, &key->rsa); - if (ret < 0) - goto out_unmap; - ret = RSA_size(key->rsa); -out_unmap: - ret2 = para_munmap(map, map_size); - if (ret >= 0 && ret2 < 0) - ret = ret2; -out: - if (ret < 0) { - free(key); - *result = NULL; - PARA_ERROR_LOG("key %s: %s\n", key_file, para_strerror(-ret)); - } else - *result = key; - free(blob); - return ret; -} - -void free_public_key(struct asymmetric_key *key) -{ - if (!key) - return; - RSA_free(key->rsa); - free(key); -} - -int priv_decrypt(const char *key_file, unsigned char *outbuf, - unsigned char *inbuf, int inlen) -{ - struct asymmetric_key *priv; - int ret; - - ret = check_private_key_file(key_file); - if (ret < 0) - return ret; - if (inlen < 0) - return -E_RSA; - priv = para_malloc(sizeof(*priv)); - ret = get_private_key(key_file, &priv->rsa); - if (ret < 0) { - free(priv); - return ret; - } - /* - * RSA is vulnerable to timing attacks. Generate a random blinding - * factor to protect against this kind of attack. - */ - ret = -E_BLINDING; - if (RSA_blinding_on(priv->rsa, NULL) == 0) - goto out; - ret = RSA_private_decrypt(inlen, inbuf, outbuf, priv->rsa, - RSA_PKCS1_OAEP_PADDING); - RSA_blinding_off(priv->rsa); - if (ret <= 0) - ret = -E_DECRYPT; -out: - RSA_free(priv->rsa); - free(priv); - return ret; -} - -int pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf, - unsigned len, unsigned char *outbuf) -{ - int ret, flen = len; /* RSA_public_encrypt expects a signed int */ - - if (flen < 0) - return -E_ENCRYPT; - ret = RSA_public_encrypt(flen, inbuf, outbuf, pub->rsa, - RSA_PKCS1_OAEP_PADDING); - return ret < 0? -E_ENCRYPT : ret; -} - -struct stream_cipher { - EVP_CIPHER_CTX *aes; -}; - -struct stream_cipher *sc_new(const unsigned char *data, int len) -{ - struct stream_cipher *sc = para_malloc(sizeof(*sc)); - - assert(len >= 2 * AES_CRT128_BLOCK_SIZE); - sc->aes = EVP_CIPHER_CTX_new(); - EVP_EncryptInit_ex(sc->aes, EVP_aes_128_ctr(), NULL, data, - data + AES_CRT128_BLOCK_SIZE); - return sc; -} - -void sc_free(struct stream_cipher *sc) -{ - if (!sc) - return; - EVP_CIPHER_CTX_free(sc->aes); - free(sc); -} - -static void aes_ctr128_crypt(EVP_CIPHER_CTX *ctx, struct iovec *src, - struct iovec *dst) -{ - int ret, inlen = src->iov_len, outlen, tmplen; - - *dst = (typeof(*dst)) { - /* Add one for the terminating zero byte. */ - .iov_base = para_malloc(inlen + 1), - .iov_len = inlen - }; - ret = EVP_EncryptUpdate(ctx, dst->iov_base, &outlen, src->iov_base, inlen); - assert(ret != 0); - ret = EVP_EncryptFinal_ex(ctx, dst->iov_base + outlen, &tmplen); - assert(ret != 0); - outlen += tmplen; - ((char *)dst->iov_base)[outlen] = '\0'; - dst->iov_len = outlen; -} - -void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst) -{ - return aes_ctr128_crypt(sc->aes, src, dst); -} - -void hash_function(const char *data, unsigned long len, unsigned char *hash) -{ - SHA_CTX c; - SHA1_Init(&c); - SHA1_Update(&c, data, len); - SHA1_Final(hash, &c); -}