]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/crypto.c
crypto: convert EVP_MD_CTX + EVP_CIPHER_CTX to OpenSSL 1.1
[bacula/bacula] / bacula / src / lib / crypto.c
index d2a2d4a4d3562d77490315f51cd5fd679da67e13..e035de78ac212fdef748bf2bfc89ee4b20fa5b8d 100644 (file)
@@ -1,12 +1,26 @@
+/*
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2016 Kern Sibbald
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
+
+   This notice must be preserved when any source code is 
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
+*/
 /*
  * crypto.c Encryption support functions
  *
  * Author: Landon Fuller <landonf@opendarwin.org>
  *
- * Version $Id$
- *
- * Copyright (C) 2005 Kern Sibbald
- *
  * This file was contributed to the Bacula project by Landon Fuller.
  *
  * Landon Fuller has been granted a perpetual, worldwide, non-exclusive,
  * If you wish to license these contributions under an alternate open source
  * license please contact Landon Fuller <landonf@opendarwin.org>.
  */
-/*
-   Copyright (C) 2005 Kern Sibbald
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License
-   version 2 as amended with additional clauses defined in the
-   file LICENSE in the main source directory.
-
-   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 
-   the file LICENSE for additional details.
-
- */
 
 
 #include "bacula.h"
+#include "jcr.h"
 #include <assert.h>
 
+/**
+ * For OpenSSL version 1.x, EVP_PKEY_encrypt no longer
+ *  exists.  It was not an official API.
+ */
+#ifdef HAVE_OPENSSLv1
+#define EVP_PKEY_encrypt EVP_PKEY_encrypt_old
+#define EVP_PKEY_decrypt EVP_PKEY_decrypt_old
+#endif
+
 /*
  * Bacula ASN.1 Syntax
  *
@@ -73,7 +83,8 @@
  *
  * CryptoData ::= SEQUENCE {
  *    version                     Version DEFAULT v0,
- *    contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier
+ *    contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
+ *    iv                          InitializationVector,
  *    recipientInfo               RecipientInfo
  * }
  *
  *
  * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
  *
+ * ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * InitializationVector ::= OCTET STRING
+ *
  * SignatureValue ::= OCTET STRING
  *
  * EncryptedKey ::= OCTET STRING
 #ifdef HAVE_CRYPTO /* Is encryption enabled? */
 #ifdef HAVE_OPENSSL /* How about OpenSSL? */
 
-/* Are we initialized? */
-static int crypto_initialized = false;
+#include "openssl-compat.h"
 
 /* ASN.1 Declarations */
 #define BACULA_ASN1_VERSION 0
