/**
* collectd - src/libcollectdclient/network_buffer.c
- * Copyright (C) 2010 Florian octo Forster
+ * Copyright (C) 2010-2012 Florian octo Forster
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; only version 2.1 of the License is
- * applicable.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
*
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
*
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
**/
#include "config.h"
#define TYPE_ENCR_AES256 0x0210
#define PART_SIGNATURE_SHA256_SIZE 36
+#define PART_ENCRYPTION_AES256_SIZE 42
+
+#define ADD_GENERIC(nb,srcptr,size) do { \
+ assert ((size) <= (nb)->free); \
+ memcpy ((nb)->ptr, (srcptr), (size)); \
+ (nb)->ptr += (size); \
+ (nb)->free -= (size); \
+} while (0)
+
+#define ADD_STATIC(nb,var) \
+ ADD_GENERIC(nb,&(var),sizeof(var));
/*
* Data types
lcc_security_level_t seclevel;
char *username;
char *password;
+
+ gcry_cipher_hd_t encr_cypher;
+ size_t encr_header_len;
+ char encr_iv[16];
};
#define SSTRNCPY(dst,src,sz) do { \
return (0);
} /* }}} int nb_add_signature */
+static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
+{
+ size_t package_length;
+ char *encr_ptr; /* pointer to data being encrypted */
+ size_t encr_size;
+
+ char *hash_ptr; /* pointer to data being hashed */
+ size_t hash_size;
+ char hash[20];
+
+ uint16_t pkg_length;
+ gcry_error_t err;
+
+ /* Fill in the package length */
+ package_length = nb->size - nb->free;
+ pkg_length = htons ((uint16_t) package_length);
+ memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
+
+ /* Calculate what to hash */
+ hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
+ hash_size = package_length - nb->encr_header_len;
+
+ /* Calculate what to encrypt */
+ encr_ptr = hash_ptr - sizeof (hash);
+ encr_size = hash_size + sizeof (hash);
+
+ /* Calculate the SHA-1 hash */
+ gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
+ memcpy (encr_ptr, hash, sizeof (hash));
+
+ if (nb->encr_cypher == NULL)
+ {
+ unsigned char password_hash[32];
+
+ err = gcry_cipher_open (&nb->encr_cypher,
+ GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
+ if (err != 0)
+ return (-1);
+
+ /* Calculate our 256bit key used for AES */
+ gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
+ nb->password, strlen (nb->password));
+
+ err = gcry_cipher_setkey (nb->encr_cypher,
+ password_hash, sizeof (password_hash));
+ if (err != 0)
+ {
+ gcry_cipher_close (nb->encr_cypher);
+ nb->encr_cypher = NULL;
+ return (-1);
+ }
+ }
+ else /* if (nb->encr_cypher != NULL) */
+ {
+ gcry_cipher_reset (nb->encr_cypher);
+ }
+
+ /* Set the initialization vector */
+ err = gcry_cipher_setiv (nb->encr_cypher,
+ nb->encr_iv, sizeof (nb->encr_iv));
+ if (err != 0)
+ {
+ gcry_cipher_close (nb->encr_cypher);
+ nb->encr_cypher = NULL;
+ return (-1);
+ }
+
+ /* Encrypt the buffer in-place */
+ err = gcry_cipher_encrypt (nb->encr_cypher,
+ encr_ptr, encr_size,
+ /* in = */ NULL, /* in len = */ 0);
+ if (err != 0)
+ {
+ gcry_cipher_close (nb->encr_cypher);
+ nb->encr_cypher = NULL;
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int nb_add_encryption */
+
/*
* Public functions
*/
nb->ptr += username_len;
nb->free -= username_len;
}
-
- /* FIXME: If security is enabled, reserve space for the signature /
- * encryption block here. */
+ else if (nb->seclevel == ENCRYPT)
+ {
+ size_t username_length = strlen (nb->username);
+ uint16_t pkg_type = htons (TYPE_ENCR_AES256);
+ uint16_t pkg_length = 0; /* Filled in in finalize. */
+ uint16_t pkg_user_len = htons ((uint16_t) username_length);
+ char hash[20];
+
+ nb->encr_header_len = username_length;
+ nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
+
+ gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
+ GCRY_STRONG_RANDOM);
+
+ /* Filled in in finalize. */
+ memset (hash, 0, sizeof (hash));
+
+ ADD_STATIC (nb, pkg_type);
+ ADD_STATIC (nb, pkg_length);
+ ADD_STATIC (nb, pkg_user_len);
+ ADD_GENERIC (nb, nb->username, username_length);
+ ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
+ ADD_GENERIC (nb, hash, sizeof (hash));
+ assert ((nb->encr_header_len + nb->free) == nb->size);
+ }
return (0);
} /* }}} int lcc_network_buffer_initialize */
if (nb->seclevel == SIGN)
nb_add_signature (nb);
- /* FIXME: If security is enabled, sign or encrypt the packet here. */
+ else if (nb->seclevel == ENCRYPT)
+ nb_add_encryption (nb);
return (0);
} /* }}} int lcc_network_buffer_finalize */