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