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