91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina/*
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina SSSD
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina Encryption/Decryption primitives
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina Authors:
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina Simo Sorce <simo@redhat.com>
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina Copyright (C) Simo Sorce 2016
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina This program is free software; you can redistribute it and/or modify
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina it under the terms of the GNU General Public License as published by
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina the Free Software Foundation; either version 3 of the License, or
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina (at your option) any later version.
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina This program is distributed in the hope that it will be useful,
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina but WITHOUT ANY WARRANTY; without even the implied warranty of
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina GNU General Public License for more details.
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina You should have received a copy of the GNU General Public License
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina along with this program. If not, see <http://www.gnu.org/licenses/>.
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina*/
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina#include "config.h"
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina#include <talloc.h>
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina#include <errno.h>
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina#include "util/util.h"
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina#include "util/crypto/sss_crypto.h"
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina#include <openssl/evp.h>
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina#include <openssl/rand.h>
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina#include <openssl/crypto.h>
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina#include "sss_openssl.h"
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březinastruct cipher_mech {
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina const EVP_CIPHER * (*cipher)(void);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina const EVP_MD * (*digest)(void);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina} mechs[] = {
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina { EVP_aes_256_cbc, EVP_sha256 }
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina};
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březinaint sss_encrypt(TALLOC_CTX *mem_ctx, enum encmethod enctype,
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina uint8_t *key, size_t keylen,
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina const uint8_t *plaintext, size_t plainlen,
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina uint8_t **ciphertext, size_t *cipherlen)
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina{
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina const EVP_CIPHER *cipher;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina const EVP_MD *digest;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina EVP_PKEY *hmackey = NULL;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina EVP_CIPHER_CTX *ctx;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina EVP_MD_CTX *mdctx = NULL;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina uint8_t *out = NULL;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina int evpkeylen;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina int evpivlen;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina int hmaclen;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina int outlen, tmplen;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina size_t slen;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina int ret;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (!plaintext || !plainlen) return EINVAL;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (enctype != AES256CBC_HMAC_SHA256) return EINVAL;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina cipher = mechs[AES256CBC_HMAC_SHA256].cipher();
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina digest = mechs[AES256CBC_HMAC_SHA256].digest();
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina evpkeylen = EVP_CIPHER_key_length(cipher);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (!key || keylen != evpkeylen) return EINVAL;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina hmackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, keylen);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (!hmackey) return ENOMEM;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina /* We have no function to return the size of the output for arbitray HMAC
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina * algorithms so we just truncate to the key size should the hmac be bigger
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina * (or pad with zeros should the HMAC be smaller) */
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina hmaclen = keylen;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina evpivlen = EVP_CIPHER_iv_length(cipher);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina outlen = plainlen + (2 * EVP_CIPHER_block_size(cipher))
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina + evpivlen + hmaclen;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina out = talloc_zero_size(mem_ctx, outlen);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina /* First Encrypt */
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (evpivlen != 0) {
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina RAND_bytes(out, evpivlen);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina }
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ctx = EVP_CIPHER_CTX_new();
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (ctx == NULL) {
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = ENOMEM;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina goto done;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina }
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = EVP_EncryptInit_ex(ctx, cipher, 0, key, evpivlen ? out : NULL);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (ret != 1) {
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = EFAULT;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina goto done;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina }
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina outlen = evpivlen;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina tmplen = 0;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = EVP_EncryptUpdate(ctx, out + outlen, &tmplen, plaintext, plainlen);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 1) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina outlen += tmplen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EVP_EncryptFinal_ex(ctx, out + outlen, &tmplen);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 1) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina outlen += tmplen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina /* Then HMAC */
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina mdctx = EVP_MD_CTX_new();
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (mdctx == NULL) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = ENOMEM;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EVP_DigestInit_ex(mdctx, digest, NULL);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 1) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EVP_DigestSignInit(mdctx, NULL, digest, NULL, hmackey);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 1) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EVP_DigestSignUpdate(mdctx, out, outlen);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 1) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina slen = hmaclen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EVP_DigestSignFinal(mdctx, &out[outlen], &slen);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 1) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina outlen += hmaclen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina *ciphertext = out;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina *cipherlen = outlen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EOK;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březinadone:
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina EVP_MD_CTX_free(mdctx);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina EVP_CIPHER_CTX_free(ctx);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina EVP_PKEY_free(hmackey);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina return ret;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina}
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březinaint sss_decrypt(TALLOC_CTX *mem_ctx, enum encmethod enctype,
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina uint8_t *key, size_t keylen,
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina const uint8_t *ciphertext, size_t cipherlen,
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina uint8_t **plaintext, size_t *plainlen)
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina{
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina const EVP_CIPHER *cipher;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina const EVP_MD *digest;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina EVP_PKEY *hmackey = NULL;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina EVP_CIPHER_CTX *ctx = NULL;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina EVP_MD_CTX *mdctx;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina const uint8_t *iv = NULL;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina uint8_t *out;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina int evpkeylen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina int evpivlen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina int hmaclen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina int outlen, tmplen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina size_t slen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina int ret;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (!ciphertext || !cipherlen) return EINVAL;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (enctype != AES256CBC_HMAC_SHA256) return EINVAL;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina cipher = mechs[AES256CBC_HMAC_SHA256].cipher();
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina digest = mechs[AES256CBC_HMAC_SHA256].digest();
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina evpkeylen = EVP_CIPHER_key_length(cipher);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (!key || keylen != evpkeylen) return EINVAL;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina hmackey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, keylen);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (!hmackey) return ENOMEM;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina /* We have no function to return the size of the output for arbitray HMAC
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina * algorithms so we just assume it was truncated to the key size should
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina * the hmac be bigger (or pad with zeros should the HMAC be smaller) */
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina hmaclen = keylen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina evpivlen = EVP_CIPHER_iv_length(cipher);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina out = talloc_zero_size(mem_ctx, cipherlen);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina /* First check HMAC */
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina mdctx = EVP_MD_CTX_new();
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (mdctx == NULL) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = ENOMEM;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EVP_DigestInit_ex(mdctx, digest, NULL);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 1) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EVP_DigestSignInit(mdctx, NULL, digest, NULL, hmackey);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 1) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EVP_DigestSignUpdate(mdctx, ciphertext, cipherlen - hmaclen);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 1) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina slen = hmaclen;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EVP_DigestSignFinal(mdctx, out, &slen);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 1) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = CRYPTO_memcmp(&ciphertext[cipherlen - hmaclen], out, hmaclen);
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (ret != 0) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina ret = EFAULT;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina goto done;
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina }
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina /* Then Decrypt */
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (evpivlen != 0) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina iv = ciphertext;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina }
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ctx = EVP_CIPHER_CTX_new();
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (ctx == NULL) {
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = ENOMEM;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina goto done;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina }
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = EVP_DecryptInit_ex(ctx, cipher, 0, key, iv);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (ret != 1) {
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = EFAULT;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina goto done;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina }
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = EVP_DecryptUpdate(ctx, out, &outlen,
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ciphertext + evpivlen,
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina cipherlen - evpivlen - hmaclen);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (ret != 1) {
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = EFAULT;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina goto done;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina }
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = EVP_DecryptFinal_ex(ctx, out + outlen, &tmplen);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina if (ret != 1) {
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = EFAULT;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina goto done;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina }
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina outlen += tmplen;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina *plaintext = out;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina *plainlen = outlen;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina ret = EOK;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březinadone:
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina EVP_MD_CTX_free(mdctx);
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina EVP_CIPHER_CTX_free(ctx);
f194bd0fa75f87ac29dc08c3aeca9aa86311bfc5Fabiano Fidêncio EVP_PKEY_free(hmackey);
f194bd0fa75f87ac29dc08c3aeca9aa86311bfc5Fabiano Fidêncio return ret;
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina}
91cf6f4c6069d6aff01aab171825e83a1a669e2fPavel Březina