LCOV - code coverage report
Current view: top level - lib/crypto - py_crypto.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 136 195 69.7 %
Date: 2024-04-21 15:09:00 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Samba crypto functions
       4             : 
       5             :    Copyright (C) Alexander Bokovoy <ab@samba.org> 2017
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "lib/replace/system/python.h"
      22             : #include "includes.h"
      23             : #include "python/py3compat.h"
      24             : 
      25             : #include <gnutls/gnutls.h>
      26             : #include <gnutls/crypto.h>
      27             : #include "lib/crypto/gnutls_helpers.h"
      28             : #include "lib/crypto/md4.h"
      29             : #include "libcli/auth/libcli_auth.h"
      30             : #include "libcli/util/pyerrors.h"
      31             : 
      32           4 : static bool samba_gnutls_datum_from_PyObject(PyObject *py_obj,
      33             :                                              gnutls_datum_t *datum)
      34             : {
      35           4 :         uint8_t *data = NULL;
      36           0 :         Py_ssize_t size;
      37             : 
      38           0 :         int ret;
      39             : 
      40           4 :         ret = PyBytes_AsStringAndSize(py_obj,
      41             :                                       (char **)&data,
      42             :                                       &size);
      43           4 :         if (ret != 0) {
      44           0 :                 return false;
      45             :         }
      46             : 
      47           4 :         datum->data = data;
      48           4 :         datum->size = size;
      49             : 
      50           4 :         return true;
      51             : }
      52             : 
      53         125 : static bool samba_DATA_BLOB_from_PyObject(PyObject *py_obj,
      54             :                                           DATA_BLOB *blob)
      55             : {
      56         125 :         uint8_t *data = NULL;
      57           0 :         Py_ssize_t size;
      58             : 
      59           0 :         int ret;
      60             : 
      61         125 :         ret = PyBytes_AsStringAndSize(py_obj,
      62             :                                       (char **)&data,
      63             :                                       &size);
      64         125 :         if (ret != 0) {
      65           0 :                 return false;
      66             :         }
      67             : 
      68         125 :         blob->data = data;
      69         125 :         blob->length = size;
      70             : 
      71         125 :         return true;
      72             : }
      73             : 
      74          29 : static PyObject *py_crypto_arcfour_crypt_blob(PyObject *module, PyObject *args)
      75             : {
      76           1 :         DATA_BLOB data;
      77           1 :         PyObject *py_data, *py_key, *result;
      78           1 :         TALLOC_CTX *ctx;
      79          29 :         gnutls_cipher_hd_t cipher_hnd = NULL;
      80           1 :         gnutls_datum_t key;
      81           1 :         int rc;
      82             : 
      83          29 :         if (!PyArg_ParseTuple(args, "OO", &py_data, &py_key))
      84           0 :                 return NULL;
      85             : 
      86          29 :         if (!PyBytes_Check(py_data)) {
      87           0 :                 PyErr_Format(PyExc_TypeError, "bytes expected");
      88           0 :                 return NULL;
      89             :         }
      90             : 
      91          29 :         if (!PyBytes_Check(py_key)) {
      92           0 :                 PyErr_Format(PyExc_TypeError, "bytes expected");
      93           0 :                 return NULL;
      94             :         }
      95             : 
      96          29 :         ctx = talloc_new(NULL);
      97             : 
      98          29 :         data.length = PyBytes_Size(py_data);
      99          29 :         data.data = talloc_memdup(ctx, PyBytes_AsString(py_data), data.length);
     100          29 :         if (!data.data) {
     101           0 :                 talloc_free(ctx);
     102           0 :                 return PyErr_NoMemory();
     103             :         }
     104             : 
     105          30 :         key = (gnutls_datum_t) {
     106          29 :                 .data = (uint8_t *)PyBytes_AsString(py_key),
     107          29 :                 .size = PyBytes_Size(py_key),
     108             :         };
     109             : 
     110          29 :         rc = gnutls_cipher_init(&cipher_hnd,
     111             :                                 GNUTLS_CIPHER_ARCFOUR_128,
     112             :                                 &key,
     113             :                                 NULL);
     114          29 :         if (rc < 0) {
     115           1 :                 talloc_free(ctx);
     116           1 :                 PyErr_Format(PyExc_OSError, "encryption failed");
     117           1 :                 return NULL;
     118             :         }
     119          28 :         rc = gnutls_cipher_encrypt(cipher_hnd,
     120          27 :                                    data.data,
     121             :                                    data.length);
     122          28 :         gnutls_cipher_deinit(cipher_hnd);
     123          28 :         if (rc < 0) {
     124           0 :                 talloc_free(ctx);
     125           0 :                 PyErr_Format(PyExc_OSError, "encryption failed");
     126           0 :                 return NULL;
     127             :         }
     128             : 
     129          28 :         result = PyBytes_FromStringAndSize((const char*) data.data, data.length);
     130          28 :         talloc_free(ctx);
     131          28 :         return result;
     132             : }
     133             : 
     134           5 : static PyObject *py_crypto_set_relax_mode(PyObject *module, PyObject *Py_UNUSED(ignored))
     135             : {
     136           5 :         GNUTLS_FIPS140_SET_LAX_MODE();
     137             : 
     138           5 :         Py_RETURN_NONE;
     139             : }
     140             : 
     141           6 : static PyObject *py_crypto_set_strict_mode(PyObject *module, PyObject *Py_UNUSED(ignored))
     142             : {
     143           6 :         GNUTLS_FIPS140_SET_STRICT_MODE();
     144             : 
     145           6 :         Py_RETURN_NONE;
     146             : }
     147             : 
     148          24 : static PyObject *py_crypto_des_crypt_blob_16(PyObject *self, PyObject *args)
     149             : {
     150          24 :         PyObject *py_data = NULL;
     151          24 :         uint8_t *data = NULL;
     152           0 :         Py_ssize_t data_size;
     153             : 
     154          24 :         PyObject *py_key = NULL;
     155          24 :         uint8_t *key = NULL;
     156           0 :         Py_ssize_t key_size;
     157             : 
     158           0 :         uint8_t result[16];
     159             : 
     160           0 :         bool ok;
     161           0 :         int ret;
     162             : 
     163          24 :         ok = PyArg_ParseTuple(args, "SS",
     164             :                               &py_data, &py_key);
     165          24 :         if (!ok) {
     166           0 :                 return NULL;
     167             :         }
     168             : 
     169          24 :         ret = PyBytes_AsStringAndSize(py_data,
     170             :                                       (char **)&data,
     171             :                                       &data_size);
     172          24 :         if (ret != 0) {
     173           0 :                 return NULL;
     174             :         }
     175             : 
     176          24 :         ret = PyBytes_AsStringAndSize(py_key,
     177             :                                       (char **)&key,
     178             :                                       &key_size);
     179          24 :         if (ret != 0) {
     180           0 :                 return NULL;
     181             :         }
     182             : 
     183          24 :         if (data_size != 16) {
     184           0 :                 return PyErr_Format(PyExc_ValueError,
     185             :                                     "Expected data size of 16 bytes; got %zd",
     186             :                                     data_size);
     187             :         }
     188             : 
     189          24 :         if (key_size != 14) {
     190           0 :                 return PyErr_Format(PyExc_ValueError,
     191             :                                     "Expected key size of 14 bytes; got %zd",
     192             :                                     key_size);
     193             :         }
     194             : 
     195          24 :         ret = des_crypt112_16(result, data, key,
     196             :                               SAMBA_GNUTLS_ENCRYPT);
     197          24 :         if (ret != 0) {
     198           0 :                 return PyErr_Format(PyExc_RuntimeError,
     199             :                                     "des_crypt112_16() failed: %d",
     200             :                                     ret);
     201             :         }
     202             : 
     203          24 :         return PyBytes_FromStringAndSize((const char *)result,
     204             :                                          sizeof(result));
     205             : }
     206             : 
     207          26 : static PyObject *py_crypto_md4_hash_blob(PyObject *self, PyObject *args)
     208             : {
     209          26 :         PyObject *py_data = NULL;
     210          26 :         uint8_t *data = NULL;
     211           0 :         Py_ssize_t data_size;
     212             : 
     213           0 :         uint8_t result[16];
     214             : 
     215           0 :         bool ok;
     216           0 :         int ret;
     217             : 
     218          26 :         ok = PyArg_ParseTuple(args, "S",
     219             :                               &py_data);
     220          26 :         if (!ok) {
     221           0 :                 return NULL;
     222             :         }
     223             : 
     224          26 :         ret = PyBytes_AsStringAndSize(py_data,
     225             :                                       (char **)&data,
     226             :                                       &data_size);
     227          26 :         if (ret != 0) {
     228           0 :                 return NULL;
     229             :         }
     230             : 
     231          26 :         mdfour(result, data, data_size);
     232             : 
     233          26 :         return PyBytes_FromStringAndSize((const char *)result,
     234             :                                          sizeof(result));
     235             : }
     236             : 
     237           2 : static PyObject *py_crypto_sha512_pbkdf2(PyObject *self, PyObject *args)
     238             : {
     239           2 :         PyObject *py_key = NULL;
     240           2 :         uint8_t *key = NULL;
     241           2 :         gnutls_datum_t key_datum = {0};
     242             : 
     243           2 :         PyObject *py_salt = NULL;
     244           2 :         gnutls_datum_t salt_datum = {0};
     245             : 
     246           0 :         uint8_t result[16];
     247             : 
     248           2 :         unsigned iterations = 0;
     249             : 
     250           0 :         bool ok;
     251           0 :         int ret;
     252           0 :         NTSTATUS status;
     253             : 
     254           2 :         ok = PyArg_ParseTuple(args, "SSI",
     255             :                               &py_key, &py_salt, &iterations);
     256           2 :         if (!ok) {
     257           0 :                 return NULL;
     258             :         }
     259             : 
     260           2 :         ok = samba_gnutls_datum_from_PyObject(py_key, &key_datum);
     261           2 :         if (!ok) {
     262           0 :                 return NULL;
     263             :         }
     264             : 
     265           2 :         ok = samba_gnutls_datum_from_PyObject(py_salt, &salt_datum);
     266           2 :         if (!ok) {
     267           0 :                 return NULL;
     268             :         }
     269             : 
     270           2 :         ret = gnutls_pbkdf2(GNUTLS_MAC_SHA512,
     271             :                             &key_datum,
     272             :                             &salt_datum,
     273             :                             iterations,
     274             :                             result,
     275             :                             sizeof(result));
     276           2 :         BURN_DATA(key);
     277           2 :         if (ret < 0) {
     278           0 :                 status = gnutls_error_to_ntstatus(ret, NT_STATUS_CRYPTO_SYSTEM_INVALID);
     279           0 :                 PyErr_SetNTSTATUS(status);
     280           0 :                 return NULL;
     281             :         }
     282             : 
     283           2 :         return PyBytes_FromStringAndSize((const char *)result,
     284             :                                          sizeof(result));
     285             : }
     286             : 
     287          25 : static PyObject *py_crypto_aead_aes_256_cbc_hmac_sha512_blob(PyObject *self, PyObject *args)
     288             : {
     289          25 :         TALLOC_CTX *ctx = NULL;
     290             : 
     291          25 :         PyObject *py_ciphertext = NULL;
     292          25 :         DATA_BLOB ciphertext_blob = {0};
     293             : 
     294          25 :         PyObject *py_auth_data = NULL;
     295          25 :         PyObject *py_result = NULL;
     296             : 
     297          25 :         PyObject *py_plaintext = NULL;
     298          25 :         DATA_BLOB plaintext_blob = {0};
     299          25 :         PyObject *py_cek = NULL;
     300          25 :         DATA_BLOB cek_blob = {0};
     301          25 :         PyObject *py_key_salt = NULL;
     302          25 :         DATA_BLOB key_salt_blob = {0};
     303          25 :         PyObject *py_mac_salt = NULL;
     304          25 :         DATA_BLOB mac_salt_blob = {0};
     305          25 :         PyObject *py_iv = NULL;
     306          25 :         DATA_BLOB iv_blob = {0};
     307             : 
     308           0 :         uint8_t auth_data[64];
     309             : 
     310           0 :         bool ok;
     311           0 :         NTSTATUS status;
     312             : 
     313          25 :         ok = PyArg_ParseTuple(args, "SSSSS",
     314             :                               &py_plaintext,
     315             :                               &py_cek,
     316             :                               &py_key_salt,
     317             :                               &py_mac_salt,
     318             :                               &py_iv);
     319          25 :         if (!ok) {
     320           0 :                 return NULL;
     321             :         }
     322             : 
     323             :         /* Create data blobs from the contents of the function parameters. */
     324             : 
     325          25 :         ok = samba_DATA_BLOB_from_PyObject(py_plaintext, &plaintext_blob);
     326          25 :         if (!ok) {
     327           0 :                 return NULL;
     328             :         }
     329             : 
     330          25 :         ok = samba_DATA_BLOB_from_PyObject(py_cek, &cek_blob);
     331          25 :         if (!ok) {
     332           0 :                 return NULL;
     333             :         }
     334             : 
     335          25 :         ok = samba_DATA_BLOB_from_PyObject(py_key_salt, &key_salt_blob);
     336          25 :         if (!ok) {
     337           0 :                 return NULL;
     338             :         }
     339             : 
     340          25 :         ok = samba_DATA_BLOB_from_PyObject(py_mac_salt, &mac_salt_blob);
     341          25 :         if (!ok) {
     342           0 :                 return NULL;
     343             :         }
     344             : 
     345          25 :         ok = samba_DATA_BLOB_from_PyObject(py_iv, &iv_blob);
     346          25 :         if (!ok) {
     347           0 :                 return NULL;
     348             :         }
     349             : 
     350          25 :         ctx = talloc_new(NULL);
     351          25 :         if (ctx == NULL) {
     352           0 :                 return PyErr_NoMemory();
     353             :         }
     354             : 
     355             :         /* Encrypt the plaintext. */
     356          25 :         status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(ctx,
     357             :                                                                    &plaintext_blob,
     358             :                                                                    &cek_blob,
     359             :                                                                    &key_salt_blob,
     360             :                                                                    &mac_salt_blob,
     361             :                                                                    &iv_blob,
     362             :                                                                    &ciphertext_blob,
     363             :                                                                    auth_data);
     364          25 :         if (!NT_STATUS_IS_OK(status)) {
     365           0 :                 PyErr_SetNTSTATUS(status);
     366           0 :                 talloc_free(ctx);
     367           0 :                 return NULL;
     368             :         }
     369             : 
     370             :         /* Convert the output into Python 'bytes' objects. */
     371          25 :         py_ciphertext = PyBytes_FromStringAndSize((const char *)ciphertext_blob.data,
     372          25 :                                                   ciphertext_blob.length);
     373          25 :         talloc_free(ctx);
     374          25 :         if (py_ciphertext == NULL) {
     375           0 :                 return NULL;
     376             :         }
     377          25 :         py_auth_data = PyBytes_FromStringAndSize((const char *)auth_data,
     378             :                                                  sizeof(auth_data));
     379          25 :         if (py_auth_data == NULL) {
     380           0 :                 return NULL;
     381             :         }
     382             : 
     383             :         /* Steal ciphertext and auth_data into a new tuple. */
     384          25 :         py_result = Py_BuildValue("(NN)", py_ciphertext, py_auth_data);
     385             : 
     386          25 :         return py_result;
     387             : }
     388             : 
     389             : 
     390             : 
     391             : static const char py_crypto_arcfour_crypt_blob_doc[] = "arcfour_crypt_blob(data, key)\n"
     392             :                                          "Encrypt the data with RC4 algorithm using the key";
     393             : 
     394             : static const char py_crypto_des_crypt_blob_16_doc[] = "des_crypt_blob_16(data, key) -> bytes\n"
     395             :                                                       "Encrypt the 16-byte data with DES using "
     396             :                                                       "the 14-byte key";
     397             : 
     398             : static const char py_crypto_md4_hash_blob_doc[] = "md4_hash_blob(data) -> bytes\n"
     399             :                                                   "Hash the data with MD4 algorithm";
     400             : 
     401             : static const char py_crypto_sha512_pbkdf2_doc[] = "sha512_pbkdf2(key, salt, iterations) -> bytes\n"
     402             :                                                   "Derive a key from an existing one with SHA512 "
     403             :                                                   "algorithm";
     404             : 
     405             : static const char py_crypto_aead_aes_256_cbc_hmac_sha512_blob_doc[] =
     406             :         "aead_aes_256_cbc_hmac_sha512_blob(plaintext, cek, key_salt, "
     407             :         "mac_salt, iv) -> ciphertext, auth_data\n"
     408             :         "Encrypt the plaintext with AES256 as specified in "
     409             :         "[MS-SAMR] 3.2.2.4 AES Cipher Usage";
     410             : 
     411             : static PyMethodDef py_crypto_methods[] = {
     412             :         { "arcfour_crypt_blob", (PyCFunction)py_crypto_arcfour_crypt_blob, METH_VARARGS, py_crypto_arcfour_crypt_blob_doc },
     413             :         { "set_relax_mode", (PyCFunction)py_crypto_set_relax_mode, METH_NOARGS, "Set fips to relax mode" },
     414             :         { "set_strict_mode", (PyCFunction)py_crypto_set_strict_mode, METH_NOARGS, "Set fips to strict mode" },
     415             :         { "des_crypt_blob_16", (PyCFunction)py_crypto_des_crypt_blob_16, METH_VARARGS, py_crypto_des_crypt_blob_16_doc },
     416             :         { "md4_hash_blob", (PyCFunction)py_crypto_md4_hash_blob, METH_VARARGS, py_crypto_md4_hash_blob_doc },
     417             :         { "sha512_pbkdf2", (PyCFunction)py_crypto_sha512_pbkdf2, METH_VARARGS, py_crypto_sha512_pbkdf2_doc },
     418             :         {
     419             :                 "aead_aes_256_cbc_hmac_sha512_blob",
     420             :                 (PyCFunction)py_crypto_aead_aes_256_cbc_hmac_sha512_blob,
     421             :                 METH_VARARGS,
     422             :                 py_crypto_aead_aes_256_cbc_hmac_sha512_blob_doc
     423             :         },
     424             :         {0},
     425             : };
     426             : 
     427             : static struct PyModuleDef moduledef = {
     428             :         PyModuleDef_HEAD_INIT,
     429             :         .m_name = "crypto",
     430             :         .m_doc = "Crypto functions required for SMB",
     431             :         .m_size = -1,
     432             :         .m_methods = py_crypto_methods,
     433             : };
     434             : 
     435         860 : MODULE_INIT_FUNC(crypto)
     436             : {
     437          35 :         PyObject *m;
     438             : 
     439         860 :         m = PyModule_Create(&moduledef);
     440         860 :         if (m == NULL)
     441           0 :                 return NULL;
     442             : 
     443         825 :         return m;
     444             : }

Generated by: LCOV version 1.14