summaryrefslogtreecommitdiffstats
path: root/src/util/crypto/libcrypto/crypto_nite.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/crypto/libcrypto/crypto_nite.c')
-rw-r--r--src/util/crypto/libcrypto/crypto_nite.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/src/util/crypto/libcrypto/crypto_nite.c b/src/util/crypto/libcrypto/crypto_nite.c
new file mode 100644
index 000000000..fa267fbcc
--- /dev/null
+++ b/src/util/crypto/libcrypto/crypto_nite.c
@@ -0,0 +1,268 @@
+/*
+ SSSD
+
+ Encryption/Decryption primitives
+
+ Authors:
+ Simo Sorce <simo@redhat.com>
+
+ Copyright (C) Simo Sorce 2016
+
+ 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 "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>
+#include <openssl/crypto.h>
+
+struct cipher_mech {
+ const EVP_CIPHER * (*cipher)(void);
+ const EVP_MD * (*digest)(void);
+} mechs[] = {
+ { EVP_aes_256_cbc, EVP_sha256 }
+};
+
+int sss_encrypt(TALLOC_CTX *mem_ctx, enum encmethod enctype,
+ uint8_t *key, size_t keylen,
+ const uint8_t *plaintext, size_t plainlen,
+ uint8_t **ciphertext, size_t *cipherlen)
+{
+ const EVP_CIPHER *cipher;
+ const EVP_MD *digest;
+ EVP_PKEY *hmackey;
+ EVP_CIPHER_CTX ctx;
+ EVP_MD_CTX mdctx;
+ uint8_t *out = NULL;
+ int evpkeylen;
+ int evpivlen;
+ int hmaclen;
+ int outlen, tmplen;
+ size_t slen;
+ int ret;
+
+ if (!plaintext || !plainlen) return EINVAL;
+
+ if (enctype != AES256CBC_HMAC_SHA256) return EINVAL;
+ cipher = mechs[AES256CBC_HMAC_SHA256].cipher();
+ digest = mechs[AES256CBC_HMAC_SHA256].digest();
+
+ evpkeylen = EVP_CIPHER_key_length(cipher);
+ if (!key || keylen != evpkeylen) return EINVAL;
+
+ hmackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, keylen);
+ if (!hmackey) return ENOMEM;
+
+ /* We have no function to return the size of the output for arbitray HMAC
+ * algorithms so we just truncate to the key size should the hmac be bigger
+ * (or pad with zeros should the HMAC be smaller) */
+ hmaclen = keylen;
+
+ evpivlen = EVP_CIPHER_iv_length(cipher);
+ outlen = plainlen + (2 * EVP_CIPHER_block_size(cipher))
+ + evpivlen + hmaclen;
+ out = talloc_zero_size(mem_ctx, outlen);
+
+ /* First Encrypt */
+
+ if (evpivlen != 0) {
+ RAND_bytes(out, evpivlen);
+ }
+
+ EVP_CIPHER_CTX_init(&ctx);
+ ret = EVP_EncryptInit_ex(&ctx, cipher, 0, key, evpivlen ? out : NULL);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ outlen = evpivlen;
+ tmplen = 0;
+ ret = EVP_EncryptUpdate(&ctx, out + outlen, &tmplen, plaintext, plainlen);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ outlen += tmplen;
+
+ ret = EVP_EncryptFinal_ex(&ctx, out + outlen, &tmplen);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ outlen += tmplen;
+
+ /* Then HMAC */
+
+ EVP_MD_CTX_init(&mdctx);
+
+ ret = EVP_DigestInit_ex(&mdctx, digest, NULL);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ ret = EVP_DigestSignInit(&mdctx, NULL, digest, NULL, hmackey);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ ret = EVP_DigestSignUpdate(&mdctx, out, outlen);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ slen = hmaclen;
+ ret = EVP_DigestSignFinal(&mdctx, &out[outlen], &slen);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ outlen += hmaclen;
+
+ *ciphertext = out;
+ *cipherlen = outlen;
+ ret = EOK;
+
+done:
+ EVP_MD_CTX_cleanup(&mdctx);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ EVP_PKEY_free(hmackey);
+ return ret;
+}
+
+int sss_decrypt(TALLOC_CTX *mem_ctx, enum encmethod enctype,
+ uint8_t *key, size_t keylen,
+ const uint8_t *ciphertext, size_t cipherlen,
+ uint8_t **plaintext, size_t *plainlen)
+{
+ const EVP_CIPHER *cipher;
+ const EVP_MD *digest;
+ EVP_PKEY *hmackey;
+ EVP_CIPHER_CTX ctx;
+ EVP_MD_CTX mdctx;
+ const uint8_t *iv = NULL;
+ uint8_t *out;
+ int evpkeylen;
+ int evpivlen;
+ int hmaclen;
+ int outlen, tmplen;
+ size_t slen;
+ int ret;
+
+ if (!ciphertext || !cipherlen) return EINVAL;
+
+ if (enctype != AES256CBC_HMAC_SHA256) return EINVAL;
+ cipher = mechs[AES256CBC_HMAC_SHA256].cipher();
+ digest = mechs[AES256CBC_HMAC_SHA256].digest();
+
+ evpkeylen = EVP_CIPHER_key_length(cipher);
+ if (!key || keylen != evpkeylen) return EINVAL;
+
+ hmackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, keylen);
+ if (!hmackey) return ENOMEM;
+
+ /* We have no function to return the size of the output for arbitray HMAC
+ * algorithms so we just assume it was truncated to the key size should
+ * the hmac be bigger (or pad with zeros should the HMAC be smaller) */
+ hmaclen = keylen;
+
+ evpivlen = EVP_CIPHER_iv_length(cipher);
+ out = talloc_zero_size(mem_ctx, cipherlen);
+
+ /* First check HMAC */
+
+ EVP_MD_CTX_init(&mdctx);
+
+ ret = EVP_DigestInit_ex(&mdctx, digest, NULL);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ ret = EVP_DigestSignInit(&mdctx, NULL, digest, NULL, hmackey);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ ret = EVP_DigestSignUpdate(&mdctx, ciphertext, cipherlen - hmaclen);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ slen = hmaclen;
+ ret = EVP_DigestSignFinal(&mdctx, out, &slen);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ ret = CRYPTO_memcmp(&ciphertext[cipherlen - hmaclen], out, hmaclen);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ /* Then Decrypt */
+
+ if (evpivlen != 0) {
+ iv = ciphertext;
+ }
+
+ EVP_CIPHER_CTX_init(&ctx);
+ ret = EVP_DecryptInit_ex(&ctx, cipher, 0, key, iv);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ ret = EVP_DecryptUpdate(&ctx, out, &outlen,
+ ciphertext + evpivlen,
+ cipherlen - evpivlen - hmaclen);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ ret = EVP_DecryptFinal_ex(&ctx, out + outlen, &tmplen);
+ if (ret != 1) {
+ ret = EFAULT;
+ goto done;
+ }
+
+ outlen += tmplen;
+
+ *plaintext = out;
+ *plainlen = outlen;
+ ret = EOK;
+
+done:
+ EVP_MD_CTX_cleanup(&mdctx);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ EVP_PKEY_free(hmackey);
+ return ret;
+}