-add ABE crypto module
authorSchanzenbach, Martin <mschanzenbach@posteo.de>
Sat, 8 Jul 2017 16:30:01 +0000 (18:30 +0200)
committerSchanzenbach, Martin <mschanzenbach@posteo.de>
Sat, 8 Jul 2017 16:30:01 +0000 (18:30 +0200)
configure.ac
src/include/gnunet_crypto_lib.h
src/util/Makefile.am
src/util/crypto_abe.c [new file with mode: 0644]
src/util/test_crypto_abe.c [new file with mode: 0644]

index c16fbdcbafde5aba2754b5f2960c3dcc9b99ee3f..30f5a823c72a3fdac124a565fd463524e063d80d 100644 (file)
@@ -440,6 +440,18 @@ AC_CHECK_LIB(ogg, ogg_stream_flush_fill,
         AM_CONDITIONAL(HAVE_OGG, false)
         ogg=0)
 
+PKG_CHECK_MODULES([ABE], [glib-2.0])
+# check for pbc library
+pbc=0
+AC_CHECK_HEADER([pbc/pbc.h],pbc=1)
+AM_CONDITIONAL(HAVE_PBC, [test "$pbc" = 1])
+if test "x$pbc" = x1
+then
+  AC_DEFINE([HAVE_PBC],[1],[Have pbc library])
+else
+  AC_DEFINE([HAVE_PBC],[0],[Lacking pbc library])
+fi
+
 
 
 gst=0
index 07cade0e30dc49016850d902fe3fda5b350764d4..6f2870c3725a599a830d1bf7d53f6cfe200acf04 100644 (file)
@@ -395,6 +395,11 @@ struct GNUNET_CRYPTO_PaillierCiphertext
   unsigned char bits[GNUNET_CRYPTO_PAILLIER_BITS * 2 / 8];
 };
 
+/**
+ * @brief type for ABE master keys
+ */
+struct GNUNET_CRYPTO_AbeMasterKey;
+
 
 /* **************** Functions and Macros ************* */
 
@@ -2125,6 +2130,64 @@ GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash,
                          const struct GNUNET_CRYPTO_RsaPublicKey *public_key);
 
 
+/**
+ * @ingroup crypto
+ * Create a new CP-ABE master key. Caller must free return value.
+ *
+ * @return fresh private key; free using #GNUNET_free
+ */
+struct GNUNET_CRYPTO_AbeMasterKey *
+GNUNET_CRYPTO_cpabe_create_master_key (void);
+
+/**
+ * @ingroup crypto
+ * Create a new CP-ABE key. Caller must free return value.
+ *
+ * @return fresh private key; free using #GNUNET_free
+ */
+struct GNUNET_CRYPTO_AbeKey *
+GNUNET_CRYPTO_cpabe_create_key (struct GNUNET_CRYPTO_AbeMasterKey *msk,
+                                char **attrs);
+
+
+/**
+ * @ingroup crypto
+ * Encrypt a block using  sessionkey.
+ *
+ * @param block the block to encrypt
+ * @param size the size of the @a block
+ * @param sessionkey the key used to encrypt
+ * @param iv the initialization vector to use, use INITVALUE
+ *        for streams.
+ * @return the size of the encrypted block, -1 for errors
+ */
+ssize_t
+GNUNET_CRYPTO_cpabe_encrypt (const void *block,
+                             size_t size,
+                             char *policy,
+                             const struct GNUNET_CRYPTO_AbeMasterKey *key,
+                             void **result);
+
+/**
+ * @ingroup crypto
+ * Encrypt a block using  sessionkey.
+ *
+ * @param block the block to encrypt
+ * @param size the size of the @a block
+ * @param sessionkey the key used to encrypt
+ * @param iv the initialization vector to use, use INITVALUE
+ *        for streams.
+ * @return the size of the encrypted block, -1 for errors
+ */
+ssize_t
+GNUNET_CRYPTO_cpabe_decrypt (const void *block,
+                             size_t size,
+                             const struct GNUNET_CRYPTO_AbeKey *key,
+                             void **result);
+
+
+
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif
index 9be572bb65444ab64f22e1cf7d7a60e43b71c92d..4b1e4450347fa7ea215795ca5ec7f571478256eb 100644 (file)
@@ -87,6 +87,7 @@ libgnunetutil_la_SOURCES = \
   crypto_paillier.c \
   crypto_random.c \
   crypto_rsa.c \
+  crypto_abe.c \
   disk.c \
   disk.h \
   getopt.c \
@@ -117,12 +118,20 @@ libgnunetutil_la_LIBADD = \
   $(LIBGCRYPT_LIBS) \
   $(LTLIBICONV) \
   $(LTLIBINTL) \
