diff options
author | Joseph Sutton <josephsutton@catalyst.net.nz> | 2022-08-02 14:35:19 +1200 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2022-09-12 23:07:37 +0000 |
commit | 4bb9d85fed8498566bdb87baa71a3147806baafc (patch) | |
tree | 03dc072f3ed8a38a5e13d44be3638f9b12eeb399 /lib/crypto | |
parent | 17b8d164f69a5ed79d9b7b7fc2f3f84f8ea534c8 (diff) | |
download | samba-4bb9d85fed8498566bdb87baa71a3147806baafc.tar.gz |
CVE-2021-20251 lib:crypto: Add Python functions for AES SAMR password change
These functions allow us to perform key derivation and AES256 encryption
in Python. They will be used in a following commit.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14611
Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Diffstat (limited to 'lib/crypto')
-rw-r--r-- | lib/crypto/py_crypto.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/lib/crypto/py_crypto.c b/lib/crypto/py_crypto.c index 40b0cb9e9c0..11659556884 100644 --- a/lib/crypto/py_crypto.c +++ b/lib/crypto/py_crypto.c @@ -27,6 +27,51 @@ #include "lib/crypto/gnutls_helpers.h" #include "lib/crypto/md4.h" #include "libcli/auth/libcli_auth.h" +#include "libcli/util/pyerrors.h" + +#ifdef HAVE_GNUTLS_PBKDF2 +static bool samba_gnutls_datum_from_PyObject(PyObject *py_obj, + gnutls_datum_t *datum) +{ + uint8_t *data = NULL; + Py_ssize_t size; + + int ret; + + ret = PyBytes_AsStringAndSize(py_obj, + (char **)&data, + &size); + if (ret != 0) { + return false; + } + + datum->data = data; + datum->size = size; + + return true; +} +#endif /* HAVE_GNUTLS_PBKDF2 */ + +static bool samba_DATA_BLOB_from_PyObject(PyObject *py_obj, + DATA_BLOB *blob) +{ + uint8_t *data = NULL; + Py_ssize_t size; + + int ret; + + ret = PyBytes_AsStringAndSize(py_obj, + (char **)&data, + &size); + if (ret != 0) { + return false; + } + + blob->data = data; + blob->length = size; + + return true; +} static PyObject *py_crypto_arcfour_crypt_blob(PyObject *module, PyObject *args) { @@ -191,6 +236,165 @@ static PyObject *py_crypto_md4_hash_blob(PyObject *self, PyObject *args) sizeof(result)); } +static PyObject *py_crypto_sha512_pbkdf2(PyObject *self, PyObject *args) +{ +#ifdef HAVE_GNUTLS_PBKDF2 + PyObject *py_key = NULL; + uint8_t *key = NULL; + gnutls_datum_t key_datum = {0}; + + PyObject *py_salt = NULL; + gnutls_datum_t salt_datum = {0}; + + uint8_t result[16]; + + unsigned iterations = 0; + + bool ok; + int ret; + NTSTATUS status; + + ok = PyArg_ParseTuple(args, "SSI", + &py_key, &py_salt, &iterations); + if (!ok) { + return NULL; + } + + ok = samba_gnutls_datum_from_PyObject(py_key, &key_datum); + if (!ok) { + return NULL; + } + + ok = samba_gnutls_datum_from_PyObject(py_salt, &salt_datum); + if (!ok) { + return NULL; + } + + ret = gnutls_pbkdf2(GNUTLS_MAC_SHA512, + &key_datum, + &salt_datum, + iterations, + result, + sizeof(result)); + BURN_DATA(key); + if (ret < 0) { + status = gnutls_error_to_ntstatus(ret, NT_STATUS_CRYPTO_SYSTEM_INVALID); + PyErr_SetNTSTATUS(status); + return NULL; + } + + return PyBytes_FromStringAndSize((const char *)result, + sizeof(result)); +#else /* HAVE_GNUTLS_PBKDF2 */ + PyErr_SetString(PyExc_NotImplementedError, "gnutls_pbkdf2() is not available"); + return NULL; +#endif /* HAVE_GNUTLS_PBKDF2 */ +} + +static PyObject *py_crypto_aead_aes_256_cbc_hmac_sha512_blob(PyObject *self, PyObject *args) +{ + TALLOC_CTX *ctx = NULL; + + PyObject *py_ciphertext = NULL; + DATA_BLOB ciphertext_blob = {0}; + + PyObject *py_auth_data = NULL; + PyObject *py_result = NULL; + + PyObject *py_plaintext = NULL; + DATA_BLOB plaintext_blob = {0}; + PyObject *py_cek = NULL; + DATA_BLOB cek_blob = {0}; + PyObject *py_key_salt = NULL; + DATA_BLOB key_salt_blob = {0}; + PyObject *py_mac_salt = NULL; + DATA_BLOB mac_salt_blob = {0}; + PyObject *py_iv = NULL; + DATA_BLOB iv_blob = {0}; + + uint8_t auth_data[64]; + + bool ok; + NTSTATUS status; + + ok = PyArg_ParseTuple(args, "SSSSS", + &py_plaintext, + &py_cek, + &py_key_salt, + &py_mac_salt, + &py_iv); + if (!ok) { + return NULL; + } + + /* Create data blobs from the contents of the function parameters. */ + + ok = samba_DATA_BLOB_from_PyObject(py_plaintext, &plaintext_blob); + if (!ok) { + return NULL; + } + + ok = samba_DATA_BLOB_from_PyObject(py_cek, &cek_blob); + if (!ok) { + return NULL; + } + + ok = samba_DATA_BLOB_from_PyObject(py_key_salt, &key_salt_blob); + if (!ok) { + return NULL; + } + + ok = samba_DATA_BLOB_from_PyObject(py_mac_salt, &mac_salt_blob); + if (!ok) { + return NULL; + } + + ok = samba_DATA_BLOB_from_PyObject(py_iv, &iv_blob); + if (!ok) { + return NULL; + } + + ctx = talloc_new(NULL); + if (ctx == NULL) { + return PyErr_NoMemory(); + } + + /* Encrypt the plaintext. */ + status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(ctx, + &plaintext_blob, + &cek_blob, + &key_salt_blob, + &mac_salt_blob, + &iv_blob, + &ciphertext_blob, + auth_data); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + talloc_free(ctx); + return NULL; + } + + /* Convert the output into Python 'bytes' objects. */ + py_ciphertext = PyBytes_FromStringAndSize((const char *)ciphertext_blob.data, + ciphertext_blob.length); + talloc_free(ctx); + if (py_ciphertext == NULL) { + return NULL; + } + py_auth_data = PyBytes_FromStringAndSize((const char *)auth_data, + sizeof(auth_data)); + if (py_auth_data == NULL) { + return NULL; + } + + /* Steal ciphertext and auth_data into a new tuple. */ + py_result = Py_BuildValue("(NN)", py_ciphertext, py_auth_data); + + return py_result; +} + + + static const char py_crypto_arcfour_crypt_blob_doc[] = "arcfour_crypt_blob(data, key)\n" "Encrypt the data with RC4 algorithm using the key"; @@ -201,12 +405,29 @@ static const char py_crypto_des_crypt_blob_16_doc[] = "des_crypt_blob_16(data, k static const char py_crypto_md4_hash_blob_doc[] = "md4_hash_blob(data) -> bytes\n" "Hash the data with MD4 algorithm"; +static const char py_crypto_sha512_pbkdf2_doc[] = "sha512_pbkdf2(key, salt, iterations) -> bytes\n" + "Derive a key from an existing one with SHA512 " + "algorithm"; + +static const char py_crypto_aead_aes_256_cbc_hmac_sha512_blob_doc[] = + "aead_aes_256_cbc_hmac_sha512_blob(plaintext, cek, key_salt, " + "mac_salt, iv) -> ciphertext, auth_data\n" + "Encrypt the plaintext with AES256 as specified in " + "[MS-SAMR] 3.2.2.4 AES Cipher Usage"; + static PyMethodDef py_crypto_methods[] = { { "arcfour_crypt_blob", (PyCFunction)py_crypto_arcfour_crypt_blob, METH_VARARGS, py_crypto_arcfour_crypt_blob_doc }, { "set_relax_mode", (PyCFunction)py_crypto_set_relax_mode, METH_NOARGS, "Set fips to relax mode" }, { "set_strict_mode", (PyCFunction)py_crypto_set_strict_mode, METH_NOARGS, "Set fips to strict mode" }, { "des_crypt_blob_16", (PyCFunction)py_crypto_des_crypt_blob_16, METH_VARARGS, py_crypto_des_crypt_blob_16_doc }, { "md4_hash_blob", (PyCFunction)py_crypto_md4_hash_blob, METH_VARARGS, py_crypto_md4_hash_blob_doc }, + { "sha512_pbkdf2", (PyCFunction)py_crypto_sha512_pbkdf2, METH_VARARGS, py_crypto_sha512_pbkdf2_doc }, + { + "aead_aes_256_cbc_hmac_sha512_blob", + (PyCFunction)py_crypto_aead_aes_256_cbc_hmac_sha512_blob, + METH_VARARGS, + py_crypto_aead_aes_256_cbc_hmac_sha512_blob_doc + }, {0}, }; |