Make python arcfour_crypt more portable

Stefan Metzmacher metze at samba.org
Sun Jan 31 20:46:15 UTC 2016


Hi,

here're some fixed for https://bugzilla.samba.org/show_bug.cgi?id=11699

Crypto.Cipher.ARC4 (from python-crypto) is not available on
all platforms.

We now fallback to use M2Crypto.RC4.RC4 (from python*-]m2crypto)
which is should be available when python-crypto is not, e.g.
on RHEL (at least 6?).

Please review and push.

Thanks!
metze
-------------- next part --------------
From 353e97147fbd79460b80be1ccc1a8e4b46897e50 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 Jan 2016 13:44:33 +0100
Subject: [PATCH 1/6] python:samba: add a generic string_to_byte_array() helper
 function

We should avoid implementing this again and again.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11699

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/__init__.py | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/python/samba/__init__.py b/python/samba/__init__.py
index b04e83c..59b6ebf 100644
--- a/python/samba/__init__.py
+++ b/python/samba/__init__.py
@@ -362,6 +362,14 @@ def dn_from_dns_name(dnsdomain):
 def current_unix_time():
     return int(time.time())
 
+def string_to_byte_array(string):
+    blob = [0] * len(string)
+
+    for i in range(len(string)):
+        blob[i] = ord(string[i])
+
+    return blob
+
 import _glue
 version = _glue.version
 interface_ips = _glue.interface_ips
-- 
1.9.1


From 5054b858a669855390abe1f08c6d633bc735fa89 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 Jan 2016 13:52:44 +0100
Subject: [PATCH 2/6] python:samba: add a generic arcfour_encrypt() helper
 function

This works with Crypto.Cipher.ARC4 (from python*-crypto) and
fallback to M2Crypto.RC4.RC4 (from [python*-]m2crypto).

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11699

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/__init__.py | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/python/samba/__init__.py b/python/samba/__init__.py
index 59b6ebf..7cfbc4c 100644
--- a/python/samba/__init__.py
+++ b/python/samba/__init__.py
@@ -370,6 +370,22 @@ def string_to_byte_array(string):
 
     return blob
 
+def arcfour_encrypt(key, data):
+    try:
+        from Crypto.Cipher import ARC4
+        c = ARC4.new(key)
+        return c.encrypt(data)
+    except ImportError as e:
+        pass
+    try:
+        from M2Crypto.RC4 import RC4
+        c = RC4(key)
+        return c.update(data)
+    except ImportError as e:
+        pass
+    raise Exception("arcfour_encrypt() requires " +
+                    "python*-crypto or python*-m2crypto or m2crypto")
+
 import _glue
 version = _glue.version
 interface_ips = _glue.interface_ips
-- 
1.9.1


From cee6087b96b401c366220b3bd7e175f811e981b9 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 Jan 2016 14:00:38 +0100
Subject: [PATCH 3/6] python:samba/join.py: make use of the generic
 arcfour_encrypt() and string_to_byte_array() functions

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11699

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/join.py | 19 +++----------------
 1 file changed, 3 insertions(+), 16 deletions(-)

diff --git a/python/samba/join.py b/python/samba/join.py
index cdfe452..6df337c 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -20,7 +20,7 @@
 
 from samba.auth import system_session
 from samba.samdb import SamDB
-from samba import gensec, Ldb, drs_utils
+from samba import gensec, Ldb, drs_utils, arcfour_encrypt, string_to_byte_array
 import ldb, samba, sys, uuid
 from samba.ndr import ndr_pack
 from samba.dcerpc import security, drsuapi, misc, nbt, lsa, drsblobs
@@ -963,19 +963,6 @@ class dc_join(object):
     def join_setup_trusts(ctx):
         """provision the local SAM."""
 
