From 86743565b5ec5a304e7319823a282943ee6441f7 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Mon, 2 Aug 2010 16:53:28 +0200
Subject: [PATCH 3/7] Password obfuscation utility functions

Adds two utility functions to obfuscate a password and inverse to
extract the cleartext password back.

So far, only NSS-based implementation is provided.
---
 Makefile.am                                  |   19 +-
 src/tests/crypto-tests.c                     |  139 ++++++++
 src/util/crypto/libcrypto/crypto_obfuscate.c |   16 +
 src/util/crypto/nss/nss_obfuscate.c          |  471 ++++++++++++++++++++++++++
 src/util/crypto/sss_crypto.h                 |   14 +
 5 files changed, 658 insertions(+), 1 deletions(-)
 create mode 100644 src/tests/crypto-tests.c
 create mode 100644 src/util/crypto/libcrypto/crypto_obfuscate.c
 create mode 100644 src/util/crypto/nss/nss_obfuscate.c

diff --git a/Makefile.am b/Makefile.am
index b0e04b5..c06a360 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -81,6 +81,7 @@ if HAVE_CHECK
         auth-tests \
         ipa_ldap_opt-tests \
         simple_access-tests \
+        crypto-tests \
         util-tests
 endif
 
@@ -118,11 +119,13 @@ noinst_LTLIBRARIES = \
 
 if HAVE_NSS
     SSS_CRYPT_SOURCES = src/util/crypto/nss/nss_sha512crypt.c \
+                        src/util/crypto/nss/nss_obfuscate.c \
                         src/util/crypto/nss/nss_util.c
     SSS_CRYPT_CFLAGS = $(NSS_CFLAGS)
     SSS_CRYPT_LIBS = $(NSS_LIBS)
 else
-    SSS_CRYPT_SOURCES = src/util/crypto/libcrypto/crypto_sha512crypt.c
+    SSS_CRYPT_SOURCES = src/util/crypto/libcrypto/crypto_sha512crypt.c \
+                        src/util/crypto/libcrypto/crypto_obfuscate.c
     SSS_CRYPT_CFLAGS = $(CRYPTO_CFLAGS)
     SSS_CRYPT_LIBS = $(CRYPTO_LIBS)
 endif
@@ -678,6 +681,20 @@ util_tests_LDADD = \
     $(CHECK_LIBS) \
     libsss_test_common.la
 
+crypto_tests_SOURCES = \
+    $(SSSD_DEBUG_OBJ) \
+    $(SSS_CRYPT_SOURCES) \
+    src/tests/crypto-tests.c
+crypto_tests_CFLAGS = \
+    $(SSS_CRYPT_CFLAGS) \
+    $(AM_CFLAGS) \
+    $(CHECK_CFLAGS)
+crypto_tests_LDADD = \
+    $(SSS_CRYPT_LIBS) \
+    $(SSSD_LIBS) \
+    $(CHECK_LIBS) \
+    libsss_test_common.la
+
 endif
 
 stress_tests_SOURCES = \
