[Gluster-devel] [PATCH BUG:393 07/10] transport/encryption: add NaCl encryptor

Corentin Chary corentin.chary at gmail.com
Wed Nov 18 11:13:59 UTC 2009


This encryption plugin is based on libnacl
<http://nacl.cace-project.eu/secretbox.html> and use
crypto_secrebox/crypto_secretbox_open.

Currently libnacl doesn't provide any shared library, to
we need to link against libnacl.a. This may not work on
x86_64, to fix that :
- add -fPIC to okcompilers/c
- move the content of crypto_onetimeauth/poly1305/amd64/constants.s
  to crypto_onetimeauth/poly1305/amd64/auth.s

To enable NaCl on configure:
./configure --enable-nacl=yes --with-nacl-dir=/path/to/nacl/build/localhost

Signed-off-by: Corentin Chary <corentin.chary at gmail.com>
---
 configure.ac                              |   68 +++++++-
 libglusterfs/src/protocol.h               |    9 +
 transport/encryption/Makefile.am          |    2 +-
 transport/encryption/nacl/Makefile.am     |    1 +
 transport/encryption/nacl/src/Makefile.am |   16 ++
 transport/encryption/nacl/src/nacl.c      |  275 +++++++++++++++++++++++++++++
 transport/encryption/nacl/src/nacl.h      |   39 ++++
 7 files changed, 407 insertions(+), 3 deletions(-)
 create mode 100644 transport/encryption/nacl/Makefile.am
 create mode 100644 transport/encryption/nacl/src/Makefile.am
 create mode 100644 transport/encryption/nacl/src/nacl.c
 create mode 100644 transport/encryption/nacl/src/nacl.h