-        def arcfour_encrypt(key, data):
-            from Crypto.Cipher import ARC4
-            c = ARC4.new(key)
-            return c.encrypt(data)
-
-        def string_to_array(string):
-            blob = [0] * len(string)
-
-            for i in range(len(string)):
-                blob[i] = ord(string[i])
-
-            return blob
-
         print "Setup domain trusts with server %s" % ctx.server
         binding_options = ""  # why doesn't signing work here? w2k8r2 claims no session key
         lsaconn = lsa.lsarpc("ncacn_np:%s[%s]" % (ctx.server, binding_options),
@@ -1005,7 +992,7 @@ class dc_join(object):
         except RuntimeError:
             pass
 
-        password_blob = string_to_array(ctx.trustdom_pass.encode('utf-16-le'))
+        password_blob = string_to_byte_array(ctx.trustdom_pass.encode('utf-16-le'))
 
         clear_value = drsblobs.AuthInfoClear()
         clear_value.size = len(password_blob)
@@ -1041,7 +1028,7 @@ class dc_join(object):
 
         auth_blob = lsa.DATA_BUF2()
         auth_blob.size = len(encrypted_trustpass)
-        auth_blob.data = string_to_array(encrypted_trustpass)
+        auth_blob.data = string_to_byte_array(encrypted_trustpass)
 
         auth_info = lsa.TrustDomainInfoAuthInfoInternal()
         auth_info.auth_blob = auth_blob
-- 
1.9.1


From c5fffd574fca07685402e4886b1df1c958be839e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 Jan 2016 14:00:38 +0100
Subject: [PATCH 4/6] python:samba/netcmd/domain: make use of the generic
 arcfour_encrypt() and string_to_byte_array() functions

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11699

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/netcmd/domain.py | 23 +++++------------------
 1 file changed, 5 insertions(+), 18 deletions(-)

diff --git a/python/samba/netcmd/domain.py b/python/samba/netcmd/domain.py
index 8802803..6357144 100644
--- a/python/samba/netcmd/domain.py
+++ b/python/samba/netcmd/domain.py
@@ -60,7 +60,7 @@ from samba.upgrade import upgrade_from_samba3
 from samba.drs_utils import (
                             sendDsReplicaSync, drsuapi_connect, drsException,
                             sendRemoveDsServer)
-from samba import remove_dc
+from samba import remove_dc, arcfour_encrypt, string_to_byte_array
 
 from samba.dsdb import (
     DS_DOMAIN_FUNCTION_2000,
@@ -2230,24 +2230,16 @@ class cmd_domain_trust_create(DomainTrustCommand):
                     password = None
                     self.outf.write("Sorry, passwords do not match.\n")
 
-        def string_to_array(string):
-            blob = [0] * len(string)
-
-            for i in range(len(string)):
-                blob[i] = ord(string[i])
-
-            return blob
-
         incoming_secret = None
         outgoing_secret = None
         remote_policy_access = lsa.LSA_POLICY_VIEW_LOCAL_INFORMATION
         if create_location == "local":
             if local_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_INBOUND:
                 incoming_password = get_password("Incoming Trust")
-                incoming_secret = string_to_array(incoming_password.encode('utf-16-le'))
+                incoming_secret = string_to_byte_array(incoming_password.encode('utf-16-le'))
             if local_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_OUTBOUND:
                 outgoing_password = get_password("Outgoing Trust")
-                outgoing_secret = string_to_array(outgoing_password.encode('utf-16-le'))
+                outgoing_secret = string_to_byte_array(outgoing_password.encode('utf-16-le'))
 
             remote_trust_info = None
         else:
@@ -2272,7 +2264,7 @@ class cmd_domain_trust_create(DomainTrustCommand):
                     #
                     # We can remove this once our client libraries
                     # support using the correct NTHASH.
-                    return string_to_array(pw1.encode('utf-16-le'))
+                    return string_to_byte_array(pw1.encode('utf-16-le'))
 
                 # We mix characters from generate_random_password
                 # with random numbers from random.randint()
@@ -2425,11 +2417,6 @@ class cmd_domain_trust_create(DomainTrustCommand):
             except RuntimeError as error:
                 raise self.RemoteRuntimeError(self, error, "failed to get netlogon dc info")
 
-        def arcfour_encrypt(key, data):
-            from Crypto.Cipher import ARC4
-            c = ARC4.new(key)
-            return c.encrypt(data)
-
         def generate_AuthInOutBlob(secret, update_time):
             if secret is None:
                 blob = drsblobs.trustAuthInOutBlob()
@@ -2473,7 +2460,7 @@ class cmd_domain_trust_create(DomainTrustCommand):
 
             auth_blob = lsa.DATA_BUF2()
             auth_blob.size = len(encrypted_trustpass)
-            auth_blob.data = string_to_array(encrypted_trustpass)
+            auth_blob.data = string_to_byte_array(encrypted_trustpass)
 
             auth_info = lsa.TrustDomainInfoAuthInfoInternal()
             auth_info.auth_blob = auth_blob
-- 
1.9.1


From ee708ce07439e89416efcbb7521673067ecabf5c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 Jan 2016 14:00:38 +0100
Subject: [PATCH 5/6] s4:scripting/devel: make use of the generic
 arcfour_encrypt() and string_to_byte_array() functions

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11699

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/scripting/devel/createtrust | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/source4/scripting/devel/createtrust b/source4/scripting/devel/createtrust
index 7f1ba33..6c0de1c 100755
--- a/source4/scripting/devel/createtrust
+++ b/source4/scripting/devel/createtrust
@@ -11,21 +11,9 @@ import samba
 import samba.getopt as options
 from samba.dcerpc import lsa, security, drsblobs
 from samba.ndr import ndr_pack
+from samba import arcfour_encrypt, string_to_byte_array
 import random
 
-def arcfour_encrypt(key, data):
-    from Crypto.Cipher import ARC4
-    c = ARC4.new(key)
-    return c.encrypt(data)
-
-def string_to_array(string):
-    blob = [0] * len(string)
-
-    for i in range(len(string)):
-        blob[i] = ord(string[i])
-
-    return blob
-
 ########### main code ###########
 if __name__ == "__main__":
     parser = OptionParser("createtrust [options] server")
@@ -73,7 +61,7 @@ if __name__ == "__main__":
     info.trust_type = lsa.LSA_TRUST_TYPE_UPLEVEL
     info.trust_attributes = lsa.LSA_TRUST_ATTRIBUTE_WITHIN_FOREST
 
-    password_blob = string_to_array("password".encode('utf-16-le'))
+    password_blob = string_to_byte_array("password".encode('utf-16-le'))
 
     clear_value = drsblobs.AuthInfoClear()
     clear_value.size = len(password_blob)
@@ -123,7 +111,7 @@ if __name__ == "__main__":
 
     auth_blob = lsa.DATA_BUF2()
     auth_blob.size = len(encrypted_trustpass)
-    auth_blob.data = string_to_array(encrypted_trustpass)
+    auth_blob.data = string_to_byte_array(encrypted_trustpass)
 
     auth_info = lsa.TrustDomainInfoAuthInfoInternal()
     auth_info.auth_blob = auth_blob
-- 
1.9.1


From 091515f19f8cb79af83b10402e62ce9036bf0c69 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 28 Jan 2016 15:10:00 +0100
Subject: [PATCH 6/6] python:tests/core: add tests for arcfour_encrypt() and
 string_to_byte_array()

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11699

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 python/samba/tests/core.py | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/python/samba/tests/core.py b/python/samba/tests/core.py
index 8206e68..9dbaff1 100644
--- a/python/samba/tests/core.py
+++ b/python/samba/tests/core.py
@@ -20,6 +20,7 @@
 import ldb
 import os
 import samba
+from samba import arcfour_encrypt, string_to_byte_array
 from samba.tests import TestCase, TestCaseInTempDir
 
 class SubstituteVarTestCase(TestCase):
@@ -48,6 +49,21 @@ class SubstituteVarTestCase(TestCase):
         self.assertRaises(Exception, samba.check_all_substituted,
                 "Not subsituted: ${FOOBAR}")
 
+class ArcfourTestCase(TestCase):
+
+    def test_arcfour_direct(self):
+        key = '12345678'
+        plain = 'abcdefghi'
+        crypt_expected = '\xda\x91Z\xb0l\xd7\xb9\xcf\x99'
+        crypt_calculated = arcfour_encrypt(key, plain)
+        self.assertEquals(crypt_expected, crypt_calculated)
+
+class StringToByteArrayTestCase(TestCase):
+
+    def test_byte_array(self):
+        expected = [218, 145, 90, 176, 108, 215, 185, 207, 153]
+        calculated = string_to_byte_array('\xda\x91Z\xb0l\xd7\xb9\xcf\x99')
+        self.assertEquals(expected, calculated)
 
 class LdbExtensionTests(TestCaseInTempDir):
 
-- 
1.9.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20160131/de69c16f/signature.sig>


More information about the samba-technical mailing list