a3a04f
From 8a696458dac335071d98f39dfd1380192fbe7733 Mon Sep 17 00:00:00 2001
a3a04f
From: Alexander Bokovoy <ab@samba.org>
a3a04f
Date: Fri, 10 Mar 2017 16:20:06 +0200
a3a04f
Subject: [PATCH] lib/crypto: implement samba.crypto Python module for RC4
a3a04f
MIME-Version: 1.0
a3a04f
Content-Type: text/plain; charset=UTF-8
a3a04f
Content-Transfer-Encoding: 8bit
a3a04f
a3a04f
Implement a small Python module that exposes arcfour_crypt_blob()
a3a04f
function widely used in Samba C code.
a3a04f
a3a04f
When Samba Python bindings are used to call LSA CreateTrustedDomainEx2,
a3a04f
there is a need to encrypt trusted credentials with RC4 cipher.
a3a04f
a3a04f
Current Samba Python code relies on Python runtime to provide RC4
a3a04f
cipher. However, in FIPS 140-2 mode system crypto libraries do not
a3a04f
provide access RC4 cipher at all. According to Microsoft dochelp team,
a3a04f
Windows is treating AuthenticationInformation blob encryption as 'plain
a3a04f
text' in terms of FIPS 140-2, thus doing application-level encryption.
a3a04f
a3a04f
Replace samba.arcfour_encrypt() implementation with a call to
a3a04f
samba.crypto.arcfour_crypt_blob().
a3a04f
a3a04f
Signed-off-by: Alexander Bokovoy <ab@samba.org>
a3a04f
Reviewed-by: Simo Sorce <idra@samba.org>
a3a04f
Reviewed-by: Guenther Deschner <gd@samba.org>
a3a04f
a3a04f
Autobuild-User(master): Günther Deschner <gd@samba.org>
a3a04f
Autobuild-Date(master): Wed Mar 15 01:30:24 CET 2017 on sn-devel-144
a3a04f
a3a04f
(cherry picked from commit bbeef554f2c15e739f6095fcb57d9ef6646b411c)
a3a04f
---
a3a04f
 lib/crypto/py_crypto.c   | 90 ++++++++++++++++++++++++++++++++++++++++++++++++
a3a04f
 lib/crypto/wscript_build |  7 ++++
a3a04f
 python/samba/__init__.py | 16 ++-------
a3a04f
 3 files changed, 99 insertions(+), 14 deletions(-)
a3a04f
 create mode 100644 lib/crypto/py_crypto.c