diff --git a/configure.ac b/configure.ac
index ef455fd..2e318b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -112,6 +112,8 @@ AC_CONFIG_FILES([Makefile
 		transport/ib-verbs/Makefile
 		transport/ib-verbs/src/Makefile
 		transport/encryption/Makefile
+		transport/encryption/nacl/Makefile
+		transport/encryption/nacl/src/Makefile
 		auth/Makefile
 		auth/addr/Makefile
 		auth/addr/src/Makefile
@@ -163,7 +165,7 @@ fi
 AC_CHECK_TOOL([LD],[ld])
 
 AC_CHECK_LIB([pthread], [pthread_mutex_init], , AC_MSG_ERROR([Posix threads library is required to build glusterfs]))
-		 
+
 AC_CHECK_FUNC([dlopen], [has_dlopen=yes], AC_CHECK_LIB([dl], [dlopen], , AC_MSG_ERROR([Dynamic linking library required to build glusterfs])))
 
 
@@ -244,6 +246,67 @@ fi
 AC_SUBST(FUSERMOUNT_SUBDIR)
 #end FUSERMOUNT section
 
+# OPENSSL section
+AC_CHECK_LIB([ssl], [EVP_BytesToKey], [HAVE_OPENSSL="yes"], [HAVE_OPENSSL="no"])
+
+if test "x$HAVE_OPENSSL" = "xyes"; then
+   AC_DEFINE(HAVE_OPENSSL, 1, [found EVP_BytesToKey])
+fi
+# end OPENSSL section
+
+# NACL section
+nacl_arch="unknown"
+case $host_cpu in
+  i*86)   nacl_arch="x86";;
+  x86_64) nacl_arch="amd64";;
+  amd64) nacl_arch="amd64";;
+esac
+
+AC_ARG_ENABLE([nacl],
+	      AC_HELP_STRING([--disable-nacl],
+			     [Do not build the ibverbs transport]))
+AC_ARG_WITH(nacl-dir,
+            [  --with-nacl-dir=DIR nacl installed in DIR @<:@/usr@:>@],
+            [nacl_dir=$withval],
+            [nacl_dir='/usr'])
+
+if test x"$use_nacl" != "xno" -a x"$nacl_arch" = "xunknown" ; then
+   echo "nacl requested but $host_cpu CPU not supported."
+   exit 1
+fi
+
+if test "x$enable_nacl" != "xno" -a "x$HAVE_OPENSSL" = "xyes"; then
+    if test "x$nacl_dir" != "x"; then
+       LDFLAGS="$LDFLAGS -L$nacl_dir/lib/$nacl_arch"
+       AC_CHECK_HEADERS([$nacl_dir/include/$nacl_arch/crypto_secretbox.h])
+    else
+       AC_CHECK_HEADERS([crypto_secretbox.h])
+    fi
+    AC_CHECK_LIB([nacl], [crypto_nacl_base], [HAVE_NACL="yes"], [HAVE_NACL="no"])
+fi
+
+if test "x$enable_nacl" != "xno" -a "x$HAVE_NACL" = "xno"; then
+   echo "nacl requested but not found."
+   exit 1
+fi
+
+BUILD_NACL=no
+if test "x$enable_nacl" != "xno" -a "x$HAVE_NACL" = "xyes"; then
+  NACL_SUBDIR=nacl
+  BUILD_NACL=yes
+  NACL_LIBDIR=${nacl_dir}/lib/${nacl_arch}
+  NACL_INCDIR=${nacl_dir}/include/${nacl_arch}
+  NACL_LDADD=${NACL_LIBDIR}/libnacl.a
+fi
+AC_SUBST(NACL_SUBDIR)
+AC_SUBST(NACL_LIBDIR)
+AC_SUBST(NACL_INCDIR)
+AC_SUBST(NACL_LDADD)
+
+if test "x$HAVE_NACL" = "xyes"; then
+   AC_DEFINE(HAVE_NACL, 1, [found NaCl])
+fi
+# end NACL section
 
 # EPOLL section
 AC_ARG_ENABLE([epoll],
@@ -455,7 +518,7 @@ case $host_os in
 	GF_LDADD="${ARGP_STANDALONE_LDADD}"
 	if test "x$ac_cv_header_execinfo_h" = "xyes"; then
 	   GF_GLUSTERFS_LDFLAGS="-lexecinfo"
-	fi				      
+	fi
 	GF_FUSE_LDADD="-liconv -lfuse"
 	BUILD_LIBGLUSTERFSCLIENT=no
 	LIBGLUSTERFSCLIENT_SUBDIR=""
@@ -495,6 +558,7 @@ echo "GlusterFS configure summary"
 echo "==========================="
 echo "FUSE client        : $BUILD_FUSE_CLIENT"
 echo "Infiniband verbs   : $BUILD_IBVERBS"
+echo "NaCl encryption    : $BUILD_NACL"
 echo "epoll IO multiplex : $BUILD_EPOLL"
 echo "Berkeley-DB        : $BUILD_BDB"
 echo "libglusterfsclient : $BUILD_LIBGLUSTERFSCLIENT"
diff --git a/libglusterfs/src/protocol.h b/libglusterfs/src/protocol.h
index 2341ec8..fe0e420 100644
--- a/libglusterfs/src/protocol.h
+++ b/libglusterfs/src/protocol.h
@@ -964,12 +964,21 @@ typedef struct {
 } __attribute__ ((packed)) gf_hdr_rsp_t;
 
 typedef struct {
+	char nonce[32];
+	char crypto_hdr[32];
+	char crypto_vec[32];
+} __attribute__ ((packed)) gf_hdr_nacl_t;
+
+typedef struct {
 	uint64_t callid;
 	uint32_t type;
 	uint32_t op;
 	uint32_t size;
 	uint32_t crypto;
 	union {
+		gf_hdr_nacl_t nacl;
+	} __attribute__ ((packed));
+	union {
 		gf_hdr_req_t req;
 		gf_hdr_rsp_t rsp;
 	} __attribute__ ((packed));
diff --git a/transport/encryption/Makefile.am b/transport/encryption/Makefile.am
index e182a87..cdff0ca 100644
--- a/transport/encryption/Makefile.am
+++ b/transport/encryption/Makefile.am
@@ -1,3 +1,3 @@
-SUBDIRS =
+SUBDIRS = $(NACL_SUBDIR)
 
 CLEANFILES =
diff --git a/transport/encryption/nacl/Makefile.am b/transport/encryption/nacl/Makefile.am
new file mode 100644
index 0000000..f963eff
--- /dev/null
+++ b/transport/encryption/nacl/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = src
\ No newline at end of file
diff --git a/transport/encryption/nacl/src/Makefile.am b/transport/encryption/nacl/src/Makefile.am
new file mode 100644
index 0000000..c6c171a
--- /dev/null
+++ b/transport/encryption/nacl/src/Makefile.am
@@ -0,0 +1,16 @@
+xlator_LTLIBRARIES = nacl.la
+xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/transport/encryption
+
+nacl_la_LDFLAGS = -module -avoidversion -lssl
+
+nacl_la_SOURCES = nacl.c
+nacl_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la ${NACL_LIBDIR}/libnacl.a
+
+noinst_HEADERS = nacl.h
+
+AM_CFLAGS =  -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS) \
+	-I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS) \
+	-I$(NACL_INCDIR)
+
+CLEANFILES =
+
diff --git a/transport/encryption/nacl/src/nacl.c b/transport/encryption/nacl/src/nacl.c
new file mode 100644
index 0000000..40f7e28
--- /dev/null
+++ b/transport/encryption/nacl/src/nacl.c
@@ -0,0 +1,275 @@
+/*
+  Copyright (c) 2009 commonIT
+  Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com>
+  This file is part of GlusterFS.
+
+  GlusterFS 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 of the License,
+  or (at your option) any later version.
+
+  GlusterFS 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 this program.  If not, see
+  <http://www.gnu.org/licenses/>.
+*/
+
+#include <ctype.h>
+#include <sys/uio.h>
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "glusterfs.h"
+#include "xlator.h"
+#include "transport.h"
+#include "logging.h"
+#include "protocol.h"
+#include "iobuf.h"
+
+#include "nacl.h"
+
+#include <openssl/evp.h>
+
+#define NACL_ZERO_BYTES		crypto_secretbox_ZEROBYTES
+#define NACL_NONCE_BYTES	crypto_secretbox_NONCEBYTES
+
+static char *
+nacl_alloc(transport_crypto_t *this, size_t len, struct iobuf **ref)
+{
+	if (len + NACL_ZERO_BYTES > GF_UNIT_MB) {
+		char *p = CALLOC (1, len + NACL_ZERO_BYTES);
+
+		if (!p)
+			return NULL;
+		return p;
+	} else {
+		*ref = iobuf_get (this->xl->ctx->iobuf_pool);
+		if (!*ref)
+			return NULL;
+		return (*ref)->ptr;
+	}
+}
+
+static void
+nacl_free(struct iobuf *iobuf, struct iobuf *ref, char *ptr)
+{
+	if (ref)
+		iobuf_unref (ref);
+	else if (!iobuf || ptr != iobuf->ptr)
+		FREE (ptr);
+}
+
+static char *
+nacl_join(transport_crypto_t *this, struct iobuf *iobuf,
+	  char *buf, size_t len, char *prefix, struct iobuf **iobuf_p)
+{
+	if (len + NACL_ZERO_BYTES > GF_UNIT_MB) {
+		char *p = nacl_alloc(this, len + NACL_ZERO_BYTES, NULL);
+
+		if (!p)
+			return NULL;
+		memcpy(p, prefix, NACL_ZERO_BYTES);
+		if (buf)
+			memcpy(p + NACL_ZERO_BYTES, buf, len);
+		else
+			memcpy(p + NACL_ZERO_BYTES, iobuf->ptr, len);
+		return p;
+	} else if (iobuf) {
+		memmove(iobuf->ptr + NACL_ZERO_BYTES, iobuf->ptr, len);
+		memcpy(iobuf->ptr, prefix, NACL_ZERO_BYTES);
+		return iobuf->ptr;
+	} else {
+		nacl_alloc(this, len, iobuf_p);
+		if (!*iobuf_p)
+			return NULL;
+		memcpy((*iobuf_p)->ptr, prefix, NACL_ZERO_BYTES);
+		memcpy((*iobuf_p)->ptr + NACL_ZERO_BYTES, buf, len);
+		return (*iobuf_p)->ptr;
+	}
+}
+static void
+nacl_split(struct iobuf *iobuf, char *buf, size_t len, char *prefix, char *p)
+{
+	memcpy(prefix, p, NACL_ZERO_BYTES);
+	if (iobuf)
+		/* memmove because p could be iobuf->ptr */
+		memmove(iobuf->ptr, p + NACL_ZERO_BYTES, len);
+        else
+		memcpy(buf, p + NACL_ZERO_BYTES, len);
+}
+
+static int32_t
+__nacl_work (transport_crypto_t *this, struct iobuf *iobuf,
+	     char *buf, size_t len, char *prefix,
+	     char *nonce, int encrypt)
+{
+	char *orig, *dest;
+	struct iobuf *orig_ref = NULL, *dest_ref = NULL;
+	nacl_private_t *priv;
+	int ret;
+	char n[32];
+
+	priv = this->xl_private;
+	memcpy (n, nonce, NACL_NONCE_BYTES);
+	//memset (n, 0, NACL_NONCE_BYTES);
+	orig = nacl_join (this, iobuf, buf, len, prefix, &orig_ref);
+	dest = nacl_alloc (this, len, &dest_ref);
+	if (!orig || !dest)
+		return -ENOMEM;
+
+	if (encrypt)
+		memset (orig, 0, NACL_ZERO_BYTES);
+
+	if (encrypt)
+		ret = crypto_secretbox ((u_char *)dest, (u_char *)orig,
+					len + NACL_ZERO_BYTES,
+					(u_char *)n, priv->k);
+	else
+		ret = crypto_secretbox_open ((u_char *)dest, (u_char *)orig,
+					     len + NACL_ZERO_BYTES,
+					     (u_char *)n, priv->k);
+	if (ret)
+		gf_log ("nacl", GF_LOG_ERROR, "error during %s."
+			" Check the passphrase.",
+			encrypt ? "encryption" : "decryption");
+	nacl_split(iobuf, buf, len, prefix, dest);
+
+	nacl_free(iobuf, orig_ref, orig);
+	nacl_free(NULL, dest_ref, dest);
+	return ret;
+}
+
+static int32_t
+nacl_iovec (transport_crypto_t *this, struct iovec *vector, int count,
+	    char *prefix, char *nonce)
+{
+	size_t len;
+	int32_t ret;
+	struct iobuf *iobuf;
+
+	if (!vector || !count)
+		return 0;
+
+	iobuf = iobuf_get (this->xl->ctx->iobuf_pool);
+	if (!iobuf)
+		return -ENOMEM;
+	iov_unload (iobuf->ptr, vector, count);
+	len = iov_length (vector, count);
+	ret = __nacl_work (this, iobuf, NULL, len, prefix, nonce, 1);
+	iov_load (vector, count, iobuf->ptr);
+	iobuf_unref (iobuf);
+	return ret;
+}
+
+int32_t
+nacl_encrypt (transport_crypto_t *this, char *hdr, size_t len,
+	      struct iovec *vector, int count)
+{
+	int32_t ret = 0;
+	int32_t n;
+	gf_hdr_common_t *h = (gf_hdr_common_t *)hdr;
+	nacl_private_t *priv;
+
+	priv = this->xl_private;
+
+	n = (h->callid << 16) ^ h->size ^ priv->time;
+	memcpy (h->nacl.nonce, (char *)&n, NACL_NONCE_BYTES);
+
+	ret = __nacl_work (this, NULL, gf_param(h), len - GF_HDR_COMMON_SIZE,
+			   h->nacl.crypto_hdr, h->nacl.nonce, 1);
+	if (ret)
+		return ret;
+	if (count)
+		ret = nacl_iovec (this, vector, count, h->nacl.crypto_vec,
+				  h->nacl.nonce);
+	return ret;
+}
+
+int32_t
+nacl_decrypt (transport_crypto_t *this, char *hdr, size_t len,
+	      struct iobuf *iobuf, size_t buflen)
+{
+	int32_t ret = 0;
+	gf_hdr_common_t *h = (gf_hdr_common_t *)hdr;
+
+	ret = __nacl_work (this, NULL, gf_param(h), len - GF_HDR_COMMON_SIZE,
+			   h->nacl.crypto_hdr, h->nacl.nonce, 0);
+	if (ret)
+	return ret;
+	if (buflen)
+		ret = __nacl_work (this, iobuf, NULL, buflen,
+				   h->nacl.crypto_vec, h->nacl.nonce, 0);
+	return ret;
+}
+
+static void
+nacl_gen_key(nacl_private_t *priv, const char *pass)
+{
+	const EVP_CIPHER *cipher = EVP_aes_256_cbc();
+	const EVP_MD *dgst = EVP_sha1();
+	u_char key[cipher->key_len];
+	u_char iv[cipher->iv_len];
+
+	/* GF_PROTOCOL_VERSION use as salt */
+	EVP_BytesToKey(cipher, dgst,
+		       (u_char *)GF_PROTOCOL_VERSION, (u_char *)pass,
+		       strlen(pass), 1, key, iv);
+
+	memcpy(priv->k, key, crypto_secretbox_KEYBYTES);
+}
+
+int32_t
+init (transport_crypto_t *crypto)
+{
+	nacl_private_t *priv;
+	char *password;
+	data_t *password_data;
+
+	priv = CALLOC (1, sizeof (*priv));
+	if (!priv)
+		return -ENOMEM;
+
+	crypto->xl_private = priv;
+	crypto->magic = CRYPTO_MAGIC_NACL;
+
+
+	password_data = dict_get (crypto->xl->options,
+				  "transport.crypto.passphrase");
+	if (!password_data) {
+		gf_log ("nacl", GF_LOG_ERROR, "no passphrase specified");
+		return -1;
+	}
+
+	password = data_to_str (password_data);
+	nacl_gen_key(priv, password);
+	priv->time = time(NULL);
+
+	gf_log ("nacl", GF_LOG_DEBUG, "nacl transport encryptor loaded");
+	return 0;
+}
+
+void
+fini (transport_crypto_t *crypto)
+{
+	FREE (crypto->xl_private);
+	return;
+}
+
+struct transport_crypto_ops tcops = {
+	.encrypt = nacl_encrypt,
+	.decrypt = nacl_decrypt,
+};
+
+struct volume_options options[] = {
+	{ .key   = {"transport.crypto.passphrase"},
+	  .type  = GF_OPTION_TYPE_ANY
+	},
+	{ .key  = {NULL} },
+};
diff --git a/transport/encryption/nacl/src/nacl.h b/transport/encryption/nacl/src/nacl.h
new file mode 100644
index 0000000..89e8f7a
--- /dev/null
+++ b/transport/encryption/nacl/src/nacl.h
@@ -0,0 +1,39 @@
+/*
+   Copyright (c) 2009 commonIT
+   Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com>
+   This file is part of GlusterFS.
+
+   GlusterFS 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 of the License,
+   or (at your option) any later version.
+
+   GlusterFS 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 this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __NACL_H__
+#define __NACL_H__
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include <crypto_secretbox.h>
+
+#define CRYPTO_MAGIC_NACL	58443 /* NaCl molar mass :) */
+
+typedef struct {
+	unsigned char k[crypto_secretbox_KEYBYTES];
+	time_t        time;
+} nacl_private_t;
+
+
+#endif /* __ROT_13_H__ */
-- 
1.6.4.4






More information about the Gluster-devel mailing list