diff --git a/src/tests/crypto-tests.c b/src/tests/crypto-tests.c
new file mode 100644
index 0000000..d02a843
--- /dev/null
+++ b/src/tests/crypto-tests.c
@@ -0,0 +1,139 @@
+/*
+   SSSD
+
+   Crypto tests
+
+   Author: Jakub Hrozek <jhrozek@redhat.com>
+
+   Copyright (C) Red Hat, Inc 2010
+
+   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 <stdlib.h>
+#include <popt.h>
+#include <check.h>
+
+#include "util/util.h"
+#include "tests/common.h"
+
+/* interfaces under test */
+#include "util/crypto/sss_crypto.h"
+#include "util/crypto/nss/nss_util.h"
+
+static TALLOC_CTX *test_ctx = NULL;
+
+#ifdef HAVE_NSS
+START_TEST(test_nss_init)
+{
+    int ret;
+
+    ret = nspr_nss_init();
+    fail_if(ret != EOK);
+
+    ret = nspr_nss_cleanup();
+    fail_if(ret != EOK);
+}
+END_TEST
+#endif
+
+START_TEST(test_encrypt_decrypt)
+{
+    const char *password[] = { "test123",             /* general */
+                               "12345678901234567",   /* just above blocksize */
+                               "",                    /* empty */
+                               NULL};                 /* sentinel */
+    int i;
+    char *obfpwd;
+    char *ctpwd;
+    int ret;
+
+    test_ctx = talloc_new(NULL);
+    fail_if(test_ctx == NULL);
+    check_leaks_push(test_ctx);
+
+    for (i=0; password[i]; i++) {
+        ret = sss_password_encrypt(test_ctx, password[i], strlen(password[i])+1,
+                                   AES_256, &obfpwd);
+        fail_if(ret != EOK);
+
+        ret = sss_password_decrypt(test_ctx, obfpwd, &ctpwd);
+        fail_if(ret != EOK);
+
+        fail_if(strcmp(password[i], ctpwd) != 0);
+
+        talloc_free(obfpwd);
+        talloc_free(ctpwd);
+    }
+
+    check_leaks_pop(test_ctx);
+    talloc_free(test_ctx);
+}
+END_TEST
+
+Suite *crypto_suite(void)
+{
+    Suite *s = suite_create("sss_crypto");
+
+    TCase *tc = tcase_create("sss crypto tests");
+    tcase_add_checked_fixture(tc, leak_check_setup, leak_check_teardown);
+    /* Do some testing */
+#ifdef HAVE_NSS
+    tcase_add_test(tc, test_nss_init);
+#endif
+    tcase_add_test(tc, test_encrypt_decrypt);
+    /* Add all test cases to the test suite */
+    suite_add_tcase(s, tc);
+
+    return s;
+}
+
+
+int main(int argc, const char *argv[])
+{
+    int opt;
+    poptContext pc;
+    int number_failed;
+    int debug;
+
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        { "debug-level", 'd', POPT_ARG_INT, &debug, 0, "Set debug level", NULL },
+        POPT_TABLEEND
+    };
+
+
+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+    while((opt = poptGetNextOpt(pc)) != -1) {
+        switch(opt) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                    poptBadOption(pc, 0), poptStrerror(opt));
+            poptPrintUsage(pc, stderr, 0);
+            return 1;
+        }
+    }
+    poptFreeContext(pc);
+
+    debug_level = debug;
+    tests_set_cwd();
+
+    Suite *s = crypto_suite();
+    SRunner *sr = srunner_create(s);
+    srunner_run_all(sr, CK_ENV);
+    number_failed = srunner_ntests_failed(sr);
+    srunner_free(sr);
+
+    return (number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/src/util/crypto/libcrypto/crypto_obfuscate.c b/src/util/crypto/libcrypto/crypto_obfuscate.c
new file mode 100644
index 0000000..026e993
--- /dev/null
+++ b/src/util/crypto/libcrypto/crypto_obfuscate.c
@@ -0,0 +1,16 @@
+#include <talloc.h>
+#include <errno.h>
+
+#include "util/crypto/sss_crypto.h"
+
+int sss_password_encrypt(TALLOC_CTX *mem_ctx, const char *password, int plen,
+                         enum obfmethod meth, char **obfpwd)
+{
+    return ENOSYS;
+}
+
+int sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
+                         char **password)
+{
+    return ENOSYS;
+}
diff --git a/src/util/crypto/nss/nss_obfuscate.c b/src/util/crypto/nss/nss_obfuscate.c
new file mode 100644
index 0000000..fc2eff8
--- /dev/null
+++ b/src/util/crypto/nss/nss_obfuscate.c
@@ -0,0 +1,471 @@
+/*
+   SSSD
+
+   Password obfuscation logic
+
+   Author: Jakub Hrozek <jhrozek@redhat.com>
+
+   Copyright (C) Red Hat, Inc 2010
+
+   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 <prerror.h>
+#include <nss.h>
+#include <pk11func.h>
+#include <base64.h>
+#include <talloc.h>
+
+#include "util/util.h"
+#include "util/crypto/sss_crypto.h"
+#include "util/crypto/nss/nss_util.h"
+
+#define OBF_BUFFER_SENTINEL "\0\1\2\3"
+#define OBF_BUFFER_SENTINEL_SIZE    4
+
+#define MAKE_SECITEM(sdata, slen, sitem) do { \
+    (sitem)->type = (siBuffer); \
+    (sitem)->data = (sdata);    \
+    (sitem)->len  = (slen);     \
+} while(0);
+
+struct sss_nss_crypto_ctx {
+    PK11SlotInfo *slot;
+    PK11Context  *ectx;
+    PK11SymKey   *keyobj;
+    SECItem      *sparam;
+
+    SECItem      *iv;
+    SECItem      *key;
+};
+
+struct crypto_mech_data {
+    CK_MECHANISM_TYPE cipher;
+    uint16_t keylen;
+    uint16_t bsize;
+};
+
+static struct crypto_mech_data cmdata[] = {
+    /* AES with automatic padding, 256b key, 128b block */
+    { CKM_AES_CBC_PAD, 32, 16 },
+    /* sentinel */
+    { 0, 0, 0 }
+};
+
+static struct crypto_mech_data *get_crypto_mech_data(enum obfmethod meth)
+{
+    if (meth >= NUM_OBFMETHODS) {
+        DEBUG(1, ("Unsupported cipher type\n"));
+        return NULL;
+    }
+    return &cmdata[meth];
+}
+
+static int generate_random_key(TALLOC_CTX *mem_ctx, size_t keylen,
+                               unsigned char **_key)
+{
+    unsigned char *randkey;
+    SECStatus sret;
+    int ret;
+
+    randkey = talloc_size(mem_ctx, keylen);
+    if (randkey == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    sret = PK11_GenerateRandom(randkey, keylen);
+    if (sret != SECSuccess) {
+        DEBUG(1, ("Unable to generate random data (err %d)\n",
+                  PR_GetError()));
+        ret = EIO;
+        goto done;
+    }
+
+    *_key = randkey;
+    ret = EOK;
+done:
+    if (ret != EOK) talloc_zfree(randkey);
+    return ret;
+}
+
+static int sss_nss_crypto_ctx_destructor(struct sss_nss_crypto_ctx *cctx)
+{
+    if (cctx->ectx) PK11_DestroyContext(cctx->ectx, PR_TRUE);
+    if (cctx->sparam) SECITEM_FreeItem(cctx->sparam, PR_TRUE);
+    if (cctx->slot) PK11_FreeSlot(cctx->slot);
+    if (cctx->keyobj) PK11_FreeSymKey(cctx->keyobj);
+
+    return EOK;
+}
+
+static int nss_encrypt_decrypt_init(TALLOC_CTX *mem_ctx,
+                                    struct crypto_mech_data *mech_props,
+                                    bool encrypt,
+                                    unsigned char *ivbuf,
+                                    unsigned char *keybuf,
+                                    struct sss_nss_crypto_ctx **_cctx)
+{
+    struct sss_nss_crypto_ctx *cctx;
+    CK_ATTRIBUTE_TYPE   op;
+    int ret;
+
+    cctx = talloc_zero(mem_ctx, struct sss_nss_crypto_ctx);
+    if (!cctx) {
+        return ENOMEM;
+    }
+    talloc_set_destructor(cctx, sss_nss_crypto_ctx_destructor);
+
+    cctx->iv = talloc_zero(cctx, SECItem);
+    cctx->key = talloc_zero(cctx, SECItem);
+    if (!cctx->iv || !cctx->key) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    MAKE_SECITEM(ivbuf, mech_props->bsize, cctx->iv);
+    MAKE_SECITEM(keybuf, mech_props->keylen, cctx->key);
+
+    op = encrypt ? CKA_ENCRYPT : CKA_DECRYPT;
+
+    cctx->slot = PK11_GetBestSlot(mech_props->cipher, NULL);
+    if (cctx->slot == NULL) {
+        DEBUG(1, ("Unable to find security device (err %d)\n",
+                  PR_GetError()));
+        ret = EIO;
+        goto done;
+    }
+
+    /* turn the raw key into a key object */
+    cctx->keyobj = PK11_ImportSymKey(cctx->slot, mech_props->cipher,
+                                     PK11_OriginUnwrap, op, cctx->key, NULL);
+    if (cctx->keyobj == NULL) {
+        DEBUG(1, ("Failure to import key into NSS (err %d)\n",
+                  PR_GetError()));
+        ret = EIO;
+        goto done;
+    }
+
+    /* turn the raw IV into a initialization vector object */
+    cctx->sparam = PK11_ParamFromIV(mech_props->cipher, cctx->iv);
+    if (cctx->sparam == NULL) {
+        DEBUG(1, ("Failure to set up PKCS11 param (err %d)\n",
+                  PR_GetError()));
+        ret = EIO;
+        goto done;
+    }
+
+    /* Create cipher context */
+    cctx->ectx = PK11_CreateContextBySymKey(mech_props->cipher, op,
+                                            cctx->keyobj, cctx->sparam);
+    if (cctx->ectx == NULL) {
+        DEBUG(1, ("Cannot create cipher context (err %d)\n",
+                  PORT_GetError()));
+        ret = EIO;
+        goto done;
+    }
+
+    ret = EOK;
+    *_cctx = cctx;
+done:
+    if (ret) talloc_zfree(cctx);
+    return ret;
+}
+
+/* NSS wraps b64 encoded buffers with CRLF automatically after 64 chars. This
+ * function strips the CRLF double-chars. The buffer can be decoded with plain
+ * NSS calls */
+static char *b64_encode(TALLOC_CTX *mem_ctx,
+                        unsigned char *inbuf,
+                        size_t inbufsize)
+{
+    char *b64encoded = NULL;
+    int i, j, b64size;
+    char *outbuf;
+
+    b64encoded = BTOA_DataToAscii(inbuf, inbufsize);
+    if (!b64encoded) return NULL;
+
+    b64size = strlen(b64encoded) + 1;
+    outbuf = talloc_array(mem_ctx, char, b64size);
+    if (outbuf == NULL) {
+        PORT_Free(b64encoded);
+        return NULL;
+    }
+
+    for (i=0, j=0; i < b64size; i++) {
+        if (b64encoded[i] == '\n' || b64encoded[i] == '\r') {
+            continue;
+        }
+        outbuf[j++] = b64encoded[i]; /* will also copy the trailing \0 char */
+    }
+
+    PORT_Free(b64encoded);
+    return outbuf;
+}
+
+int sss_password_encrypt(TALLOC_CTX *mem_ctx, const char *password, int plen,
+                         enum obfmethod meth, char **obfpwd)
+{
+    SECStatus sret;
+    int ret;
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct crypto_mech_data *mech_props;
+    struct sss_nss_crypto_ctx *cctx;
+
+    unsigned char *keybuf;
+    unsigned char *ivbuf;
+
+    unsigned char *cryptotext;
+    int ct_maxsize;
+    int ctlen;
+    unsigned int digestlen;
+    int result_len;
+
+    unsigned char *obfbuf;
+    size_t obufsize = 0;
+    size_t p = 0;
+
+    tmp_ctx = talloc_new(mem_ctx);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    /* initialize NSS if needed */
+    ret = nspr_nss_init();
+    if (ret != EOK) {
+        ret = EIO;
+        goto done;
+    }
+
+    mech_props = get_crypto_mech_data(meth);
+    if (mech_props == NULL) {
+        ret = EINVAL;
+        goto done;
+    }
+
+    /* generate random encryption and IV key */
+    ret = generate_random_key(tmp_ctx, mech_props->keylen, &keybuf);
+    if (ret != EOK) {
+        DEBUG(1, ("Could not generate encryption key\n"));
+        goto done;
+    }
+
+    ret = generate_random_key(tmp_ctx, mech_props->bsize, &ivbuf);
+    if (ret != EOK) {
+        DEBUG(1, ("Could not generate initialization vector\n"));
+        goto done;
+    }
+
+    ret = nss_encrypt_decrypt_init(tmp_ctx, mech_props, true,
+                                   keybuf, ivbuf, &cctx);
+    if (ret) {
+        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;
+    }
+
+    /* sample data we'll encrypt and decrypt */
+    sret = PK11_CipherOp(cctx->ectx, cryptotext, &ctlen, ct_maxsize,
+                         (unsigned char *) password, plen);
+    if (sret != SECSuccess) {
+        DEBUG(1, ("Cannot execute the encryption operation (err %d)\n",
+                   PR_GetError()));
+        ret = EIO;
+        goto done;
+    }
+
+    sret = PK11_DigestFinal(cctx->ectx, cryptotext+ctlen, &digestlen,
+                            ct_maxsize-ctlen);
+    if (sret != SECSuccess) {
+        DEBUG(1, ("Cannot execute the digest operation (err %d)\n",
+                    PR_GetError()));
+        ret = EIO;
+        goto done;
+    }
+    result_len = ctlen + digestlen;
+
+    /* Pack the obfuscation buffer */
+    /* The buffer consists of:
+     * uint16_t      the type of the cipher
+     * uint32_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(uint32_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(8, ("Writing method: %d\n", meth));
+    SAFEALIGN_SET_UINT16(&obfbuf[p], meth, &p);
+    DEBUG(8, ("Writing bufsize: %d\n", result_len));
+    SAFEALIGN_SET_UINT16(&obfbuf[p], result_len, &p);
+    safealign_memcpy(&obfbuf[p], cctx->key->data, mech_props->keylen, &p);
+    safealign_memcpy(&obfbuf[p], cctx->iv->data, 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 = b64_encode(mem_ctx, obfbuf, obufsize);
+    if (*obfpwd == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = EOK;
+done:
+    talloc_free(tmp_ctx);
+    nspr_nss_cleanup();
+    return ret;
+}
+
+int sss_password_decrypt(TALLOC_CTX *mem_ctx, char *b64encoded,
+                         char **password)
+{
+    SECStatus sret;
+    int ret;
+    TALLOC_CTX *tmp_ctx = NULL;
+    struct crypto_mech_data *mech_props;
+    struct sss_nss_crypto_ctx *cctx;
+
+    int plainlen;
+    unsigned int digestlen;
+    unsigned char *obfbuf = NULL;
+    unsigned int 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(mem_ctx);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    /* initialize NSS if needed */
+    ret = nspr_nss_init();
+    if (ret != EOK) {
+        ret = EIO;
+        goto done;
+    }
+
+    /* Base64 decode the incoming buffer */
+    obfbuf = ATOB_AsciiToData(b64encoded, &obflen);
+    if (!obfbuf) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    /* unpack obfuscation buffer */
+    SAFEALIGN_COPY_UINT16_CHECK(&meth, obfbuf+p, obflen, &p);
+    DEBUG(8, ("Read method: %d\n", meth));
+    SAFEALIGN_COPY_UINT16_CHECK(&ctsize, obfbuf+p, obflen, &p);
+    DEBUG(8, ("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(0, ("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);
+
+    ret = nss_encrypt_decrypt_init(tmp_ctx, mech_props, false,
+                                   ivbuf, keybuf, &cctx);
+    if (ret) {
+        goto done;
+    }
+
+    pwdbuf = talloc_array(tmp_ctx, char, ctsize);
+    if (!pwdbuf) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    sret = PK11_CipherOp(cctx->ectx, (unsigned char *) pwdbuf, &plainlen, ctsize,
+                         cryptotext, ctsize);
+    if (sret != SECSuccess) {
+        DEBUG(1, ("Cannot execute the encryption operation (err %d)\n",
+                   PR_GetError()));
+        ret = EIO;
+        goto done;
+    }
+
+    sret = PK11_DigestFinal(cctx->ectx, (unsigned char *) pwdbuf+plainlen, &digestlen,
+                            ctsize - plainlen);
+    if (sret != SECSuccess) {
+        DEBUG(1, ("Cannot execute the encryption operation (err %d)\n",
+                   PR_GetError()));
+        ret = EIO;
+        goto done;
+    }
+
+    *password = talloc_move(mem_ctx, &pwdbuf);
+    ret = EOK;
+done:
+    PORT_Free(obfbuf);
+    talloc_free(tmp_ctx);
+    nspr_nss_cleanup();
+    return ret;
+}
diff --git a/src/util/crypto/sss_crypto.h b/src/util/crypto/sss_crypto.h
index 5512c5d..66394ae 100644
--- a/src/util/crypto/sss_crypto.h
+++ b/src/util/crypto/sss_crypto.h
@@ -2,3 +2,17 @@
 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
+};
+
+int test2(void);
+
+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);
-- 
1.7.2.2