+       $(ABE_LIBADD) \
+       -lbswabe \
+       -lssl \
+       -lpbc \
+       -lglib-2.0 \
   -lltdl $(Z_LIBS) -lunistring $(XLIB)
 
 libgnunetutil_la_LDFLAGS = \
   $(GN_LIB_LDFLAGS) \
+       $(ABE_LDADD) \
   -version-info 13:0:0
 
+libgnunetutil_la_CFLAGS = \
+  $(ABE_CFLAGS)
 
 libgnunetutil_taler_wallet_la_SOURCES = \
   common_allocation.c \
@@ -274,6 +283,7 @@ check_PROGRAMS = \
  test_container_multipeermap \
  test_container_heap \
  test_crypto_symmetric \
+ test_crypto_abe \
  test_crypto_crc \
  test_crypto_ecdsa \
  test_crypto_eddsa \
@@ -406,6 +416,11 @@ test_crypto_symmetric_SOURCES = \
 test_crypto_symmetric_LDADD = \
  libgnunetutil.la
 
+test_crypto_abe_SOURCES = \
+ test_crypto_abe.c
+test_crypto_abe_LDADD = \
+ libgnunetutil.la
+
 test_crypto_crc_SOURCES = \
  test_crypto_crc.c
 test_crypto_crc_LDADD = \
