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 : }
|