a3a04f
a3a04f
diff --git a/lib/crypto/py_crypto.c b/lib/crypto/py_crypto.c
a3a04f
new file mode 100644
a3a04f
index 0000000..bf7f9f4
a3a04f
--- /dev/null
a3a04f
+++ b/lib/crypto/py_crypto.c
a3a04f
@@ -0,0 +1,90 @@
a3a04f
+/*
a3a04f
+   Unix SMB/CIFS implementation.
a3a04f
+   Samba crypto functions
a3a04f
+
a3a04f
+   Copyright (C) Alexander Bokovoy <ab@samba.org> 2017
a3a04f
+
a3a04f
+   This program is free software; you can redistribute it and/or modify
a3a04f
+   it under the terms of the GNU General Public License as published by
a3a04f
+   the Free Software Foundation; either version 3 of the License, or
a3a04f
+   (at your option) any later version.
a3a04f
+
a3a04f
+   This program is distributed in the hope that it will be useful,
a3a04f
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
a3a04f
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
a3a04f
+   GNU General Public License for more details.
a3a04f
+
a3a04f
+   You should have received a copy of the GNU General Public License
a3a04f
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
a3a04f
+*/
a3a04f
+
a3a04f
+#include <Python.h>
a3a04f
+#include "includes.h"
a3a04f
+#include "python/py3compat.h"
a3a04f
+#include "lib/crypto/arcfour.h"
a3a04f
+
a3a04f
+static PyObject *py_crypto_arcfour_crypt_blob(PyObject *module, PyObject *args, PyObject *kwargs)
a3a04f
+{
a3a04f
+	DATA_BLOB data, key;
a3a04f
+	PyObject *py_data, *py_key, *result;
a3a04f
+	TALLOC_CTX *ctx;
a3a04f
+
a3a04f
+	if (!PyArg_ParseTuple(args, "OO", &py_data, &py_key))
a3a04f
+		return NULL;
a3a04f
+
a3a04f
+	if (!PyBytes_Check(py_data)) {
a3a04f
+		PyErr_Format(PyExc_TypeError, "bytes expected");
a3a04f
+		return NULL;
a3a04f
+	}
a3a04f
+
a3a04f
+	if (!PyBytes_Check(py_key)) {
a3a04f
+		PyErr_Format(PyExc_TypeError, "bytes expected");
a3a04f
+		return NULL;
a3a04f
+	}
a3a04f
+
a3a04f
+	ctx = talloc_new(NULL);
a3a04f
+
a3a04f
+	data.length = PyBytes_Size(py_data);
a3a04f
+	data.data = talloc_memdup(ctx, PyBytes_AsString(py_data), data.length);
a3a04f
+	if (!data.data) {
a3a04f
+		talloc_free(ctx);
a3a04f
+		return PyErr_NoMemory();
a3a04f
+	}
a3a04f
+
a3a04f
+	key.data = (uint8_t *)PyBytes_AsString(py_key);
a3a04f
+	key.length = PyBytes_Size(py_key);
a3a04f
+
a3a04f
+	arcfour_crypt_blob(data.data, data.length, &key);
a3a04f
+
a3a04f
+	result = PyBytes_FromStringAndSize((const char*) data.data, data.length);
a3a04f
+	talloc_free(ctx);
a3a04f
+	return result;
a3a04f
+}
a3a04f
+
a3a04f
+
a3a04f
+static const char py_crypto_arcfour_crypt_blob_doc[] = "arcfour_crypt_blob(data, key)\n"
a3a04f
+					 "Encrypt the data with RC4 algorithm using the key";
a3a04f
+
a3a04f
+static PyMethodDef py_crypto_methods[] = {
a3a04f
+	{ "arcfour_crypt_blob", (PyCFunction)py_crypto_arcfour_crypt_blob, METH_VARARGS, py_crypto_arcfour_crypt_blob_doc },
a3a04f
+	{ NULL },
a3a04f
+};
a3a04f
+
a3a04f
+static struct PyModuleDef moduledef = {
a3a04f
+	PyModuleDef_HEAD_INIT,
a3a04f
+	.m_name = "crypto",
a3a04f
+	.m_doc = "Crypto functions required for SMB",
a3a04f
+	.m_size = -1,
a3a04f
+	.m_methods = py_crypto_methods,
a3a04f
+};
a3a04f
+
a3a04f
+MODULE_INIT_FUNC(crypto)
a3a04f
+{
a3a04f
+	PyObject *m;
a3a04f
+
a3a04f
+	m = PyModule_Create(&moduledef);
a3a04f
+	if (m == NULL)
a3a04f
+		return NULL;
a3a04f
+
a3a04f
+	return m;
a3a04f
+}
a3a04f
diff --git a/lib/crypto/wscript_build b/lib/crypto/wscript_build
a3a04f
index 7f94532..d1f152e 100644
a3a04f
--- a/lib/crypto/wscript_build
a3a04f
+++ b/lib/crypto/wscript_build
a3a04f
@@ -25,3 +25,10 @@ bld.SAMBA_SUBSYSTEM('TORTURE_LIBCRYPTO',
a3a04f
         autoproto='test_proto.h',
a3a04f
         deps='LIBCRYPTO'
a3a04f
         )
a3a04f
+
a3a04f
+for env in bld.gen_python_environments():
a3a04f
+	bld.SAMBA_PYTHON('python_crypto',
a3a04f
+		source='py_crypto.c',
a3a04f
+		deps='LIBCRYPTO',
a3a04f
+		realname='samba/crypto.so'
a3a04f
+		)
a3a04f
diff --git a/python/samba/__init__.py b/python/samba/__init__.py
a3a04f
index 19d5e38..fa4244a 100644
a3a04f
--- a/python/samba/__init__.py
a3a04f
+++ b/python/samba/__init__.py
a3a04f
@@ -371,20 +371,8 @@ def string_to_byte_array(string):
a3a04f
     return blob
a3a04f
 
a3a04f
 def arcfour_encrypt(key, data):
a3a04f
-    try:
a3a04f
-        from Crypto.Cipher import ARC4
a3a04f
-        c = ARC4.new(key)
a3a04f
-        return c.encrypt(data)
a3a04f
-    except ImportError as e:
a3a04f
-        pass
a3a04f
-    try:
a3a04f
-        from M2Crypto.RC4 import RC4
a3a04f
-        c = RC4(key)
a3a04f
-        return c.update(data)
a3a04f
-    except ImportError as e:
a3a04f
-        pass
a3a04f
-    raise Exception("arcfour_encrypt() requires " +
a3a04f
-                    "python*-crypto or python*-m2crypto or m2crypto")
a3a04f
+    from samba.crypto import arcfour_crypt_blob
a3a04f
+    return arcfour_crypt_blob(data, key)
a3a04f
 
a3a04f
 import _glue
a3a04f
 version = _glue.version
a3a04f
-- 
a3a04f
2.9.3
a3a04f