diff --git a/src/util/crypto_abe.c b/src/util/crypto_abe.c
new file mode 100644 (file)
index 0000000..d004220
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+     This file is part of GNUnet.  Copyright (C) 2001-2014 Christian Grothoff
+     (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet 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
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+
+*/
+
+/**
+ * @file util/crypto_random.c
+ * @brief functions to gather random numbers
+ * @author Christian Grothoff
+ */
+
+
+#include "platform.h"
+#include <glib.h>
+#include <openssl/aes.h>
+#include <openssl/sha.h>
+#include <pbc/pbc.h>
+#include <bswabe.h>
+
+#include "gnunet_crypto_lib.h"
+
+struct GNUNET_CRYPTO_AbeMasterKey
+{
+  GByteArray* pub;
+
+  GByteArray* msk;
+};
+
+struct GNUNET_CRYPTO_AbeKey
+{
+  GByteArray* pub;
+  GByteArray* prv;
+};
+
+static void
+init_aes( element_t k, int enc, AES_KEY* key, unsigned char* iv )
+{
+  int key_len;
+  unsigned char* key_buf;
+
+  key_len = element_length_in_bytes(k) < 17 ? 17 : element_length_in_bytes(k);
+  key_buf = (unsigned char*) malloc(key_len);
+  element_to_bytes(key_buf, k);
+
+  if( enc )
+    AES_set_encrypt_key(key_buf + 1, 128, key);
+  else
+    AES_set_decrypt_key(key_buf + 1, 128, key);
+  free(key_buf);
+
+  memset(iv, 0, 16);
+}
+
+static GByteArray*
+aes_128_cbc_encrypt( GByteArray* pt, element_t k )
+{
+  AES_KEY key;
+  unsigned char iv[16];
+  GByteArray* ct;
+  guint8 len[4];
+  guint8 zero;
+
+  init_aes(k, 1, &key, iv);
+
+  /* TODO make less crufty */
+
+  /* stuff in real length (big endian) before padding */
+  len[0] = (pt->len & 0xff000000)>>24;
+  len[1] = (pt->len & 0xff0000)>>16;
+  len[2] = (pt->len & 0xff00)>>8;
+  len[3] = (pt->len & 0xff)>>0;
+  g_byte_array_prepend(pt, len, 4);
+
+  /* pad out to multiple of 128 bit (16 byte) blocks */
+  zero = 0;
+  while( pt->len % 16 )
+    g_byte_array_append(pt, &zero, 1);
+
+  ct = g_byte_array_new();
+  g_byte_array_set_size(ct, pt->len);
+
+  AES_cbc_encrypt(pt->data, ct->data, pt->len, &key, iv, AES_ENCRYPT);
+
+  return ct;
+}
+
+static GByteArray*
+aes_128_cbc_decrypt( GByteArray* ct, element_t k )
+{
+  AES_KEY key;
+  unsigned char iv[16];
+  GByteArray* pt;
+  unsigned int len;
+
+  init_aes(k, 0, &key, iv);
+
+  pt = g_byte_array_new();
+  g_byte_array_set_size(pt, ct->len);
+
+  AES_cbc_encrypt(ct->data, pt->data, ct->len, &key, iv, AES_DECRYPT);
+
+  /* TODO make less crufty */
+  
+  /* get real length */
+  len = 0;
+  len = len
+    | ((pt->data[0])<<24) | ((pt->data[1])<<16)
+    | ((pt->data[2])<<8)  | ((pt->data[3])<<0);
+  g_byte_array_remove_index(pt, 0);
+  g_byte_array_remove_index(pt, 0);
+  g_byte_array_remove_index(pt, 0);
+  g_byte_array_remove_index(pt, 0);
+
+  /* truncate any garbage from the padding */
+  g_byte_array_set_size(pt, len);
+
+  return pt;
+}
+
+struct GNUNET_CRYPTO_AbeMasterKey*
+GNUNET_CRYPTO_cpabe_create_master_key (void)
+{
+  struct GNUNET_CRYPTO_AbeMasterKey* key;
+  bswabe_msk_t* msk;
+  bswabe_pub_t* pub;
+  bswabe_setup(&pub, &msk);
+  key = GNUNET_new (struct GNUNET_CRYPTO_AbeMasterKey);
+  key->pub = bswabe_pub_serialize(pub);
+  key->msk = bswabe_msk_serialize(msk);
+  GNUNET_assert (NULL != key->pub);
+  GNUNET_assert (NULL != key->msk);
+  return key;
+}
+
+struct GNUNET_CRYPTO_AbeKey*
+GNUNET_CRYPTO_cpabe_create_key (struct GNUNET_CRYPTO_AbeMasterKey *key,
+                             char **attrs)
+{
+  struct GNUNET_CRYPTO_AbeKey *prv_key;
+  bswabe_pub_t* pub;
+  bswabe_msk_t* msk;
+  bswabe_prv_t* prv;
+  gchar* pub_data;
+  gsize len;
+
+  pub = bswabe_pub_unserialize(key->pub, 0);
+  msk = bswabe_msk_unserialize(pub, key->msk, 0);
+  prv = bswabe_keygen(pub, msk, attrs);
+  prv_key = GNUNET_new (struct GNUNET_CRYPTO_AbeKey);
+  prv_key->prv = bswabe_prv_serialize(prv);
+  pub_data = g_strndup ((gchar*)key->pub->data,
+                        key->pub->len);
+  len = key->pub->len;
+  prv_key->pub = g_byte_array_new_take ((guint8*)pub_data, len);
+  GNUNET_assert (NULL != prv_key->prv);
+  return prv_key;
+}
+
+ssize_t
+write_cpabe (void **result, GByteArray* cph_buf,
+             int file_len, GByteArray* aes_buf)
+{
+  char *ptr;
+  int i;
+  ssize_t size;
+  size = aes_buf->len + cph_buf->len + 12;
+  *result = GNUNET_malloc (size);
+  ptr = *result;
+  for(i=3; i >= 0; i--) {
+    *ptr = (file_len & 0xff<<(i*8))>>(i*8);
+    ptr++;
+  }
+  for(i=3; i >= 0; i--) {
+    *ptr = (aes_buf->len & 0xff<<(i*8))>>(i*8);
+    ptr++;
+  }
+  memcpy (ptr, aes_buf->data, aes_buf->len);
+  ptr += aes_buf->len;
+  for(i=3; i >= 0; i--) {
+    *ptr = (cph_buf->len & 0xff<<(i*8))>>(i*8);
+    ptr++;
+  }
+  memcpy (ptr, cph_buf->data, cph_buf->len);
+  return size;
+}
+
+ssize_t
+read_cpabe (const void *data, GByteArray** cph_buf, GByteArray** aes_buf)
+{
+  int i;
+  ssize_t buf_len;
+  ssize_t tmp_len;
+  char *ptr;
+
+  *cph_buf = g_byte_array_new();
+  *aes_buf = g_byte_array_new();
+  ptr = (char*)data;
+
+  buf_len = 0;
+  for(i=3; i >= 0; i--) {
+    buf_len |= *ptr<<(i*8);
+    ptr++;
+  }
+
+  tmp_len = 0;
+  for(i=3; i >= 0; i--) {
+    tmp_len |= *ptr<<(i*8);
+    ptr++;
+  }
+  g_byte_array_set_size(*aes_buf, tmp_len);
+  memcpy((*aes_buf)->data, ptr, tmp_len);
+  ptr += tmp_len;
+  tmp_len = 0;
+  for(i=3; i >= 0; i--) {
+    tmp_len |= *ptr<<(i*8);
+    ptr++;
+  }
+  g_byte_array_set_size(*cph_buf, tmp_len);
+  memcpy((*cph_buf)->data, ptr, tmp_len);
+
+  return buf_len;
+}
+
+ssize_t
+GNUNET_CRYPTO_cpabe_encrypt (const void *block,
+                             size_t size,
+                             char *policy,
+                             const struct GNUNET_CRYPTO_AbeMasterKey *key,
+                             void **result)
+{
+  bswabe_pub_t* pub;
+  bswabe_cph_t* cph;
+  GByteArray* plt;
+  GByteArray* cph_buf;
+  GByteArray* aes_buf;
+  guint8 *data;
+  element_t m;
+  size_t payload_len;
+  ssize_t result_len;
+  pub = bswabe_pub_unserialize(key->pub, 0);
+  if( !(cph = bswabe_enc(pub, m, policy)) )
+    return GNUNET_SYSERR;
+  cph_buf = bswabe_cph_serialize(cph);
+  bswabe_cph_free(cph);
+  data = g_memdup (block, size);
+  plt = g_byte_array_new_take (data, size);
+  payload_len = plt->len;
+  aes_buf = aes_128_cbc_encrypt(plt, m);
+  g_byte_array_free(plt, 1);
+  element_clear(m);
+  result_len = write_cpabe(result, cph_buf, payload_len, aes_buf);
+  g_byte_array_free(cph_buf, 1);
+  g_byte_array_free(aes_buf, 1);
+  return result_len;
+}
+
+ssize_t
+GNUNET_CRYPTO_cpabe_decrypt (const void *block,
+                       size_t size,
+                       const struct GNUNET_CRYPTO_AbeKey *key,
+                       void **result)
+{
+  bswabe_pub_t* pub;
+  bswabe_prv_t* prv;
+  GByteArray* aes_buf;
+  GByteArray* plt;
+  GByteArray* cph_buf;
+  bswabe_cph_t* cph;
+  element_t m;
+  ssize_t pt_size;
+
+  pub = bswabe_pub_unserialize(key->pub, 0);
+  prv = bswabe_prv_unserialize(pub, key->prv, 0);
+  pt_size = read_cpabe(block, &cph_buf, &aes_buf);
+  cph = bswabe_cph_unserialize(pub, cph_buf, 0);
+  if( !bswabe_dec(pub, prv, cph, m) ) {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "%s\n", bswabe_error());
+    return GNUNET_SYSERR;
+  }
+  bswabe_cph_free(cph);
+  plt = aes_128_cbc_decrypt(aes_buf, m);
+  g_byte_array_set_size(plt, size);
+  g_byte_array_free(aes_buf, 1);
+  *result = GNUNET_malloc (plt->len);
+  GNUNET_memcpy (*result, plt->data, plt->len);
+  
+  return pt_size;
+}
diff --git a/src/util/test_crypto_abe.c b/src/util/test_crypto_abe.c
new file mode 100644 (file)
index 0000000..cb36dcc
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2002, 2003, 2004, 2006 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet 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
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+
+*/
+/**
+ * @author Martin Schanzenbach
+ * @file util/test_crypto_abe.c
+ * @brief test for ABE ciphers
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#define TESTSTRING "Hello World!"
+
+static int
+testAbecipher ()
+{
+  struct GNUNET_CRYPTO_AbeMasterKey *msk;
+  struct GNUNET_CRYPTO_AbeKey *key;
+  char *result;
+  char **attrs;
+  int size;
+  char *res;
+  msk = GNUNET_CRYPTO_cpabe_create_master_key ();
+  size = GNUNET_CRYPTO_cpabe_encrypt (TESTSTRING, strlen (TESTSTRING) + 1,
+                                      "testattr", //Policy
+                                      msk,
+                                      (void*)&result);
+  GNUNET_assert (-1 != size);
+  attrs = GNUNET_malloc (2 * sizeof (char*));
+  attrs[0] = "testattr";
+  attrs[1] = NULL;
+  key = GNUNET_CRYPTO_cpabe_create_key (msk,
+                                        attrs);
+
+  size = GNUNET_CRYPTO_cpabe_decrypt (result, size,
+                                      key,
+                                      (void*)&res);
+  if (strlen (TESTSTRING) + 1 != size)
+  {
+    printf ("abeciphertest failed: decryptBlock returned %d\n", size);
+    return 1;
+  }
+  if (0 != strcmp (res, TESTSTRING))
+  {
+    printf ("abeciphertest failed: %s != %s\n", res, TESTSTRING);
+    return 1;
+  }
+  else
+    return 0;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int failureCount = 0;
+
+  GNUNET_log_setup ("test-crypto-abe", "WARNING", NULL);
+  failureCount += testAbecipher ();
+
+  if (failureCount != 0)
+  {
+    printf ("%d TESTS FAILED!\n", failureCount);
+    return -1;
+  }
+  return 0;
+}
+
+/* end of test_crypto_aes.c */