summaryrefslogtreecommitdiffstats
path: root/src/util/crypto
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
commit74aa0bc6779af38018a03fd2cf4419fe85917904 (patch)
tree9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/util/crypto
parentInitial commit. (diff)
downloadsssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz
sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/util/crypto')
-rw-r--r--src/util/crypto/libcrypto/crypto_base64.c133
-rw-r--r--src/util/crypto/libcrypto/crypto_hmac_sha1.c49
-rw-r--r--src/util/crypto/libcrypto/crypto_obfuscate.c313
-rw-r--r--src/util/crypto/libcrypto/crypto_prng.c42
-rw-r--r--src/util/crypto/libcrypto/crypto_sha512crypt.c382
-rw-r--r--src/util/crypto/libcrypto/sss_openssl.h39
-rw-r--r--src/util/crypto/sss_crypto.h63
7 files changed, 1021 insertions, 0 deletions
diff --git a/src/util/crypto/libcrypto/crypto_base64.c b/src/util/crypto/libcrypto/crypto_base64.c
new file mode 100644
index 0000000..11a0648
--- /dev/null
+++ b/src/util/crypto/libcrypto/crypto_base64.c
@@ -0,0 +1,133 @@
+/*
+ Authors:
+ Jan Cholasta <jcholast@redhat.com>
+ George McCollister <george.mccollister@gmail.com>
+
+ Copyright (C) 2012 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "util/crypto/sss_crypto.h"
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+
+char *sss_base64_encode(TALLOC_CTX *mem_ctx,
+ const unsigned char *in,
+ size_t insize)
+{
+ char *b64encoded = NULL, *outbuf = NULL;
+ int i, j, b64size;
+ BIO *bmem, *b64;
+
+ b64 = BIO_new(BIO_f_base64());
+ if (!b64) return NULL;
+
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+ bmem = BIO_new(BIO_s_mem());
+ if (!bmem) goto done;
+
+ b64 = BIO_push(b64, bmem);
+
+ BIO_write(b64, in, insize);
+
+ (void) BIO_flush(b64);
+
+ b64size = BIO_get_mem_data(bmem, &b64encoded);
+ if (b64encoded) {
+ outbuf = talloc_array(mem_ctx, char, b64size+1);
+ if (outbuf == NULL) goto done;
+
+ for (i=0, j=0; i < b64size; i++) {
+ if (b64encoded[i] == '\n' || b64encoded[i] == '\r') {
+ continue;
+ }
+ outbuf[j++] = b64encoded[i];
+ }
+ outbuf[j++] = '\0';
+ }
+
+done:
+ BIO_free_all(b64);
+ return outbuf;
+}
+
+unsigned char *sss_base64_decode(TALLOC_CTX *mem_ctx,
+ const char *in,
+ size_t *outsize)
+{
+ unsigned char *outbuf = NULL;
+ unsigned char *b64decoded = NULL;
+ unsigned char inbuf[512];
+ char * in_dup;
+ int size, inlen = strlen(in);
+ BIO *bmem, *b64, *bmem_out;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return NULL;
+ }
+
+ in_dup = talloc_size(tmp_ctx, inlen+1);
+ if (!in_dup) goto done;
+ memcpy(in_dup, in, inlen+1);
+
+ b64 = BIO_new(BIO_f_base64());
+ if (!b64) goto done;
+
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+
+ bmem = BIO_new_mem_buf(in_dup, -1);
+ if (!bmem) {
+ BIO_free(b64);
+ goto done;
+ }
+
+ b64 = BIO_push(b64, bmem);
+
+ bmem_out = BIO_new(BIO_s_mem());
+ if (!bmem_out) {
+ BIO_free_all(b64);
+ goto done;
+ }
+
+ while((inlen = BIO_read(b64, inbuf, 512)) > 0)
+ BIO_write(bmem_out, inbuf, inlen);
+
+ (void) BIO_flush(bmem_out);
+
+ size = BIO_get_mem_data(bmem_out, &b64decoded);
+
+ if (b64decoded) {
+ outbuf = talloc_memdup(mem_ctx, b64decoded, size);
+ if (!outbuf) {
+ BIO_free_all(b64);
+ BIO_free(bmem_out);
+ goto done;
+ }
+
+ *outsize = size;
+ } else {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get decoded data\n");
+ }
+ BIO_free_all(b64);
+ BIO_free(bmem_out);
+
+done:
+ talloc_free(tmp_ctx);
+ return outbuf;
+}
diff --git a/src/util/crypto/libcrypto/crypto_hmac_sha1.c b/src/util/crypto/libcrypto/crypto_hmac_sha1.c
new file mode 100644
index 0000000..9b072ad
--- /dev/null
+++ b/src/util/crypto/libcrypto/crypto_hmac_sha1.c
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2019 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+#include <openssl/hmac.h>
+
+#include "util/util.h"
+#include "util/crypto/sss_crypto.h"
+
+
+int sss_hmac_sha1(const unsigned char *key, size_t key_len,
+ const unsigned char *in, size_t in_len,
+ unsigned char *out)
+{
+ unsigned int res_len = 0;
+ unsigned char md[EVP_MAX_MD_SIZE];
+
+ if ((key == NULL) || (key_len == 0) || (key_len > INT_MAX)
+ || (in == NULL) || (in_len == 0) || (in_len > INT_MAX)
+ || (out == NULL)) {
+ return EINVAL;
+ }
+
+ if (!HMAC(EVP_sha1(), key, (int)key_len, in, (int)in_len, md, &res_len)) {
+ return EINVAL;
+ }
+
+ if (res_len != SSS_SHA1_LENGTH) {
+ return EINVAL;
+ }
+
+ memcpy(out, md, SSS_SHA1_LENGTH);
+
+ return EOK;
+}
diff --git a/src/util/crypto/libcrypto/crypto_obfuscate.c b/src/util/crypto/libcrypto/crypto_obfuscate.c
new file mode 100644
index 0000000..2cef61b
--- /dev/null
+++ b/src/util/crypto/libcrypto/crypto_obfuscate.c
@@ -0,0 +1,313 @@
+/*
+ SSSD
+
+ Password obfuscation logic
+
+ Authors:
+ George McCollister <george.mccollister@gmail.com>
+
+ Copyright (C) George McCollister 2012
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * READ ME:
+ *
+ * Please note that password obfuscation does not improve security in any
+ * way. It is just a mechanism to make the password human-unreadable.
+ */
+
+#include "config.h"
+#include <talloc.h>
+#include <errno.h>
+
+#include "util/util.h"
+#include "util/crypto/sss_crypto.h"
+
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+#define OBF_BUFFER_SENTINEL "\0\1\2\3"
+#define OBF_BUFFER_SENTINEL_SIZE 4
+
+struct crypto_mech_data {
+ const EVP_CIPHER * (*cipher)(void);
+ uint16_t keylen;
+ uint16_t bsize;
+};
+
+static struct crypto_mech_data cmdata[] = {
+ /* AES with automatic padding, 256b key, 128b block */
+ { EVP_aes_256_cbc, 32, 16 },
+ /* sentinel */
+ { 0, 0, 0 }
+};
+
+static struct crypto_mech_data *get_crypto_mech_data(enum obfmethod meth)
+{
+ if (meth >= NUM_OBFMETHODS) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported cipher type\n");
+ return NULL;
+ }
+ return &cmdata[meth];
+}
+
+int sss_password_encrypt(TALLOC_CTX *mem_ctx, const char *password, int plen,
+ enum obfmethod meth, char **obfpwd)
+{
+ int ret;
+ EVP_CIPHER_CTX *ctx;
+ struct crypto_mech_data *mech_props;
+ TALLOC_CTX *tmp_ctx = NULL;
+ unsigned char *keybuf;
+ unsigned char *ivbuf;
+ unsigned char *cryptotext;
+ int ct_maxsize;
+ int ctlen = 0;
+ int digestlen = 0;
+ int result_len;
+
+ unsigned char *obfbuf;
+ size_t obufsize = 0;
+ size_t p = 0;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ mech_props = get_crypto_mech_data(meth);
+ if (mech_props == NULL) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ keybuf = talloc_array(tmp_ctx, unsigned char, mech_props->keylen);
+ if (keybuf == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ivbuf = talloc_array(tmp_ctx, unsigned char, mech_props->bsize);
+ if (ivbuf == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sss_generate_csprng_buffer((uint8_t *)keybuf, mech_props->keylen);
+ if (ret != EOK) {
+ goto done;
+ }
+ ret = sss_generate_csprng_buffer((uint8_t *)ivbuf, mech_props->bsize);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* cryptotext buffer must be at least len(plaintext)+blocksize */
+ ct_maxsize = plen + (mech_props->bsize);
+ cryptotext = talloc_array(tmp_ctx, unsigned char, ct_maxsize);
+ if (!cryptotext) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (!EVP_EncryptInit_ex(ctx, mech_props->cipher(), 0, keybuf, ivbuf)) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failure to initialize cipher contex\n");
+ ret = EIO;
+ goto done;
+ }
+
+ /* sample data we'll encrypt and decrypt */
+ if (!EVP_EncryptUpdate(ctx, cryptotext, &ctlen, (const unsigned char *)password, plen)) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot execute the encryption operation\n");
+ ret = EIO;
+ goto done;
+ }
+
+ if (!EVP_EncryptFinal_ex(ctx, cryptotext + ctlen, &digestlen)) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot finialize the encryption operation\n");
+ ret = EIO;
+ goto done;
+ }
+
+ result_len = ctlen + digestlen;
+ if (result_len < 0 || result_len > UINT16_MAX) {
+ ret = ERANGE;
+ goto done;
+ }
+
+ /* Pack the obfuscation buffer */
+ /* The buffer consists of:
+ * uint16_t the type of the cipher
+ * uint16_t length of the cryptotext in bytes (clen)
+ * uint8_t[klen] key
+ * uint8_t[blen] IV
+ * uint8_t[clen] cryptotext
+ * 4 bytes of "sentinel" denoting end of the buffer
+ */
+ obufsize = sizeof(uint16_t) + sizeof(uint16_t) +
+ mech_props->keylen + mech_props->bsize +
+ result_len + OBF_BUFFER_SENTINEL_SIZE;
+ obfbuf = talloc_array(tmp_ctx, unsigned char, obufsize);
+ if (!obfbuf) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Writing method: %d\n", meth);
+ SAFEALIGN_SET_UINT16(&obfbuf[p], meth, &p);
+ DEBUG(SSSDBG_TRACE_FUNC, "Writing bufsize: %d\n", result_len);
+ SAFEALIGN_SET_UINT16(&obfbuf[p], result_len, &p);
+ safealign_memcpy(&obfbuf[p], keybuf, mech_props->keylen, &p);
+ safealign_memcpy(&obfbuf[p], ivbuf, mech_props->bsize, &p);
+ safealign_memcpy(&obfbuf[p], cryptotext, result_len, &p);
+ safealign_memcpy(&obfbuf[p], OBF_BUFFER_SENTINEL,
+ OBF_BUFFER_SENTINEL_SIZE, &p);
+
+ /* Base64 encode the resulting buffer */
+ *obfpwd = sss_base64_encode(mem_ctx, obfbuf, obufsize);
+ if (*obfpwd == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
+}
+
+int sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
+ char **password)
+{
+ int ret;
+ EVP_CIPHER_CTX *ctx;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct crypto_mech_data *mech_props;
+
+ int plainlen;
+ int digestlen;
+ unsigned char *obfbuf = NULL;
+ size_t obflen;
+ char *pwdbuf;
+
+ /* for unmarshaling data */
+ uint16_t meth;
+ uint16_t ctsize;
+ size_t p = 0;
+ unsigned char *cryptotext;
+ unsigned char *keybuf;
+ unsigned char *ivbuf;
+ unsigned char sentinel_check[OBF_BUFFER_SENTINEL_SIZE];
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Base64 decode the incoming buffer */
+ obfbuf = sss_base64_decode(tmp_ctx, b64encoded, &obflen);
+ if (!obfbuf) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* unpack obfuscation buffer */
+ SAFEALIGN_COPY_UINT16_CHECK(&meth, obfbuf+p, obflen, &p);
+ DEBUG(SSSDBG_TRACE_FUNC, "Read method: %d\n", meth);
+ SAFEALIGN_COPY_UINT16_CHECK(&ctsize, obfbuf+p, obflen, &p);
+ DEBUG(SSSDBG_TRACE_FUNC, "Read bufsize: %d\n", ctsize);
+
+ mech_props = get_crypto_mech_data(meth);
+ if (mech_props == NULL) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ /* check that we got sane mechanism properties and cryptotext size */
+ memcpy(sentinel_check,
+ obfbuf + p + mech_props->keylen + mech_props->bsize + ctsize,
+ OBF_BUFFER_SENTINEL_SIZE);
+ if (memcmp(sentinel_check, OBF_BUFFER_SENTINEL, OBF_BUFFER_SENTINEL_SIZE) != 0) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Obfuscation buffer seems corrupt, aborting\n");
+ ret = EFAULT;
+ goto done;
+ }
+
+ /* copy out key, ivbuf and cryptotext */
+ keybuf = talloc_array(tmp_ctx, unsigned char, mech_props->keylen);
+ if (keybuf == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ safealign_memcpy(keybuf, obfbuf+p, mech_props->keylen, &p);
+
+ ivbuf = talloc_array(tmp_ctx, unsigned char, mech_props->bsize);
+ if (ivbuf == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ safealign_memcpy(ivbuf, obfbuf+p, mech_props->bsize, &p);
+
+ cryptotext = talloc_array(tmp_ctx, unsigned char, ctsize);
+ if (cryptotext == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ safealign_memcpy(cryptotext, obfbuf+p, ctsize, &p);
+
+ pwdbuf = talloc_array(tmp_ctx, char, ctsize);
+ if (!pwdbuf) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (!EVP_DecryptInit_ex(ctx, mech_props->cipher(), 0, keybuf, ivbuf)) {
+ ret = EIO;
+ goto done;
+ }
+
+ /* sample data we'll encrypt and decrypt */
+ if (!EVP_DecryptUpdate(ctx, (unsigned char *)pwdbuf, &plainlen, cryptotext, ctsize)) {
+ ret = EIO;
+ goto done;
+ }
+
+ if (!EVP_DecryptFinal_ex(ctx, (unsigned char *)pwdbuf + plainlen, &digestlen)) {
+ ret = EIO;
+ goto done;
+ }
+
+ *password = talloc_move(mem_ctx, &pwdbuf);
+ ret = EOK;
+done:
+ talloc_free(tmp_ctx);
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
+}
diff --git a/src/util/crypto/libcrypto/crypto_prng.c b/src/util/crypto/libcrypto/crypto_prng.c
new file mode 100644
index 0000000..32e5b60
--- /dev/null
+++ b/src/util/crypto/libcrypto/crypto_prng.c
@@ -0,0 +1,42 @@
+/*
+ Copyright (C) Red Hat 2019
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <openssl/rand.h>
+
+#include "util/util_errors.h"
+#include "util/crypto/sss_crypto.h"
+
+int sss_generate_csprng_buffer(uint8_t *buf, size_t size)
+{
+ if ((buf == NULL) || (size > INT_MAX)) {
+ return EINVAL;
+ }
+
+ if (RAND_bytes((unsigned char *)buf, (int)size) == 1) {
+ return EOK;
+ }
+
+ return EAGAIN;
+}
diff --git a/src/util/crypto/libcrypto/crypto_sha512crypt.c b/src/util/crypto/libcrypto/crypto_sha512crypt.c
new file mode 100644
index 0000000..c816d26
--- /dev/null
+++ b/src/util/crypto/libcrypto/crypto_sha512crypt.c
@@ -0,0 +1,382 @@
+/* This file is based on nss_sha512crypt.c which is based on the work of
+ * Ulrich Drepper (http://people.redhat.com/drepper/SHA-crypt.txt).
+ *
+ * libcrypto is used to provide SHA512 and random number generation.
+ * (http://www.openssl.org/docs/crypto/crypto.html).
+ *
+ * Sumit Bose <sbose@redhat.com>
+ * George McCollister <georgem@novatech-llc.com>
+ */
+/* SHA512-based UNIX crypt implementation.
+ Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>. */
+
+#include "config.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include "util/util.h"
+#include "util/sss_endian.h"
+#include "util/crypto/sss_crypto.h"
+
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+#include "sss_openssl.h"
+
+
+/* Define our magic string to mark salt for SHA512 "encryption" replacement. */
+const char sha512_salt_prefix[] = "$6$";
+#define SALT_PREF_SIZE (sizeof(sha512_salt_prefix) - 1)
+
+/* Prefix for optional rounds specification. */
+const char sha512_rounds_prefix[] = "rounds=";
+#define ROUNDS_SIZE (sizeof(sha512_rounds_prefix) - 1)
+
+#define SALT_LEN_MAX 16
+#define ROUNDS_DEFAULT 5000
+#define ROUNDS_MIN 1000
+#define ROUNDS_MAX 999999999
+
+/* Table with characters for base64 transformation. */
+const char b64t[64] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+/* base64 conversion function */
+static inline void b64_from_24bit(char **dest, size_t *len, size_t n,
+ uint8_t b2, uint8_t b1, uint8_t b0)
+{
+ uint32_t w;
+ size_t i;
+
+ if (*len < n) n = *len;
+
+ w = (b2 << 16) | (b1 << 8) | b0;
+ for (i = 0; i < n; i++) {
+ (*dest)[i] = b64t[w & 0x3f];
+ w >>= 6;
+ }
+
+ *len -= i;
+ *dest += i;
+}
+
+static int sha512_crypt_r(const char *key,
+ const char *salt,
+ char *buffer, size_t buflen)
+{
+ unsigned char temp_result[64];
+ unsigned char alt_result[64];
+ size_t rounds = ROUNDS_DEFAULT;
+ bool rounds_custom = false;
+ EVP_MD_CTX *alt_ctx = NULL;
+ EVP_MD_CTX *ctx;
+ size_t salt_len;
+ size_t key_len;
+ size_t cnt;
+ char *p_bytes = NULL;
+ char *s_bytes = NULL;
+ int p1, p2, p3, pt, n;
+ unsigned int part;
+ char *cp;
+ int ret;
+
+ /* Find beginning of salt string. The prefix should normally always be
+ * present. Just in case it is not. */
+ if (strncmp(salt, sha512_salt_prefix, SALT_PREF_SIZE) == 0) {
+ /* Skip salt prefix. */
+ salt += SALT_PREF_SIZE;
+ }
+
+ if (strncmp(salt, sha512_rounds_prefix, ROUNDS_SIZE) == 0) {
+ unsigned long int srounds;
+ const char *num;
+ char *endp;
+
+ num = salt + ROUNDS_SIZE;
+ errno = 0;
+ srounds = strtoul(num, &endp, 10);
+ if (!errno && (*endp == '$')) {
+ salt = endp + 1;
+ if (srounds < ROUNDS_MIN) srounds = ROUNDS_MIN;
+ if (srounds > ROUNDS_MAX) srounds = ROUNDS_MAX;
+ rounds = srounds;
+ rounds_custom = true;
+ }
+ }
+
+ salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
+ key_len = strlen(key);
+
+ ctx = EVP_MD_CTX_new();
+ if (ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ alt_ctx = EVP_MD_CTX_new();
+ if (alt_ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Prepare for the real work. */
+ if (!EVP_DigestInit_ex(ctx, EVP_sha512(), NULL)) {
+ ret = EIO;
+ goto done;
+ }
+
+ /* Add the key string. */
+ EVP_DigestUpdate(ctx, (const unsigned char *)key, key_len);
+
+ /* The last part is the salt string. This must be at most 16
+ * characters and it ends at the first `$' character (for
+ * compatibility with existing implementations). */
+ EVP_DigestUpdate(ctx, (const unsigned char *)salt, salt_len);
+
+ /* Compute alternate SHA512 sum with input KEY, SALT, and KEY.
+ * The final result will be added to the first context. */
+ if (!EVP_DigestInit_ex(alt_ctx, EVP_sha512(), NULL)) {
+ ret = EIO;
+ goto done;
+ }
+
+ /* Add key. */
+ EVP_DigestUpdate(alt_ctx, (const unsigned char *)key, key_len);
+
+ /* Add salt. */
+ EVP_DigestUpdate(alt_ctx, (const unsigned char *)salt, salt_len);
+
+ /* Add key again. */
+ EVP_DigestUpdate(alt_ctx, (const unsigned char *)key, key_len);
+
+ /* Now get result of this (64 bytes) and add it to the other context. */
+ EVP_DigestFinal_ex(alt_ctx, alt_result, &part);
+
+ /* Add for any character in the key one byte of the alternate sum. */
+ for (cnt = key_len; cnt > 64; cnt -= 64) {
+ EVP_DigestUpdate(ctx, alt_result, 64);
+ }
+ EVP_DigestUpdate(ctx, alt_result, cnt);
+
+ /* Take the binary representation of the length of the key and for every
+ * 1 add the alternate sum, for every 0 the key. */
+ for (cnt = key_len; cnt > 0; cnt >>= 1) {
+ if ((cnt & 1) != 0) {
+ EVP_DigestUpdate(ctx, alt_result, 64);
+ } else {
+ EVP_DigestUpdate(ctx, (const unsigned char *)key, key_len);
+ }
+ }
+
+ /* Create intermediate result. */
+ EVP_DigestFinal_ex(ctx, alt_result, &part);
+
+ /* Start computation of P byte sequence. */
+ if (!EVP_DigestInit_ex(alt_ctx, EVP_sha512(), NULL)) {
+ ret = EIO;
+ goto done;
+ }
+
+ /* For every character in the password add the entire password. */
+ for (cnt = 0; cnt < key_len; cnt++) {
+ EVP_DigestUpdate(alt_ctx, (const unsigned char *)key, key_len);
+ }
+
+ /* Finish the digest. */
+ EVP_DigestFinal_ex(alt_ctx, temp_result, &part);
+
+ /* Create byte sequence P. */
+ cp = p_bytes = alloca(key_len);
+ for (cnt = key_len; cnt >= 64; cnt -= 64) {
+ cp = mempcpy(cp, temp_result, 64);
+ }
+ memcpy(cp, temp_result, cnt);
+
+ /* Start computation of S byte sequence. */
+ if (!EVP_DigestInit_ex(alt_ctx, EVP_sha512(), NULL)) {
+ ret = EIO;
+ goto done;
+ }
+
+ for (cnt = 0; cnt < 16 + alt_result[0]; cnt++) {
+ EVP_DigestUpdate(alt_ctx, (const unsigned char *)salt, salt_len);
+ }
+
+ /* Finish the digest. */
+ EVP_DigestFinal_ex(alt_ctx, temp_result, &part);
+
+ /* Create byte sequence S. */
+ cp = s_bytes = alloca(salt_len);
+ for (cnt = salt_len; cnt >= 64; cnt -= 64) {
+ cp = mempcpy(cp, temp_result, 64);
+ }
+ memcpy(cp, temp_result, cnt);
+
+ /* Repeatedly run the collected hash value through SHA512 to burn CPU cycles. */
+ for (cnt = 0; cnt < rounds; cnt++) {
+
+ if (!EVP_DigestInit_ex(ctx, EVP_sha512(), NULL)) {
+ ret = EIO;
+ goto done;
+ }
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0) {
+ EVP_DigestUpdate(ctx, (const unsigned char *)p_bytes, key_len);
+ } else {
+ EVP_DigestUpdate(ctx, alt_result, 64);
+ }
+
+ /* Add salt for numbers not divisible by 3. */
+ if (cnt % 3 != 0) {
+ EVP_DigestUpdate(ctx, (const unsigned char *)s_bytes, salt_len);
+ }
+
+ /* Add key for numbers not divisible by 7. */
+ if (cnt % 7 != 0) {
+ EVP_DigestUpdate(ctx, (const unsigned char *)p_bytes, key_len);
+ }
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0) {
+ EVP_DigestUpdate(ctx, alt_result, 64);
+ } else {
+ EVP_DigestUpdate(ctx, (const unsigned char *)p_bytes, key_len);
+ }
+
+ /* Create intermediate result. */
+ EVP_DigestFinal_ex(ctx, alt_result, &part);
+ }
+
+ /* Now we can construct the result string.
+ * It consists of three parts. */
+ if (buflen <= SALT_PREF_SIZE) {
+ ret = ERANGE;
+ goto done;
+ }
+
+ cp = memcpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
+ cp += SALT_PREF_SIZE;
+ buflen -= SALT_PREF_SIZE;
+
+ if (rounds_custom) {
+ n = snprintf(cp, buflen, "%s%zu$",
+ sha512_rounds_prefix, rounds);
+ if (n < 0 || n >= buflen) {
+ ret = ERANGE;
+ goto done;
+ }
+ cp += n;
+ buflen -= n;
+ }
+
+ if (buflen <= salt_len + 1) {
+ ret = ERANGE;
+ goto done;
+ }
+ cp = stpncpy(cp, salt, salt_len);
+ *cp++ = '$';
+ buflen -= salt_len + 1;
+
+ /* fuzzyfill the base 64 string */
+ p1 = 0;
+ p2 = 21;
+ p3 = 42;
+ for (n = 0; n < 21; n++) {
+ b64_from_24bit(&cp, &buflen, 4, alt_result[p1], alt_result[p2], alt_result[p3]);
+ if (buflen == 0) {
+ ret = ERANGE;
+ goto done;
+ }
+ pt = p1;
+ p1 = p2 + 1;
+ p2 = p3 + 1;
+ p3 = pt + 1;
+ }
+ /* 64th and last byte */
+ b64_from_24bit(&cp, &buflen, 2, 0, 0, alt_result[p3]);
+ if (buflen == 0) {
+ ret = ERANGE;
+ goto done;
+ }
+
+ *cp = '\0';
+ ret = EOK;
+
+done:
+ /* Clear the buffer for the intermediate result so that people attaching
+ * to processes or reading core dumps cannot get any information. We do it
+ * in this way to clear correct_words[] inside the SHA512 implementation
+ * as well. */
+ EVP_MD_CTX_free(ctx);
+ EVP_MD_CTX_free(alt_ctx);
+ if (p_bytes != NULL) {
+ sss_erase_mem_securely(p_bytes, key_len);
+ }
+ if (s_bytes != NULL) {
+ sss_erase_mem_securely(s_bytes, salt_len);
+ }
+ sss_erase_mem_securely(temp_result, sizeof(temp_result));
+ sss_erase_mem_securely(alt_result, sizeof(alt_result));
+
+ return ret;
+}
+
+int s3crypt_sha512(TALLOC_CTX *memctx,
+ const char *key, const char *salt, char **_hash)
+{
+ char *hash;
+ int hlen = (sizeof (sha512_salt_prefix) - 1
+ + sizeof (sha512_rounds_prefix) + 9 + 1
+ + strlen (salt) + 1 + 86 + 1);
+ int ret;
+
+ hash = talloc_size(memctx, hlen);
+ if (!hash) return ENOMEM;
+
+ ret = sha512_crypt_r(key, salt, hash, hlen);
+ if (ret) return ret;
+
+ *_hash = hash;
+ return ret;
+}
+
+#define SALT_RAND_LEN 12
+
+int s3crypt_gen_salt(TALLOC_CTX *memctx, char **_salt)
+{
+ uint8_t rb[SALT_RAND_LEN];
+ char *salt, *cp;
+ size_t slen;
+ int ret;
+
+ ret = sss_generate_csprng_buffer(rb, SALT_RAND_LEN);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ salt = talloc_size(memctx, SALT_LEN_MAX + 1);
+ if (!salt) {
+ return ENOMEM;
+ }
+
+ slen = SALT_LEN_MAX;
+ cp = salt;
+ b64_from_24bit(&cp, &slen, 4, rb[0], rb[1], rb[2]);
+ b64_from_24bit(&cp, &slen, 4, rb[3], rb[4], rb[5]);
+ b64_from_24bit(&cp, &slen, 4, rb[6], rb[7], rb[8]);
+ b64_from_24bit(&cp, &slen, 4, rb[9], rb[10], rb[11]);
+ *cp = '\0';
+
+ *_salt = salt;
+
+ return EOK;
+}
diff --git a/src/util/crypto/libcrypto/sss_openssl.h b/src/util/crypto/libcrypto/sss_openssl.h
new file mode 100644
index 0000000..a2e2d85
--- /dev/null
+++ b/src/util/crypto/libcrypto/sss_openssl.h
@@ -0,0 +1,39 @@
+/*
+ Authors:
+ Lukas Slebodnik <lslebodn@redhat.com>
+
+ Copyright (C) 2016 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SSS_LIBCRYTPO_SSS_OPENSSL_H_
+#define _SSS_LIBCRYTPO_SSS_OPENSSL_H_
+
+#include <openssl/evp.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+/* EVP_MD_CTX_create and EVP_MD_CTX_destroy are deprecated macros
+ * in openssl-1.1 but openssl-1.0 does not know anything about
+ * newly added functions EVP_MD_CTX_new, EVP_MD_CTX_free in 1.1
+ */
+
+# define EVP_MD_CTX_new() EVP_MD_CTX_create()
+# define EVP_MD_CTX_free(ctx) EVP_MD_CTX_destroy((ctx))
+
+#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
+
+
+#endif /* _SSS_LIBCRYTPO_SSS_OPENSSL_H_ */
diff --git a/src/util/crypto/sss_crypto.h b/src/util/crypto/sss_crypto.h
new file mode 100644
index 0000000..db6b154
--- /dev/null
+++ b/src/util/crypto/sss_crypto.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2009-2016 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SSS_CRYPTO_H_
+#define _SSS_CRYPTO_H_
+
+#include <talloc.h>
+#include <stdint.h>
+
+/* Guaranteed either to fill given buffer with crypto strong random data
+ * or to fail with error code (for example in the case of the lack of
+ * proper entropy)
+ * Suitable to be used in security relevant context.
+ */
+int sss_generate_csprng_buffer(uint8_t *buf, size_t size);
+
+int s3crypt_sha512(TALLOC_CTX *mmectx,
+ const char *key, const char *salt, char **_hash);
+int s3crypt_gen_salt(TALLOC_CTX *memctx, char **_salt);
+
+/* Methods of obfuscation. */
+enum obfmethod {
+ AES_256,
+ NUM_OBFMETHODS
+};
+
+char *sss_base64_encode(TALLOC_CTX *mem_ctx,
+ const unsigned char *in,
+ size_t insize);
+
+unsigned char *sss_base64_decode(TALLOC_CTX *mem_ctx,
+ const char *in,
+ size_t *outsize);
+
+#define SSS_SHA1_LENGTH 20
+
+int sss_hmac_sha1(const unsigned char *key,
+ size_t key_len,
+ const unsigned char *in,
+ size_t in_len,
+ unsigned char *out);
+
+int sss_password_encrypt(TALLOC_CTX *mem_ctx, const char *password, int plen,
+ enum obfmethod meth, char **obfpwd);
+
+int sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
+ char **password);
+
+#endif /* _SSS_CRYPTO_H_ */