@@ -160,6 +174,7 @@ typedef struct {
 typedef struct {
    ASN1_INTEGER *version;
    ASN1_OBJECT *contentEncryptionAlgorithm;
+   ASN1_OCTET_STRING *iv;
    STACK_OF(RecipientInfo) *recipientInfo;
 } CryptoData;
 
@@ -170,15 +185,20 @@ ASN1_SEQUENCE(SignatureData) = {
 
 ASN1_SEQUENCE(CryptoData) = {
    ASN1_SIMPLE(CryptoData, version, ASN1_INTEGER),
+   ASN1_SIMPLE(CryptoData, contentEncryptionAlgorithm, ASN1_OBJECT),
+   ASN1_SIMPLE(CryptoData, iv, ASN1_OCTET_STRING),
    ASN1_SET_OF(CryptoData, recipientInfo, RecipientInfo)
 } ASN1_SEQUENCE_END(CryptoData);
 
 IMPLEMENT_ASN1_FUNCTIONS(SignerInfo)
+IMPLEMENT_ASN1_FUNCTIONS(RecipientInfo)
 IMPLEMENT_ASN1_FUNCTIONS(SignatureData)
 IMPLEMENT_ASN1_FUNCTIONS(CryptoData)
-IMPLEMENT_STACK_OF(SignerInfo)
-IMPLEMENT_STACK_OF(RecipientInfo)
 
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+DEFINE_STACK_OF(SignerInfo);
+DEFINE_STACK_OF(RecipientInfo);
+#else
 /*
  * SignerInfo and RecipientInfo stack macros, generated by OpenSSL's util/mkstack.pl.
  */
@@ -204,13 +224,13 @@ IMPLEMENT_STACK_OF(RecipientInfo)
 #define sk_SignerInfo_is_sorted(st) SKM_sk_is_sorted(SignerInfo, (st))
 
 #define d2i_ASN1_SET_OF_SignerInfo(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
-       SKM_ASN1_SET_OF_d2i(SignerInfo, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+        SKM_ASN1_SET_OF_d2i(SignerInfo, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
 #define i2d_ASN1_SET_OF_SignerInfo(st, pp, i2d_func, ex_tag, ex_class, is_set) \
-       SKM_ASN1_SET_OF_i2d(SignerInfo, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+        SKM_ASN1_SET_OF_i2d(SignerInfo, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
 #define ASN1_seq_pack_SignerInfo(st, i2d_func, buf, len) \
-       SKM_ASN1_seq_pack(SignerInfo, (st), (i2d_func), (buf), (len))
+        SKM_ASN1_seq_pack(SignerInfo, (st), (i2d_func), (buf), (len))
 #define ASN1_seq_unpack_SignerInfo(buf, len, d2i_func, free_func) \
-       SKM_ASN1_seq_unpack(SignerInfo, (buf), (len), (d2i_func), (free_func))
+        SKM_ASN1_seq_unpack(SignerInfo, (buf), (len), (d2i_func), (free_func))
 
 #define sk_RecipientInfo_new(st) SKM_sk_new(RecipientInfo, (st))
 #define sk_RecipientInfo_new_null() SKM_sk_new_null(RecipientInfo)
@@ -234,14 +254,15 @@ IMPLEMENT_STACK_OF(RecipientInfo)
 #define sk_RecipientInfo_is_sorted(st) SKM_sk_is_sorted(RecipientInfo, (st))
 
 #define d2i_ASN1_SET_OF_RecipientInfo(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
-       SKM_ASN1_SET_OF_d2i(RecipientInfo, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+        SKM_ASN1_SET_OF_d2i(RecipientInfo, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class))
 #define i2d_ASN1_SET_OF_RecipientInfo(st, pp, i2d_func, ex_tag, ex_class, is_set) \
-       SKM_ASN1_SET_OF_i2d(RecipientInfo, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+        SKM_ASN1_SET_OF_i2d(RecipientInfo, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
 #define ASN1_seq_pack_RecipientInfo(st, i2d_func, buf, len) \
-       SKM_ASN1_seq_pack(RecipientInfo, (st), (i2d_func), (buf), (len))
+        SKM_ASN1_seq_pack(RecipientInfo, (st), (i2d_func), (buf), (len))
 #define ASN1_seq_unpack_RecipientInfo(buf, len, d2i_func, free_func) \
-       SKM_ASN1_seq_unpack(RecipientInfo, (buf), (len), (d2i_func), (free_func))
+        SKM_ASN1_seq_unpack(RecipientInfo, (buf), (len), (d2i_func), (free_func))
 /* End of util/mkstack.pl block */
+#endif
 
 /* X509 Public/Private Key Pair Structure */
 struct X509_Keypair {
@@ -253,12 +274,26 @@ struct X509_Keypair {
 /* Message Digest Structure */
 struct Digest {
    crypto_digest_t type;
-   EVP_MD_CTX ctx;
+   JCR *jcr;
+   EVP_MD_CTX *ctx;
 };
 
 /* Message Signature Structure */
 struct Signature {
    SignatureData *sigData;
+   JCR *jcr;
+};
+
+/* Encryption Session Data */
+struct Crypto_Session {
+   CryptoData *cryptoData;                        /* ASN.1 Structure */
+   unsigned char *session_key;                    /* Private symmetric session key */
+   size_t session_key_len;                        /* Symmetric session key length */
+};
+
+/* Symmetric Cipher Context */
+struct Cipher_Context {
+   EVP_CIPHER_CTX *ctx;
 };
 
 /* PEM Password Dispatch Context */
@@ -272,17 +307,12 @@ typedef struct PEM_CB_Context {
  * Returns: On success, an ASN1_OCTET_STRING that must be freed via M_ASN1_OCTET_STRING_free().
  *          NULL on failure.
  */
-static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert){
+static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert) {
    X509_EXTENSION *ext;
-   X509V3_EXT_METHOD *method;
+   const X509V3_EXT_METHOD *method;
    ASN1_OCTET_STRING *keyid;
    int i;
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
    const unsigned char *ext_value_data;
-#else
-   unsigned char *ext_value_data;
-#endif
-
 
    /* Find the index to the subjectKeyIdentifier extension */
    i = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1);
@@ -301,7 +331,6 @@ static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert){
 
    ext_value_data = ext->value->data;
 
-#if (OPENSSL_VERSION_NUMBER > 0x00907000L)
    if (method->it) {
       /* New style ASN1 */
 
@@ -315,10 +344,6 @@ static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert){
       keyid = (ASN1_OCTET_STRING *) method->d2i(NULL, &ext_value_data, ext->value->length);
    }
 
-#else
-   keyid = (ASN1_OCTET_STRING *) method->d2i(NULL, &ext_value_data, ext->value->length);
-#endif
-
    return keyid;
 }
 
@@ -327,14 +352,12 @@ static ASN1_OCTET_STRING *openssl_cert_keyid(X509 *cert){
  *  Returns: A pointer to a X509 KEYPAIR object on success.
  *           NULL on failure.
  */
-X509_KEYPAIR *crypto_keypair_new (void) {
+X509_KEYPAIR *crypto_keypair_new(void)
+{
    X509_KEYPAIR *keypair;
 
    /* Allocate our keypair structure */
-   keypair = (X509_KEYPAIR *) malloc(sizeof(X509_KEYPAIR));
-   if (!keypair) {
-      return NULL;
-   }
+   keypair = (X509_KEYPAIR *)malloc(sizeof(X509_KEYPAIR));
 
    /* Initialize our keypair structure */
    keypair->keyid = NULL;
@@ -344,12 +367,55 @@ X509_KEYPAIR *crypto_keypair_new (void) {
    return keypair;
 }
 
+/*
+ * Create a copy of a keypair object. The underlying
+ * EVP objects are not duplicated, as no EVP_PKEY_dup()
+ * API is available. Instead, the reference count is
+ * incremented.
+ */
+X509_KEYPAIR *crypto_keypair_dup(X509_KEYPAIR *keypair)
+{
+   X509_KEYPAIR *newpair;
+
+   newpair = crypto_keypair_new();
+
+   if (!newpair) {
+      /* Allocation failed */
+      return NULL;
+   }
+
+   /* Increment the public key ref count */
+   if (keypair->pubkey) {
+      CRYPTO_add(&(keypair->pubkey->references), 1, CRYPTO_LOCK_EVP_PKEY);
+      newpair->pubkey = keypair->pubkey;
+   }
+
+   /* Increment the private key ref count */
+   if (keypair->privkey) {
+      CRYPTO_add(&(keypair->privkey->references), 1, CRYPTO_LOCK_EVP_PKEY);
+      newpair->privkey = keypair->privkey;
+   }
+
+   /* Duplicate the keyid */
+   if (keypair->keyid) {
+      newpair->keyid = M_ASN1_OCTET_STRING_dup(keypair->keyid);
+      if (!newpair->keyid) {
+         /* Allocation failed */
+         crypto_keypair_free(newpair);
+         return NULL;
+      }
+   }
+
+   return newpair;
+}
+
+
 /*
  * Load a public key from a PEM-encoded x509 certificate.
  *  Returns: true on success
  *           false on failure
  */
-int crypto_keypair_load_cert (X509_KEYPAIR *keypair, const char *file)
+int crypto_keypair_load_cert(X509_KEYPAIR *keypair, const char *file)
 {
    BIO *bio;
    X509 *cert;
@@ -375,16 +441,19 @@ int crypto_keypair_load_cert (X509_KEYPAIR *keypair, const char *file)
 
    /* Extract the subjectKeyIdentifier extension field */
    if ((keypair->keyid = openssl_cert_keyid(cert)) == NULL) {
-      Emsg0(M_ERROR, 0, _("Provided certificate does not include the required subjectKeyIdentifier extension."));
+      Jmsg0(NULL, M_ERROR, 0,
+         _("Provided certificate does not include the required subjectKeyIdentifier extension."));
       goto err;
    }
 
    /* Validate the public key type (only RSA is supported) */
    if (EVP_PKEY_type(keypair->pubkey->type) != EVP_PKEY_RSA) {
-       Emsg1(M_ERROR, 0, _("Unsupported key type provided: %d\n"), EVP_PKEY_type(keypair->pubkey->type));
+       Jmsg1(NULL, M_ERROR, 0,
+             _("Unsupported key type provided: %d\n"), EVP_PKEY_type(keypair->pubkey->type));
        goto err;
    }
 
+   X509_free(cert);
    return true;
 
 err:
@@ -402,12 +471,61 @@ static int crypto_pem_callback_dispatch (char *buf, int size, int rwflag, void *
    return (ctx->pem_callback(buf, size, ctx->pem_userdata));
 }
 
+/*
+ * Check a PEM-encoded file
+ * for the existence of a private key.
+ * Returns: true if a private key is found
+ *          false otherwise
+ */
+bool crypto_keypair_has_key(const char *file) {
+   BIO *bio;
+   char *name = NULL;
+   char *header = NULL;
+   unsigned char *data = NULL;
+   bool retval = false;
+   long len;
+
+   if (!(bio = BIO_new_file(file, "r"))) {
+      openssl_post_errors(M_ERROR, _("Unable to open private key file"));
+      return false;
+   }
+
+   while (PEM_read_bio(bio, &name, &header, &data, &len)) {
+      /* We don't care what the data is, just that it's there */
+      OPENSSL_free(header);
+      OPENSSL_free(data);
+
+      /*
+       * PEM Header Found, check for a private key
+       * Due to OpenSSL limitations, we must specifically
+       * list supported PEM private key encodings.
+       */
+      if (strcmp(name, PEM_STRING_RSA) == 0
+            || strcmp(name, PEM_STRING_DSA) == 0
+            || strcmp(name, PEM_STRING_PKCS8) == 0
+            || strcmp(name, PEM_STRING_PKCS8INF) == 0) {
+         retval = true;
+         OPENSSL_free(name);
+         break;
+      } else {
+         OPENSSL_free(name);
+      }
+   }
+
+   /* Free our bio */
+   BIO_free(bio);
+
+   /* Post PEM-decoding error messages, if any */
+   openssl_post_errors(M_ERROR, _("Unable to read private key from file"));
+   return retval;
+}
+
 /*
  * Load a PEM-encoded private key.
  *  Returns: true on success
  *           false on failure
  */
-int crypto_keypair_load_key (X509_KEYPAIR *keypair, const char *file,
+int crypto_keypair_load_key(X509_KEYPAIR *keypair, const char *file,
                              CRYPTO_PEM_PASSWD_CB *pem_callback,
                              const void *pem_userdata)
 {
@@ -442,7 +560,7 @@ int crypto_keypair_load_key (X509_KEYPAIR *keypair, const char *file,
 /*
  * Free memory associated with a keypair object.
  */
-void crypto_keypair_free (X509_KEYPAIR *keypair)
+void crypto_keypair_free(X509_KEYPAIR *keypair)
 {
    if (keypair->pubkey) {
       EVP_PKEY_free(keypair->pubkey);
@@ -461,16 +579,21 @@ void crypto_keypair_free (X509_KEYPAIR *keypair)
  *  Returns: A pointer to a DIGEST object on success.
  *           NULL on failure.
  */
-DIGEST *crypto_digest_new (crypto_digest_t type)
+DIGEST *crypto_digest_new(JCR *jcr, crypto_digest_t type)
 {
    DIGEST *digest;
    const EVP_MD *md = NULL; /* Quell invalid uninitialized warnings */
 
-   digest = (DIGEST *) malloc(sizeof(DIGEST));
+   digest = (DIGEST *)malloc(sizeof(DIGEST));
    digest->type = type;
+   digest->jcr = jcr;
+   Dmsg1(150, "crypto_digest_new jcr=%p\n", jcr);
 
    /* Initialize the OpenSSL message digest context */
-   EVP_MD_CTX_init(&digest->ctx);
+   digest->ctx = EVP_MD_CTX_new();
+   if (!digest->ctx)
+          goto err;
+   EVP_MD_CTX_reset(digest->ctx);
 
    /* Determine the correct OpenSSL message digest type */
    switch (type) {
@@ -489,12 +612,12 @@ DIGEST *crypto_digest_new (crypto_digest_t type)
       break;
 #endif
    default:
-      Emsg1(M_ERROR, 0, _("Unsupported digest type: %d\n"), type);
+      Jmsg1(jcr, M_ERROR, 0, _("Unsupported digest type: %d\n"), type);
       goto err;
    }
 
    /* Initialize the backing OpenSSL context */
-   if (EVP_DigestInit_ex(&digest->ctx, md, NULL) == 0) {
+   if (EVP_DigestInit_ex(digest->ctx, md, NULL) == 0) {
       goto err;
    }
 
@@ -502,7 +625,8 @@ DIGEST *crypto_digest_new (crypto_digest_t type)
 
 err:
    /* This should not happen, but never say never ... */
-   openssl_post_errors(M_ERROR, _("OpenSSL digest initialization failed"));
+   Dmsg0(150, "Digest init failed.\n");
+   openssl_post_errors(jcr, M_ERROR, _("OpenSSL digest initialization failed"));
    crypto_digest_free(digest);
    return NULL;
 }
@@ -512,11 +636,14 @@ err:
  * Returns: true on success
  *          false on failure
  */
-int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
-   if (EVP_DigestUpdate(&digest->ctx, data, length) == 0) {
-      return true;
-   } else { 
+bool crypto_digest_update(DIGEST *digest, const uint8_t *data, uint32_t length)
+{
+   if (EVP_DigestUpdate(digest->ctx, data, length) == 0) {
+      Dmsg0(150, "digest update failed\n");
+      openssl_post_errors(digest->jcr, M_ERROR, _("OpenSSL digest update failed"));
       return false;
+   } else {
+      return true;
    }
 }
 
@@ -527,8 +654,11 @@ int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
  * Returns: true on success
  *          false on failure
  */
-int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
-   if (!EVP_DigestFinal(&digest->ctx, (unsigned char *) dest, length)) {
+bool crypto_digest_finalize(DIGEST *digest, uint8_t *dest, uint32_t *length)
+{
+   if (!EVP_DigestFinal(digest->ctx, dest, (unsigned int *)length)) {
+      Dmsg0(150, "digest finalize failed\n");
+      openssl_post_errors(digest->jcr, M_ERROR, _("OpenSSL digest finalize failed"));
       return false;
    } else {
       return true;
@@ -538,10 +668,10 @@ int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
 /*
  * Free memory associated with a digest object.
  */
-void crypto_digest_free (DIGEST *digest)
+void crypto_digest_free(DIGEST *digest)
 {
-  EVP_MD_CTX_cleanup(&digest->ctx);
-  free (digest);
+  EVP_MD_CTX_free(digest->ctx);
+  free(digest);
 }
 
 /*
@@ -549,16 +679,18 @@ void crypto_digest_free (DIGEST *digest)
  *  Returns: A pointer to a SIGNATURE object on success.
  *           NULL on failure.
  */
-SIGNATURE *crypto_sign_new (void)
+SIGNATURE *crypto_sign_new(JCR *jcr)
 {
    SIGNATURE *sig;
 
-   sig = (SIGNATURE *) malloc(sizeof(SIGNATURE));
+   sig = (SIGNATURE *)malloc(sizeof(SIGNATURE));
    if (!sig) {
       return NULL;
    }
 
    sig->sigData = SignatureData_new();
+   sig->jcr = jcr;
+   Dmsg1(150, "crypto_sign_new jcr=%p\n", jcr);
 
    if (!sig->sigData) {
       /* Allocation failed in OpenSSL */
@@ -574,11 +706,13 @@ SIGNATURE *crypto_sign_new (void)
 
 /*
  * For a given public key, find the associated SignatureInfo record
- * and create a digest context for signature validation
+ *   and create a digest context for signature validation
+ *
  * Returns: CRYPTO_ERROR_NONE on success, with the newly allocated DIGEST in digest.
  *          A crypto_error_t value on failure.
  */
-crypto_error_t crypto_sign_get_digest(SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST **digest)
+crypto_error_t crypto_sign_get_digest(SIGNATURE *sig, X509_KEYPAIR *keypair,
+                                      crypto_digest_t &type, DIGEST **digest)
 {
    STACK_OF(SignerInfo) *signers;
    SignerInfo *si;
@@ -590,33 +724,47 @@ crypto_error_t crypto_sign_get_digest(SIGNATURE *sig, X509_KEYPAIR *keypair, DIG
       si = sk_SignerInfo_value(signers, i);
       if (M_ASN1_OCTET_STRING_cmp(keypair->keyid, si->subjectKeyIdentifier) == 0) {
          /* Get the digest algorithm and allocate a digest context */
+         Dmsg1(150, "crypto_sign_get_digest jcr=%p\n", sig->jcr);
          switch (OBJ_obj2nid(si->digestAlgorithm)) {
          case NID_md5:
-            *digest = crypto_digest_new(CRYPTO_DIGEST_MD5);
+            Dmsg0(100, "sign digest algorithm is MD5\n");
+            type = CRYPTO_DIGEST_MD5;
+            *digest = crypto_digest_new(sig->jcr, CRYPTO_DIGEST_MD5);
             break;
          case NID_sha1:
-            *digest = crypto_digest_new(CRYPTO_DIGEST_SHA1);
+            Dmsg0(100, "sign digest algorithm is SHA1\n");
+            type = CRYPTO_DIGEST_SHA1;
+            *digest = crypto_digest_new(sig->jcr, CRYPTO_DIGEST_SHA1);
             break;
 #ifdef HAVE_SHA2
          case NID_sha256:
-            *digest = crypto_digest_new(CRYPTO_DIGEST_SHA256);
+            Dmsg0(100, "sign digest algorithm is SHA256\n");
+            type = CRYPTO_DIGEST_SHA256;
+            *digest = crypto_digest_new(sig->jcr, CRYPTO_DIGEST_SHA256);
             break;
          case NID_sha512:
-            *digest = crypto_digest_new(CRYPTO_DIGEST_SHA512);
+            Dmsg0(100, "sign digest algorithm is SHA512\n");
+            type = CRYPTO_DIGEST_SHA512;
+            *digest = crypto_digest_new(sig->jcr, CRYPTO_DIGEST_SHA512);
             break;
 #endif
          default:
+            type = CRYPTO_DIGEST_NONE;
             *digest = NULL;
             return CRYPTO_ERROR_INVALID_DIGEST;
          }
 
          /* Shouldn't happen */
          if (*digest == NULL) {
+            openssl_post_errors(sig->jcr, M_ERROR, _("OpenSSL digest_new failed"));
             return CRYPTO_ERROR_INVALID_DIGEST;
          } else {
             return CRYPTO_ERROR_NONE;
          }
+      } else {
+         openssl_post_errors(sig->jcr, M_ERROR, _("OpenSSL sign get digest failed"));
       }
+
    }
 
    return CRYPTO_ERROR_NOSIGNER;
@@ -633,11 +781,7 @@ crypto_error_t crypto_sign_verify(SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST
    SignerInfo *si;
    int ok, i;
    unsigned int sigLen;
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
    const unsigned char *sigData;
-#else
-   unsigned char *sigData;
-#endif
 
    signers = sig->sigData->signerInfo;
 
@@ -649,19 +793,20 @@ crypto_error_t crypto_sign_verify(SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST
          sigLen = M_ASN1_STRING_length(si->signature);
          sigData = M_ASN1_STRING_data(si->signature);
 
-         ok = EVP_VerifyFinal(&digest->ctx, sigData, sigLen, keypair->pubkey);
+         ok = EVP_VerifyFinal(digest->ctx, sigData, sigLen, keypair->pubkey);
          if (ok >= 1) {
             return CRYPTO_ERROR_NONE;
          } else if (ok == 0) {
+            openssl_post_errors(sig->jcr, M_ERROR, _("OpenSSL digest Verify final failed"));
             return CRYPTO_ERROR_BAD_SIGNATURE;
          } else if (ok < 0) {
             /* Shouldn't happen */
-            openssl_post_errors(M_ERROR, _("OpenSSL error occured"));
+            openssl_post_errors(sig->jcr, M_ERROR, _("OpenSSL digest Verify final failed"));
             return CRYPTO_ERROR_INTERNAL;
          }
       }
    }
-
+   Jmsg(sig->jcr, M_ERROR, 0, _("No signers found for crypto verify.\n"));
    /* Signer wasn't found. */
    return CRYPTO_ERROR_NOSIGNER;
 }
@@ -716,12 +861,12 @@ int crypto_sign_add_signer(SIGNATURE *sig, DIGEST *digest, X509_KEYPAIR *keypair
    /* Set our signature algorithm. We currently require RSA */
    assert(EVP_PKEY_type(keypair->pubkey->type) == EVP_PKEY_RSA);
    /* This is slightly evil. Reach into the MD structure and grab the key type */
-   si->signatureAlgorithm = OBJ_nid2obj(digest->ctx.digest->pkey_type);
+   si->signatureAlgorithm = OBJ_nid2obj(EVP_MD_pkey_type(EVP_MD_CTX_md(digest->ctx)));
 
    /* Finalize/Sign our Digest */
    len = EVP_PKEY_size(keypair->privkey);
    buf = (unsigned char *) malloc(len);
-   if (!EVP_SignFinal(&digest->ctx, buf, &len, keypair->privkey)) {
+   if (!EVP_SignFinal(digest->ctx, buf, &len, keypair->privkey)) {
       openssl_post_errors(M_ERROR, _("Signature creation failed"));
       goto err;
    }
@@ -760,14 +905,14 @@ err:
  * Returns: true on success, stores the encoded data in dest, and the size in length.
  *          false on failure.
  */
-int crypto_sign_encode(SIGNATURE *sig, void *dest, size_t *length)
+int crypto_sign_encode(SIGNATURE *sig, uint8_t *dest, uint32_t *length)
 {
    if (*length == 0) {
       *length = i2d_SignatureData(sig->sigData, NULL);
       return true;
    }
 
-   *length = i2d_SignatureData(sig->sigData, (unsigned char **) &dest);
+   *length = i2d_SignatureData(sig->sigData, (unsigned char **)&dest);
    return true;
 }
 
@@ -780,26 +925,24 @@ int crypto_sign_encode(SIGNATURE *sig, void *dest, size_t *length)
 
  */
 
-SIGNATURE *crypto_sign_decode(const void *sigData, size_t length)
+SIGNATURE *crypto_sign_decode(JCR *jcr, const uint8_t *sigData, uint32_t length)
 {
    SIGNATURE *sig;
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
    const unsigned char *p = (const unsigned char *) sigData;
-#else
-   unsigned char *p = (unsigned char *) sigData;
-#endif
 
-   sig = (SIGNATURE *) malloc(sizeof(SIGNATURE));
+   sig = (SIGNATURE *)malloc(sizeof(SIGNATURE));
    if (!sig) {
       return NULL;
    }
+   sig->jcr = jcr;
 
    /* d2i_SignatureData modifies the supplied pointer */
    sig->sigData  = d2i_SignatureData(NULL, &p, length);
 
    if (!sig->sigData) {
       /* Allocation / Decoding failed in OpenSSL */
-      openssl_post_errors(M_ERROR, _("Signature decoding failed"));
+      openssl_post_errors(jcr, M_ERROR, _("Signature decoding failed"));
+      free(sig);
       return NULL;
    }
 
@@ -816,69 +959,402 @@ void crypto_sign_free(SIGNATURE *sig)
 }
 
 /*
- * Perform global initialization of OpenSSL
- * This function is not thread safe.
- *  Returns: 0 on success
- *           errno on failure
+ * Create a new encryption session.
+ *  Returns: A pointer to a CRYPTO_SESSION object on success.
+ *           NULL on failure.
+ *
+ *  Note! Bacula malloc() fails if out of memory.
+ */
+CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys)
+{
+   CRYPTO_SESSION *cs;
+   X509_KEYPAIR *keypair;
+   const EVP_CIPHER *ec;
+   unsigned char *iv;
+   int iv_len;
+
+   /* Allocate our session description structures */
+   cs = (CRYPTO_SESSION *)malloc(sizeof(CRYPTO_SESSION));
+
+   /* Initialize required fields */
+   cs->session_key = NULL;
+
+   /* Allocate a CryptoData structure */
+   cs->cryptoData = CryptoData_new();
+
+   if (!cs->cryptoData) {
+      /* Allocation failed in OpenSSL */
+      free(cs);
+      return NULL;
+   }
+
+   /* Set the ASN.1 structure version number */
+   ASN1_INTEGER_set(cs->cryptoData->version, BACULA_ASN1_VERSION);
+
+   /*
+    * Acquire a cipher instance and set the ASN.1 cipher NID
+    */
+   switch (cipher) {
+   case CRYPTO_CIPHER_AES_128_CBC:
+      /* AES 128 bit CBC */
+      cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_128_cbc);
+      ec = EVP_aes_128_cbc();
+      break;
+#ifndef HAVE_OPENSSL_EXPORT_LIBRARY
+   case CRYPTO_CIPHER_AES_192_CBC:
+      /* AES 192 bit CBC */
+      cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_192_cbc);
+      ec = EVP_aes_192_cbc();
+      break;
+   case CRYPTO_CIPHER_AES_256_CBC:
+      /* AES 256 bit CBC */
+      cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_aes_256_cbc);
+      ec = EVP_aes_256_cbc();
+      break;
+#endif
+   case CRYPTO_CIPHER_BLOWFISH_CBC:
+      /* Blowfish CBC */
+      cs->cryptoData->contentEncryptionAlgorithm = OBJ_nid2obj(NID_bf_cbc);
+      ec = EVP_bf_cbc();
+      break;
+   default:
+      Jmsg0(NULL, M_ERROR, 0, _("Unsupported cipher type specified\n"));
+      crypto_session_free(cs);
+      return NULL;
+   }
+
+   /* Generate a symmetric session key */
+   cs->session_key_len = EVP_CIPHER_key_length(ec);
+   cs->session_key = (unsigned char *) malloc(cs->session_key_len);
+   if (RAND_bytes(cs->session_key, cs->session_key_len) <= 0) {
+      /* OpenSSL failure */
+      crypto_session_free(cs);
+      return NULL;
+   }
+
+   /* Generate an IV if possible */
+   if ((iv_len = EVP_CIPHER_iv_length(ec))) {
+      iv = (unsigned char *)malloc(iv_len);
+
+      /* Generate random IV */
+      if (RAND_bytes(iv, iv_len) <= 0) {
+         /* OpenSSL failure */
+         crypto_session_free(cs);
+         free(iv);
+         return NULL;
+      }
+
+      /* Store it in our ASN.1 structure */
+      if (!M_ASN1_OCTET_STRING_set(cs->cryptoData->iv, iv, iv_len)) {
+         /* Allocation failed in OpenSSL */
+         crypto_session_free(cs);
+         free(iv);
+         return NULL;
+      }
+      free(iv);
+   }
+
+   /*
+    * Create RecipientInfo structures for supplied
+    * public keys.
+    */
+   foreach_alist(keypair, pubkeys) {
+      RecipientInfo *ri;
+      unsigned char *ekey;
+      int ekey_len;
+
+      ri = RecipientInfo_new();
+      if (!ri) {
+         /* Allocation failed in OpenSSL */
+         crypto_session_free(cs);
+         return NULL;
+      }
+
+      /* Set the ASN.1 structure version number */
+      ASN1_INTEGER_set(ri->version, BACULA_ASN1_VERSION);
+
+      /* Drop the string allocated by OpenSSL, and add our subjectKeyIdentifier */
+      M_ASN1_OCTET_STRING_free(ri->subjectKeyIdentifier);
+      ri->subjectKeyIdentifier = M_ASN1_OCTET_STRING_dup(keypair->keyid);
+
+      /* Set our key encryption algorithm. We currently require RSA */
+      assert(keypair->pubkey && EVP_PKEY_type(keypair->pubkey->type) == EVP_PKEY_RSA);
+      ri->keyEncryptionAlgorithm = OBJ_nid2obj(NID_rsaEncryption);
+
+      /* Encrypt the session key */
+      ekey = (unsigned char *)malloc(EVP_PKEY_size(keypair->pubkey));
+
+      if ((ekey_len = EVP_PKEY_encrypt(ekey, cs->session_key, cs->session_key_len, keypair->pubkey)) <= 0) {
+         /* OpenSSL failure */
+         RecipientInfo_free(ri);
+         crypto_session_free(cs);
+         free(ekey);
+         return NULL;
+      }
+
+      /* Store it in our ASN.1 structure */
+      if (!M_ASN1_OCTET_STRING_set(ri->encryptedKey, ekey, ekey_len)) {
+         /* Allocation failed in OpenSSL */
+         RecipientInfo_free(ri);
+         crypto_session_free(cs);
+         free(ekey);
+         return NULL;
+      }
+
+      /* Free the encrypted key buffer */
+      free(ekey);
+
+      /* Push the new RecipientInfo structure onto the stack */
+      sk_RecipientInfo_push(cs->cryptoData->recipientInfo, ri);
+   }
+
+   return cs;
+}
+
+/*
+ * Encodes the CryptoData structure. The length argument is used to specify the
+ * size of dest. A length of 0 will cause no data to be written to dest, and the
+ * required length to be written to length. The caller can then allocate sufficient
+ * space for the output.
+ *
+ * Returns: true on success, stores the encoded data in dest, and the size in length.
+ *          false on failure.
+ */
+bool crypto_session_encode(CRYPTO_SESSION *cs, uint8_t *dest, uint32_t *length)
+{
+   if (*length == 0) {
+      *length = i2d_CryptoData(cs->cryptoData, NULL);
+      return true;
+   }
+
+   *length = i2d_CryptoData(cs->cryptoData, &dest);
+   return true;
+}
+
+/*
+ * Decodes the CryptoData structure. The length argument is
+ * used to specify the size of data.
+ *
+ * Returns: CRYPTO_SESSION instance on success.
+ *          NULL on failure.
+ * Returns: CRYPTO_ERROR_NONE and a pointer to a newly allocated CRYPTO_SESSION structure in *session on success.
+ *          A crypto_error_t value on failure.
  */
-int init_crypto (void)
+crypto_error_t crypto_session_decode(const uint8_t *data, uint32_t length, alist *keypairs, CRYPTO_SESSION **session)
 {
-   int stat;
+   CRYPTO_SESSION *cs;
+   X509_KEYPAIR *keypair;
+   STACK_OF(RecipientInfo) *recipients;
+   crypto_error_t retval = CRYPTO_ERROR_NONE;
+   const unsigned char *p = (const unsigned char *)data;
 
-   if ((stat = openssl_init_threads()) != 0) {
-      Emsg1(M_ABORT, 0, _("Unable to init OpenSSL threading: ERR=%s\n"), strerror(stat));
+   /* bacula-fd.conf doesn't contains any key */
+   if (!keypairs) {
+      return CRYPTO_ERROR_NORECIPIENT;
    }
 
-   /* Load libssl and libcrypto human-readable error strings */
-   SSL_load_error_strings();
+   cs = (CRYPTO_SESSION *)malloc(sizeof(CRYPTO_SESSION));
+
+   /* Initialize required fields */
+   cs->session_key = NULL;
 
-   /* Register OpenSSL ciphers */
-   SSL_library_init();
+   /* d2i_CryptoData modifies the supplied pointer */
+   cs->cryptoData = d2i_CryptoData(NULL, &p, length);
 
-   if (!openssl_seed_prng()) {
-      Emsg0(M_ERROR_TERM, 0, _("Failed to seed OpenSSL PRNG\n"));
+   if (!cs->cryptoData) {
+      /* Allocation / Decoding failed in OpenSSL */
+      openssl_post_errors(M_ERROR, _("CryptoData decoding failed"));
+      retval = CRYPTO_ERROR_INTERNAL;
+      goto err;
+   }
+
+   recipients = cs->cryptoData->recipientInfo;
+
+   /*
+    * Find a matching RecipientInfo structure for a supplied
+    * public key
+    */
+   foreach_alist(keypair, keypairs) {
+      RecipientInfo *ri;
+      int i;
+
+      /* Private key available? */
+      if (keypair->privkey == NULL) {
+         continue;
+      }
+
+      for (i = 0; i < sk_RecipientInfo_num(recipients); i++) {
+         ri = sk_RecipientInfo_value(recipients, i);
+
+         /* Match against the subjectKeyIdentifier */
+         if (M_ASN1_OCTET_STRING_cmp(keypair->keyid, ri->subjectKeyIdentifier) == 0) {
+            /* Match found, extract symmetric encryption session data */
+
+            /* RSA is required. */
+            assert(EVP_PKEY_type(keypair->privkey->type) == EVP_PKEY_RSA);
+
+            /* If we recieve a RecipientInfo structure that does not use
+             * RSA, return an error */
+            if (OBJ_obj2nid(ri->keyEncryptionAlgorithm) != NID_rsaEncryption) {
+               retval = CRYPTO_ERROR_INVALID_CRYPTO;
+               goto err;
+            }
+
+            /* Decrypt the session key */
+            /* Allocate sufficient space for the largest possible decrypted data */
+            cs->session_key = (unsigned char *)malloc(EVP_PKEY_size(keypair->privkey));
+            cs->session_key_len = EVP_PKEY_decrypt(cs->session_key, M_ASN1_STRING_data(ri->encryptedKey),
+                                  M_ASN1_STRING_length(ri->encryptedKey), keypair->privkey);
+
+            if (cs->session_key_len <= 0) {
+               openssl_post_errors(M_ERROR, _("Failure decrypting the session key"));
+               retval = CRYPTO_ERROR_DECRYPTION;
+               goto err;
+            }
+
+            /* Session key successfully extracted, return the CRYPTO_SESSION structure */
+            *session = cs;
+            return CRYPTO_ERROR_NONE;
+         }
+      }
    }
 
-   crypto_initialized = true;
+   /* No matching recipient found */
+   return CRYPTO_ERROR_NORECIPIENT;
+
+err:
+   crypto_session_free(cs);
+   return retval;
+}
 
-   return stat;
+/*
+ * Free memory associated with a crypto session object.
+ */
+void crypto_session_free(CRYPTO_SESSION *cs)
+{
+   if (cs->cryptoData) {
+      CryptoData_free(cs->cryptoData);
+   }
+   if (cs->session_key){
+      free(cs->session_key);
+   }
+   free(cs);
 }
 
 /*
- * Perform global cleanup of OpenSSL
- * All cryptographic operations must be completed before calling this function.
- * This function is not thread safe.
- *  Returns: 0 on success
- *           errno on failure
+ * Create a new crypto cipher context with the specified session object
+ *  Returns: A pointer to a CIPHER_CONTEXT object on success. The cipher block size is returned in blocksize.
+ *           NULL on failure.
  */
-int cleanup_crypto (void)
+CIPHER_CONTEXT *crypto_cipher_new(CRYPTO_SESSION *cs, bool encrypt, uint32_t *blocksize)
 {
+   CIPHER_CONTEXT *cipher_ctx;
+   const EVP_CIPHER *ec;
+
+   cipher_ctx = (CIPHER_CONTEXT *)malloc(sizeof(CIPHER_CONTEXT));
+   if (!cipher_ctx)
+          return NULL;
+
+   cipher_ctx->ctx = EVP_CIPHER_CTX_new();
+   if (!cipher_ctx->ctx)
+          goto err;
+
    /*
-    * Ensure that we've actually been initialized; Doing this here decreases the
-    * complexity of client's termination/cleanup code.
+    * Acquire a cipher instance for the given ASN.1 cipher NID
     */
-   if (!crypto_initialized) {
-      return 0;
+   if ((ec = EVP_get_cipherbyobj(cs->cryptoData->contentEncryptionAlgorithm)) == NULL) {
+      Jmsg1(NULL, M_ERROR, 0,
+         _("Unsupported contentEncryptionAlgorithm: %d\n"), OBJ_obj2nid(cs->cryptoData->contentEncryptionAlgorithm));
+      free(cipher_ctx);
+      return NULL;
    }
 
-   if (!openssl_save_prng()) {
-      Emsg0(M_ERROR, 0, _("Failed to save OpenSSL PRNG\n"));
+   /* Initialize the OpenSSL cipher context */
+   EVP_CIPHER_CTX_reset(cipher_ctx->ctx);
+   if (encrypt) {
+      /* Initialize for encryption */
+      if (!EVP_CipherInit_ex(cipher_ctx->ctx, ec, NULL, NULL, NULL, 1)) {
+         openssl_post_errors(M_ERROR, _("OpenSSL cipher context initialization failed"));
+         goto err;
+      }
+   } else {
+      /* Initialize for decryption */
+      if (!EVP_CipherInit_ex(cipher_ctx->ctx, ec, NULL, NULL, NULL, 0)) {
+         openssl_post_errors(M_ERROR, _("OpenSSL cipher context initialization failed"));
+         goto err;
+      }
    }
 
-   openssl_cleanup_threads();
+   /* Set the key size */
+   if (!EVP_CIPHER_CTX_set_key_length(cipher_ctx->ctx, cs->session_key_len)) {
+      openssl_post_errors(M_ERROR, _("Encryption session provided an invalid symmetric key"));
+      goto err;
+   }
+
+   /* Validate the IV length */
+   if (EVP_CIPHER_iv_length(ec) != ASN1_STRING_length(cs->cryptoData->iv)) {
+      openssl_post_errors(M_ERROR, _("Encryption session provided an invalid IV"));
+      goto err;
+   }
+
+   /* Add the key and IV to the cipher context */
+   if (!EVP_CipherInit_ex(cipher_ctx->ctx, NULL, NULL, cs->session_key, ASN1_STRING_get0_data(cs->cryptoData->iv), -1)) {
+      openssl_post_errors(M_ERROR, _("OpenSSL cipher context key/IV initialization failed"));
+      goto err;
+   }
 
-   /* Free libssl and libcrypto error strings */
-   ERR_free_strings();
+   *blocksize = EVP_CIPHER_CTX_block_size(cipher_ctx->ctx);
+   return cipher_ctx;
 
-   /* Free memory used by PRNG */
-   RAND_cleanup();
+err:
+   crypto_cipher_free(cipher_ctx);
+   return NULL;
+}
 
-   crypto_initialized = false;
 
-   return 0;
+/*
+ * Encrypt/Decrypt length bytes of data using the provided cipher context
+ * Returns: true on success, number of bytes output in written
+ *          false on failure
+ */
+bool crypto_cipher_update(CIPHER_CONTEXT *cipher_ctx, const uint8_t *data, uint32_t length, const uint8_t *dest, uint32_t *written)
+{
+   if (!EVP_CipherUpdate(cipher_ctx->ctx, (unsigned char *)dest, (int *)written, (const unsigned char *)data, length)) {
+      /* This really shouldn't fail */
+      return false;
+   } else {
+      return true;
+   }
+}
+
+/*
+ * Finalize the cipher context, writing any remaining data and necessary padding
+ * to dest, and the size in written.
+ * The result size will either be one block of data or zero.
+ *
+ * Returns: true on success
+ *          false on failure
+ */
+bool crypto_cipher_finalize (CIPHER_CONTEXT *cipher_ctx, uint8_t *dest, uint32_t *written)
+{
+   if (!EVP_CipherFinal_ex(cipher_ctx->ctx, (unsigned char *)dest, (int *) written)) {
+      /* This really shouldn't fail */
+      return false;
+   } else {
+      return true;
+   }
 }
 
 
+/*
+ * Free memory associated with a cipher context.
+ */
+void crypto_cipher_free (CIPHER_CONTEXT *cipher_ctx)
+{
+   EVP_CIPHER_CTX_free(cipher_ctx->ctx);
+   free (cipher_ctx);
+}
+
 #else /* HAVE_OPENSSL */
 # error No encryption library available
 #endif /* HAVE_OPENSSL */
@@ -892,6 +1368,7 @@ int cleanup_crypto (void)
 /* Message Digest Structure */
 struct Digest {
    crypto_digest_t type;
+   JCR *jcr;
    union {
       SHA1Context sha1;
       MD5Context md5;
@@ -900,14 +1377,16 @@ struct Digest {
 
 /* Dummy Signature Structure */
 struct Signature {
+   JCR *jcr;
 };
 
-DIGEST *crypto_digest_new (crypto_digest_t type)
+DIGEST *crypto_digest_new(JCR *jcr, crypto_digest_t type)
 {
    DIGEST *digest;
 
-   digest = (DIGEST *) malloc(sizeof(DIGEST));
+   digest = (DIGEST *)malloc(sizeof(DIGEST));
    digest->type = type;
+   digest->jcr = jcr;
 
    switch (type) {
    case CRYPTO_DIGEST_MD5:
@@ -917,7 +1396,7 @@ DIGEST *crypto_digest_new (crypto_digest_t type)
       SHA1Init(&digest->sha1);
       break;
    default:
-      Emsg0(M_ERROR, 0, _("Unsupported digest type specified\n"));
+      Jmsg1(jcr, M_ERROR, 0, _("Unsupported digest type=%d specified\n"), type);
       free(digest);
       return NULL;
    }
@@ -925,7 +1404,8 @@ DIGEST *crypto_digest_new (crypto_digest_t type)
    return (digest);
 }
 
-int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
+bool crypto_digest_update(DIGEST *digest, const uint8_t *data, uint32_t length)
+{
    switch (digest->type) {
    case CRYPTO_DIGEST_MD5:
       /* Doesn't return anything ... */
@@ -934,10 +1414,10 @@ int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
    case CRYPTO_DIGEST_SHA1:
       int ret;
       if ((ret = SHA1Update(&digest->sha1, (const u_int8_t *) data, length)) == shaSuccess) {
-        return true;
+         return true;
       } else {
-         Emsg1(M_ERROR, 0, _("SHA1Update() returned an error: %d\n"), ret);
-        return false;
+         Jmsg1(NULL, M_ERROR, 0, _("SHA1Update() returned an error: %d\n"), ret);
+         return false;
       }
       break;
    default:
@@ -945,8 +1425,8 @@ int crypto_digest_update (DIGEST *digest, const void *data, size_t length) {
    }
 }
 
-int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
-
+bool crypto_digest_finalize(DIGEST *digest, uint8_t *dest, uint32_t *length)
+{
    switch (digest->type) {
    case CRYPTO_DIGEST_MD5:
       /* Guard against programmer error by either the API client or
@@ -954,7 +1434,7 @@ int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
       assert(*length >= CRYPTO_DIGEST_MD5_SIZE);
       *length = CRYPTO_DIGEST_MD5_SIZE;
       /* Doesn't return anything ... */
-      MD5Final((unsigned char *) dest, &digest->md5);
+      MD5Final((unsigned char *)dest, &digest->md5);
       return true;
    case CRYPTO_DIGEST_SHA1:
       /* Guard against programmer error by either the API client or
@@ -962,9 +1442,9 @@ int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
       assert(*length >= CRYPTO_DIGEST_SHA1_SIZE);
       *length = CRYPTO_DIGEST_SHA1_SIZE;
       if (SHA1Final(&digest->sha1, (u_int8_t *) dest) == shaSuccess) {
-        return true;
+         return true;
       } else {
-        return false;
+         return false;
       }
       break;
    default:
@@ -974,32 +1454,43 @@ int crypto_digest_finalize (DIGEST *digest, void *dest, size_t *length) {
    return false;
 }
 
-void crypto_digest_free (DIGEST *digest)
+void crypto_digest_free(DIGEST *digest)
 {
-   free (digest);
+   free(digest);
 }
 
-/* Dummy routines */
-int init_crypto (void) { return 0; }
-int cleanup_crypto (void) { return 0; }
+SIGNATURE *crypto_sign_new(JCR *jcr) { return NULL; }
 
-SIGNATURE *crypto_sign_new (void) { return NULL; }
+crypto_error_t crypto_sign_get_digest (SIGNATURE *sig, X509_KEYPAIR *keypair,
+                                       crypto_digest_t &type, DIGEST **digest)
+   { return CRYPTO_ERROR_INTERNAL; }
 
-crypto_error_t crypto_sign_get_digest (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST **digest) { return CRYPTO_ERROR_INTERNAL; }
 crypto_error_t crypto_sign_verify (SIGNATURE *sig, X509_KEYPAIR *keypair, DIGEST *digest) { return CRYPTO_ERROR_INTERNAL; }
 
 int crypto_sign_add_signer (SIGNATURE *sig, DIGEST *digest, X509_KEYPAIR *keypair) { return false; }
-int crypto_sign_encode (SIGNATURE *sig, void *dest, size_t *length) { return false; }
+int crypto_sign_encode (SIGNATURE *sig, uint8_t *dest, uint32_t *length) { return false; }
 
-SIGNATURE *crypto_sign_decode (const void *sigData, size_t length) { return false; }
+SIGNATURE *crypto_sign_decode (JCR *jcr, const uint8_t *sigData, uint32_t length) { return NULL; }
 void crypto_sign_free (SIGNATURE *sig) { }
 
 
-X509_KEYPAIR *crypto_keypair_new (void) { return NULL; }
+X509_KEYPAIR *crypto_keypair_new(void) { return NULL; }
+X509_KEYPAIR *crypto_keypair_dup (X509_KEYPAIR *keypair) { return NULL; }
 int crypto_keypair_load_cert (X509_KEYPAIR *keypair, const char *file) { return false; }
+bool crypto_keypair_has_key (const char *file) { return false; }
 int crypto_keypair_load_key (X509_KEYPAIR *keypair, const char *file, CRYPTO_PEM_PASSWD_CB *pem_callback, const void *pem_userdata) { return false; }
 void crypto_keypair_free (X509_KEYPAIR *keypair) { }
 
+CRYPTO_SESSION *crypto_session_new (crypto_cipher_t cipher, alist *pubkeys) { return NULL; }
+void crypto_session_free (CRYPTO_SESSION *cs) { }
+bool crypto_session_encode (CRYPTO_SESSION *cs, uint8_t *dest, uint32_t *length) { return false; }
+crypto_error_t crypto_session_decode(const uint8_t *data, uint32_t length, alist *keypairs, CRYPTO_SESSION **session) { return CRYPTO_ERROR_INTERNAL; }
+
+CIPHER_CONTEXT *crypto_cipher_new (CRYPTO_SESSION *cs, bool encrypt, uint32_t *blocksize) { return NULL; }
+bool crypto_cipher_update (CIPHER_CONTEXT *cipher_ctx, const uint8_t *data, uint32_t length, const uint8_t *dest, uint32_t *written) { return false; }
+bool crypto_cipher_finalize (CIPHER_CONTEXT *cipher_ctx, uint8_t *dest, uint32_t *written) { return false; }
+void crypto_cipher_free (CIPHER_CONTEXT *cipher_ctx) { }
+
 #endif /* HAVE_CRYPTO */
 
 /* Shared Code */
@@ -1018,7 +1509,8 @@ int crypto_default_pem_callback(char *buf, int size, const void *userdata)
  * Returns the ASCII name of the digest type.
  * Returns: ASCII name of digest type.
  */
-const char *crypto_digest_name (DIGEST *digest) {
+const char *crypto_digest_name(DIGEST *digest)
+{
    switch (digest->type) {
    case CRYPTO_DIGEST_MD5:
       return "MD5";
@@ -1040,7 +1532,8 @@ const char *crypto_digest_name (DIGEST *digest) {
  * Given a stream type, returns the associated
  * crypto_digest_t value.
  */
-crypto_digest_t crypto_digest_stream_type (int stream) {
+crypto_digest_t crypto_digest_stream_type(int stream)
+{
    switch (stream) {
    case STREAM_MD5_DIGEST:
       return CRYPTO_DIGEST_MD5;
@@ -1062,17 +1555,23 @@ crypto_digest_t crypto_digest_stream_type (int stream) {
 const char *crypto_strerror(crypto_error_t error) {
    switch (error) {
    case CRYPTO_ERROR_NONE:
-      return "No error";
+      return _("No error");
    case CRYPTO_ERROR_NOSIGNER:
-      return "Signer not found";
+      return _("Signer not found");
+   case CRYPTO_ERROR_NORECIPIENT:
+      return _("Recipient not found");
    case CRYPTO_ERROR_INVALID_DIGEST:
-      return "Unsupported digest algorithm";
+      return _("Unsupported digest algorithm");
+   case CRYPTO_ERROR_INVALID_CRYPTO:
+      return _("Unsupported encryption algorithm");
    case CRYPTO_ERROR_BAD_SIGNATURE:
-      return "Signature is invalid";
+      return _("Signature is invalid");
+   case CRYPTO_ERROR_DECRYPTION:
+      return _("Decryption error");
    case CRYPTO_ERROR_INTERNAL:
       /* This shouldn't happen */
-      return "Internal error";
+      return _("Internal error");
    default:
-      return "Unknown error";
+      return _("Unknown error");
    }
 }