comphelper/Library_comphelper.mk            |    5 
 comphelper/source/crypto/Crypto.cxx         |  482 ----------------------------
 comphelper/source/crypto/Crypto_NSS.cxx     |  295 +++++++++++++++++
 comphelper/source/crypto/Crypto_None.cxx    |   67 +++
 comphelper/source/crypto/Crypto_OpenSSL.cxx |  208 ++++++++++++
 include/comphelper/crypto/Crypto.hxx        |   27 +
 6 files changed, 604 insertions(+), 480 deletions(-)

New commits:
commit 676524f200b114e5bb097812321c86516cbbdda0
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Tue Nov 26 15:22:13 2024 +0900
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Nov 29 13:28:12 2024 +0100

    comphelper: put each Crypto impl. in own file - minimize ifdefs
    
    This puts NSS and OpenSSL implementations into own classes and
    adds an interface to make this possible. The implementation is
    now determined in Library_comphelper.
    
    Change-Id: I4918f19bca0adfd2f9180fb418d1bd57bb83982d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177308
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/comphelper/Library_comphelper.mk b/comphelper/Library_comphelper.mk
index c8eabde5065c..f9bd120fd960 100644
--- a/comphelper/Library_comphelper.mk
+++ b/comphelper/Library_comphelper.mk
@@ -70,12 +70,15 @@ $(eval $(call gb_Library_add_exception_objects,comphelper,\
     comphelper/source/container/NamedPropertyValuesContainer \
     comphelper/source/container/container \
     comphelper/source/container/containermultiplexer \
-       comphelper/source/container/interfacecontainer2 \
+    comphelper/source/container/interfacecontainer2 \
     comphelper/source/container/embeddedobjectcontainer \
     comphelper/source/container/enumerablemap \
     comphelper/source/container/enumhelper \
     comphelper/source/container/namecontainer \
     comphelper/source/crypto/Crypto \
+    $(if $(filter NSS,$(TLS)), comphelper/source/crypto/Crypto_NSS) \
+    $(if $(filter OPENSSL,$(TLS)), comphelper/source/crypto/Crypto_OpenSSL) \
+    $(if $(filter NSS OPENSSL,$(TLS)),,comphelper/source/crypto/Crypto_None) \
     comphelper/source/eventattachermgr/eventattachermgr \
     comphelper/source/misc/accessiblecomponenthelper \
     comphelper/source/misc/accessibleeventnotifier \
diff --git a/comphelper/source/crypto/Crypto.cxx 
b/comphelper/source/crypto/Crypto.cxx
index a65718ae20f1..faf1da7307f9 100644
--- a/comphelper/source/crypto/Crypto.cxx
+++ b/comphelper/source/crypto/Crypto.cxx
@@ -5,447 +5,34 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
  */
 
 #include <comphelper/crypto/Crypto.hxx>
 #include <com/sun/star/uno/RuntimeException.hpp>
 #include <sal/types.h>
-
 #include <config_oox.h>
 
-#if USE_TLS_OPENSSL
-#include <openssl/evp.h>
-#include <openssl/sha.h>
-#include <openssl/hmac.h>
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
-#include <nss.h>
-#include <nspr.h>
-#include <pk11pub.h>
-#endif // USE_TLS_NSS
-
 namespace comphelper
 {
-#if USE_TLS_OPENSSL
-
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
-
-static HMAC_CTX* HMAC_CTX_new(void)
-{
-    HMAC_CTX* pContext = new HMAC_CTX;
-    HMAC_CTX_init(pContext);
-    return pContext;
-}
-
-static void HMAC_CTX_free(HMAC_CTX* pContext)
-{
-    HMAC_CTX_cleanup(pContext);
-    delete pContext;
-}
-#endif
-
-namespace
-{
-struct cipher_delete
-{
-    void operator()(EVP_CIPHER_CTX* p) { EVP_CIPHER_CTX_free(p); }
-};
-
-struct hmac_delete
-{
-    SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_CTX_free' is deprecated
-        void
-        operator()(HMAC_CTX* p)
-    {
-        HMAC_CTX_free(p);
-    }
-    SAL_WNODEPRECATED_DECLARATIONS_POP
-};
-}
-
-struct CryptoImpl
-{
-    std::unique_ptr<EVP_CIPHER_CTX, cipher_delete> mpContext;
-    std::unique_ptr<HMAC_CTX, hmac_delete> mpHmacContext;
-
-    CryptoImpl() = default;
-
-    void setupEncryptContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
-                             CryptoType eType)
-    {
-        mpContext.reset(EVP_CIPHER_CTX_new());
-        EVP_CIPHER_CTX_init(mpContext.get());
-
-        const EVP_CIPHER* cipher = getCipher(eType);
-        if (cipher == nullptr)
-            return;
-
-        if (iv.empty())
-            EVP_EncryptInit_ex(mpContext.get(), cipher, nullptr, key.data(), 
nullptr);
-        else
-            EVP_EncryptInit_ex(mpContext.get(), cipher, nullptr, key.data(), 
iv.data());
-        EVP_CIPHER_CTX_set_padding(mpContext.get(), 0);
-    }
-
-    void setupDecryptContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
-                             CryptoType eType)
-    {
-        mpContext.reset(EVP_CIPHER_CTX_new());
-        EVP_CIPHER_CTX_init(mpContext.get());
-
-        const EVP_CIPHER* pCipher = getCipher(eType);
-        if (pCipher == nullptr)
-            return;
-
-        const size_t nMinKeySize = EVP_CIPHER_key_length(pCipher);
-        if (key.size() < nMinKeySize)
-            key.resize(nMinKeySize, 0);
-
-        if (iv.empty())
-            EVP_DecryptInit_ex(mpContext.get(), pCipher, nullptr, key.data(), 
nullptr);
-        else
-        {
-            const size_t nMinIVSize = EVP_CIPHER_iv_length(pCipher);
-            if (iv.size() < nMinIVSize)
-                iv.resize(nMinIVSize, 0);
-
-            EVP_DecryptInit_ex(mpContext.get(), pCipher, nullptr, key.data(), 
iv.data());
-        }
-        EVP_CIPHER_CTX_set_padding(mpContext.get(), 0);
-    }
-
-    void setupCryptoHashContext(std::vector<sal_uInt8>& rKey, CryptoHashType 
eType)
-    {
-        SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_CTX_new' is deprecated
-            mpHmacContext.reset(HMAC_CTX_new());
-        SAL_WNODEPRECATED_DECLARATIONS_POP
-        const EVP_MD* aEvpMd = nullptr;
-        switch (eType)
-        {
-            case CryptoHashType::SHA1:
-                aEvpMd = EVP_sha1();
-                break;
-            case CryptoHashType::SHA256:
-                aEvpMd = EVP_sha256();
-                break;
-            case CryptoHashType::SHA384:
-                aEvpMd = EVP_sha384();
-                break;
-            case CryptoHashType::SHA512:
-                aEvpMd = EVP_sha512();
-                break;
-        }
-        SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_Init_ex' is deprecated
-            HMAC_Init_ex(mpHmacContext.get(), rKey.data(), rKey.size(), 
aEvpMd, nullptr);
-        SAL_WNODEPRECATED_DECLARATIONS_POP
-    }
-
-    ~CryptoImpl()
-    {
-        if (mpContext)
-            EVP_CIPHER_CTX_cleanup(mpContext.get());
-    }
-
-    static const EVP_CIPHER* getCipher(CryptoType type)
-    {
-        switch (type)
-        {
-            case CryptoType::AES_128_ECB:
-                return EVP_aes_128_ecb();
-            case CryptoType::AES_256_ECB:
-                return EVP_aes_256_ecb();
-            case CryptoType::AES_128_CBC:
-                return EVP_aes_128_cbc();
-            case CryptoType::AES_256_CBC:
-                return EVP_aes_256_cbc();
-            default:
-                break;
-        }
-        return nullptr;
-    }
-};
-
-#elif USE_TLS_NSS
-
-#define MAX_WRAPPED_KEY_LEN 128
-
-struct CryptoImpl
-{
-    PK11SlotInfo* mSlot;
-    PK11Context* mContext;
-    SECItem* mSecParam;
-    PK11SymKey* mSymKey;
-    PK11Context* mWrapKeyContext;
-    PK11SymKey* mWrapKey;
-
-    CryptoImpl()
-        : mSlot(nullptr)
-        , mContext(nullptr)
-        , mSecParam(nullptr)
-        , mSymKey(nullptr)
-        , mWrapKeyContext(nullptr)
-        , mWrapKey(nullptr)
-    {
-        // Initialize NSS, database functions are not needed
-        if (!NSS_IsInitialized())
-        {
-            auto const e = NSS_NoDB_Init(nullptr);
-            if (e != SECSuccess)
-            {
-                PRErrorCode error = PR_GetError();
-                const char* errorText = PR_ErrorToName(error);
-                throw css::uno::RuntimeException(
-                    "NSS_NoDB_Init failed with "
-                    + OUString(errorText, strlen(errorText), 
RTL_TEXTENCODING_UTF8) + " ("
-                    + OUString::number(static_cast<int>(error)) + ")");
-            }
-        }
-    }
-
-    ~CryptoImpl()
-    {
-        if (mContext)
-            PK11_DestroyContext(mContext, PR_TRUE);
-        if (mSecParam)
-            SECITEM_FreeItem(mSecParam, PR_TRUE);
-        if (mSymKey)
-            PK11_FreeSymKey(mSymKey);
-        if (mWrapKeyContext)
-            PK11_DestroyContext(mWrapKeyContext, PR_TRUE);
-        if (mWrapKey)
-            PK11_FreeSymKey(mWrapKey);
-        if (mSlot)
-            PK11_FreeSlot(mSlot);
-    }
-
-    PK11SymKey* ImportSymKey(CK_MECHANISM_TYPE mechanism, CK_ATTRIBUTE_TYPE 
operation, SECItem* key)
-    {
-        mSymKey = PK11_ImportSymKey(mSlot, mechanism, PK11_OriginUnwrap, 
operation, key, nullptr);
-        if (!mSymKey) //rhbz#1614419 maybe failed due to FIPS, use 
rhbz#1461450 style workaround
-        {
-            /*
-             * Without FIPS it would be possible to just use
-             *  mSymKey = PK11_ImportSymKey( mSlot, mechanism, 
PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr );
-             * with FIPS NSS Level 2 certification has to be "workarounded" 
(so it becomes Level 1) by using
-             * following method:
-             * 1. Generate wrap key
-             * 2. Encrypt authkey with wrap key
-             * 3. Unwrap encrypted authkey using wrap key
-             */
-
-            /*
-             * Generate wrapping key
-             */
-            CK_MECHANISM_TYPE wrap_mechanism = 
PK11_GetBestWrapMechanism(mSlot);
-            int wrap_key_len = PK11_GetBestKeyLength(mSlot, wrap_mechanism);
-            mWrapKey = PK11_KeyGen(mSlot, wrap_mechanism, nullptr, 
wrap_key_len, nullptr);
-            if (!mWrapKey)
-                throw css::uno::RuntimeException("PK11_KeyGen SymKey failure",
-                                                 
css::uno::Reference<css::uno::XInterface>());
-
-            /*
-             * Encrypt authkey with wrapping key
-             */
-
-            /*
-             * Initialization of IV is not needed because 
PK11_GetBestWrapMechanism should return ECB mode
-             */
-            SECItem tmp_sec_item = {};
-            mWrapKeyContext
-                = PK11_CreateContextBySymKey(wrap_mechanism, CKA_ENCRYPT, 
mWrapKey, &tmp_sec_item);
-            if (!mWrapKeyContext)
-                throw css::uno::RuntimeException("PK11_CreateContextBySymKey 
failure",
-                                                 
css::uno::Reference<css::uno::XInterface>());
-
-            unsigned char wrapped_key_data[MAX_WRAPPED_KEY_LEN];
-            int wrapped_key_len = sizeof(wrapped_key_data);
-
-            if (PK11_CipherOp(mWrapKeyContext, wrapped_key_data, 
&wrapped_key_len,
-                              sizeof(wrapped_key_data), key->data, key->len)
-                != SECSuccess)
-            {
-                throw css::uno::RuntimeException("PK11_CipherOp failure",
-                                                 
css::uno::Reference<css::uno::XInterface>());
-            }
-
-            if (PK11_Finalize(mWrapKeyContext) != SECSuccess)
-                throw css::uno::RuntimeException("PK11_Finalize failure",
-                                                 
css::uno::Reference<css::uno::XInterface>());
-
-            /*
-             * Finally unwrap sym key
-             */
-            SECItem wrapped_key = {};
-            wrapped_key.data = wrapped_key_data;
-            wrapped_key.len = wrapped_key_len;
-
-            mSymKey = PK11_UnwrapSymKey(mWrapKey, wrap_mechanism, 
&tmp_sec_item, &wrapped_key,
-                                        mechanism, operation, key->len);
-        }
-        return mSymKey;
-    }
-
-    void setupEncryptContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
-                             CryptoType type)
-    {
-        setupCryptoContext(key, iv, type, CKA_ENCRYPT);
-    }
-
-    void setupDecryptContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
-                             CryptoType type)
-    {
-        setupCryptoContext(key, iv, type, CKA_DECRYPT);
-    }
-
-    void setupCryptoContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
-                            CryptoType type, CK_ATTRIBUTE_TYPE operation)
-    {
-        CK_MECHANISM_TYPE mechanism = static_cast<CK_ULONG>(-1);
-
-        SECItem ivItem;
-        ivItem.type = siBuffer;
-        if (iv.empty())
-            ivItem.data = nullptr;
-        else
-            ivItem.data = iv.data();
-        ivItem.len = iv.size();
-
-        SECItem* pIvItem = nullptr;
-
-        switch (type)
-        {
-            case CryptoType::AES_128_ECB:
-            case CryptoType::AES_256_ECB:
-                mechanism = CKM_AES_ECB;
-                break;
-            case CryptoType::AES_128_CBC:
-                mechanism = CKM_AES_CBC;
-                pIvItem = &ivItem;
-                break;
-            case CryptoType::AES_256_CBC:
-                mechanism = CKM_AES_CBC;
-                pIvItem = &ivItem;
-                break;
-            default:
-                break;
-        }
-
-        mSlot = PK11_GetBestSlot(mechanism, nullptr);
-
-        if (!mSlot)
-            throw css::uno::RuntimeException("NSS Slot failure",
-                                             
css::uno::Reference<css::uno::XInterface>());
-
-        SECItem keyItem;
-        keyItem.type = siBuffer;
-        keyItem.data = key.data();
-        keyItem.len = key.size();
-
-        mSymKey = ImportSymKey(mechanism, CKA_ENCRYPT, &keyItem);
-        if (!mSymKey)
-            throw css::uno::RuntimeException("NSS SymKey failure",
-                                             
css::uno::Reference<css::uno::XInterface>());
-
-        mSecParam = PK11_ParamFromIV(mechanism, pIvItem);
-        mContext = PK11_CreateContextBySymKey(mechanism, operation, mSymKey, 
mSecParam);
-    }
-
-    void setupCryptoHashContext(std::vector<sal_uInt8>& rKey, CryptoHashType 
eType)
-    {
-        CK_MECHANISM_TYPE aMechanism = static_cast<CK_ULONG>(-1);
-
-        switch (eType)
-        {
-            case CryptoHashType::SHA1:
-                aMechanism = CKM_SHA_1_HMAC;
-                break;
-            case CryptoHashType::SHA256:
-                aMechanism = CKM_SHA256_HMAC;
-                break;
-            case CryptoHashType::SHA384:
-                aMechanism = CKM_SHA384_HMAC;
-                break;
-            case CryptoHashType::SHA512:
-                aMechanism = CKM_SHA512_HMAC;
-                break;
-        }
-
-        mSlot = PK11_GetBestSlot(aMechanism, nullptr);
-
-        if (!mSlot)
-            throw css::uno::RuntimeException("NSS Slot failure",
-                                             
css::uno::Reference<css::uno::XInterface>());
-
-        SECItem aKeyItem;
-        aKeyItem.data = rKey.data();
-        aKeyItem.len = rKey.size();
-
-        mSymKey = ImportSymKey(aMechanism, CKA_SIGN, &aKeyItem);
-        if (!mSymKey)
-            throw css::uno::RuntimeException("NSS SymKey failure",
-                                             
css::uno::Reference<css::uno::XInterface>());
-
-        SECItem param;
-        param.data = nullptr;
-        param.len = 0;
-        mContext = PK11_CreateContextBySymKey(aMechanism, CKA_SIGN, mSymKey, 
&param);
-    }
-};
-#else
-struct CryptoImpl
-{
-};
-#endif
-
 Crypto::Crypto()
-    : mpImpl(std::make_unique<CryptoImpl>())
+    : mpImpl(ICryptoImplementation::createInstance())
 {
 }
-
-Crypto::~Crypto() {}
+Crypto::~Crypto() = default;
 
 // DECRYPT
 
 Decrypt::Decrypt(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, 
CryptoType type)
 {
-#if USE_TLS_OPENSSL + USE_TLS_NSS == 0
-    (void)key;
-    (void)iv;
-    (void)type;
-#else
     mpImpl->setupDecryptContext(key, iv, type);
-#endif
 }
 
 sal_uInt32 Decrypt::update(std::vector<sal_uInt8>& output, 
std::vector<sal_uInt8>& input,
                            sal_uInt32 inputLength)
 {
-    int outputLength = 0;
-
-#if USE_TLS_OPENSSL + USE_TLS_NSS > 0
     sal_uInt32 actualInputLength
         = inputLength == 0 || inputLength > input.size() ? input.size() : 
inputLength;
-#else
-    (void)output;
-    (void)input;
-    (void)inputLength;
-#endif
-
-#if USE_TLS_OPENSSL
-    (void)EVP_DecryptUpdate(mpImpl->mpContext.get(), output.data(), 
&outputLength, input.data(),
-                            actualInputLength);
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
-    if (!mpImpl->mContext)
-        return 0;
-    (void)PK11_CipherOp(mpImpl->mContext, output.data(), &outputLength, 
actualInputLength,
-                        input.data(), actualInputLength);
-#endif // USE_TLS_NSS
-
-    return static_cast<sal_uInt32>(outputLength);
+    return mpImpl->decryptUpdate(output, input, actualInputLength);
 }
 
 sal_uInt32 Decrypt::aes128ecb(std::vector<sal_uInt8>& output, 
std::vector<sal_uInt8>& input,
@@ -462,40 +49,15 @@ sal_uInt32 Decrypt::aes128ecb(std::vector<sal_uInt8>& 
output, std::vector<sal_uI
 
 Encrypt::Encrypt(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, 
CryptoType type)
 {
-#if USE_TLS_OPENSSL + USE_TLS_NSS == 0
-    (void)key;
-    (void)iv;
-    (void)type;
-#else
     mpImpl->setupEncryptContext(key, iv, type);
-#endif
 }
 
 sal_uInt32 Encrypt::update(std::vector<sal_uInt8>& output, 
std::vector<sal_uInt8>& input,
                            sal_uInt32 inputLength)
 {
-    int outputLength = 0;
-
-#if USE_TLS_OPENSSL + USE_TLS_NSS > 0
     sal_uInt32 actualInputLength
         = inputLength == 0 || inputLength > input.size() ? input.size() : 
inputLength;
-#else
-    (void)output;
-    (void)input;
-    (void)inputLength;
-#endif
-
-#if USE_TLS_OPENSSL
-    (void)EVP_EncryptUpdate(mpImpl->mpContext.get(), output.data(), 
&outputLength, input.data(),
-                            actualInputLength);
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
-    (void)PK11_CipherOp(mpImpl->mContext, output.data(), &outputLength, 
actualInputLength,
-                        input.data(), actualInputLength);
-#endif // USE_TLS_NSS
-
-    return static_cast<sal_uInt32>(outputLength);
+    return mpImpl->encryptUpdate(output, input, actualInputLength);
 }
 
 // CryptoHash - HMAC
@@ -523,52 +85,20 @@ sal_Int32 getSizeForHashType(CryptoHashType eType)
 CryptoHash::CryptoHash(std::vector<sal_uInt8>& rKey, CryptoHashType eType)
     : mnHashSize(getSizeForHashType(eType))
 {
-#if USE_TLS_OPENSSL + USE_TLS_NSS > 0
     mpImpl->setupCryptoHashContext(rKey, eType);
-
-#if USE_TLS_NSS
-    PK11_DigestBegin(mpImpl->mContext);
-#endif
-
-#else
-    (void)rKey;
-#endif
 }
 
 bool CryptoHash::update(std::vector<sal_uInt8>& rInput, sal_uInt32 
nInputLength)
 {
-#if USE_TLS_OPENSSL + USE_TLS_NSS > 0
     sal_uInt32 nActualInputLength
         = (nInputLength == 0 || nInputLength > rInput.size()) ? rInput.size() 
: nInputLength;
-#else
-    (void)rInput;
-    (void)nInputLength;
-#endif
-
-#if USE_TLS_OPENSSL
-    SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_Update' is deprecated
-        return HMAC_Update(mpImpl->mpHmacContext.get(), rInput.data(), 
nActualInputLength)
-        != 0;
-    SAL_WNODEPRECATED_DECLARATIONS_POP
-#elif USE_TLS_NSS
-    return PK11_DigestOp(mpImpl->mContext, rInput.data(), nActualInputLength) 
== SECSuccess;
-#else
-    return false; // ???
-#endif
+    return mpImpl->cryptoHashUpdate(rInput, nActualInputLength);
 }
 
 std::vector<sal_uInt8> CryptoHash::finalize()
 {
     std::vector<sal_uInt8> aHash(mnHashSize, 0);
-#if USE_TLS_OPENSSL
-    unsigned int nSizeWritten = 0;
-    SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_Final' is deprecated
-        (void) HMAC_Final(mpImpl->mpHmacContext.get(), aHash.data(), 
&nSizeWritten);
-    SAL_WNODEPRECATED_DECLARATIONS_POP
-#elif USE_TLS_NSS
-    unsigned int nSizeWritten = 0;
-    PK11_DigestFinal(mpImpl->mContext, aHash.data(), &nSizeWritten, 
aHash.size());
-#endif
+    mpImpl->cryptoHashFinalize(aHash);
     return aHash;
 }
 
diff --git a/comphelper/source/crypto/Crypto_NSS.cxx 
b/comphelper/source/crypto/Crypto_NSS.cxx
new file mode 100644
index 000000000000..4291961c801d
--- /dev/null
+++ b/comphelper/source/crypto/Crypto_NSS.cxx
@@ -0,0 +1,295 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <comphelper/crypto/Crypto.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <sal/types.h>
+#include <config_oox.h>
+
+#include <nss.h>
+#include <nspr.h>
+#include <pk11pub.h>
+
+namespace comphelper
+{
+namespace
+{
+#define MAX_WRAPPED_KEY_LEN 128
+
+class CryptoImplementationNSS : public ICryptoImplementation
+{
+    PK11SlotInfo* mSlot;
+    PK11Context* mContext;
+    SECItem* mSecParam;
+    PK11SymKey* mSymKey;
+    PK11Context* mWrapKeyContext;
+    PK11SymKey* mWrapKey;
+
+public:
+    CryptoImplementationNSS()
+        : mSlot(nullptr)
+        , mContext(nullptr)
+        , mSecParam(nullptr)
+        , mSymKey(nullptr)
+        , mWrapKeyContext(nullptr)
+        , mWrapKey(nullptr)
+    {
+        // Initialize NSS, database functions are not needed
+        if (!NSS_IsInitialized())
+        {
+            auto const e = NSS_NoDB_Init(nullptr);
+            if (e != SECSuccess)
+            {
+                PRErrorCode error = PR_GetError();
+                const char* errorText = PR_ErrorToName(error);
+                throw css::uno::RuntimeException(
+                    "NSS_NoDB_Init failed with "
+                    + OUString(errorText, strlen(errorText), 
RTL_TEXTENCODING_UTF8) + " ("
+                    + OUString::number(static_cast<int>(error)) + ")");
+            }
+        }
+    }
+
+    virtual ~CryptoImplementationNSS()
+    {
+        if (mContext)
+            PK11_DestroyContext(mContext, PR_TRUE);
+        if (mSecParam)
+            SECITEM_FreeItem(mSecParam, PR_TRUE);
+        if (mSymKey)
+            PK11_FreeSymKey(mSymKey);
+        if (mWrapKeyContext)
+            PK11_DestroyContext(mWrapKeyContext, PR_TRUE);
+        if (mWrapKey)
+            PK11_FreeSymKey(mWrapKey);
+        if (mSlot)
+            PK11_FreeSlot(mSlot);
+    }
+
+    PK11SymKey* ImportSymKey(CK_MECHANISM_TYPE mechanism, CK_ATTRIBUTE_TYPE 
operation, SECItem* key)
+    {
+        mSymKey = PK11_ImportSymKey(mSlot, mechanism, PK11_OriginUnwrap, 
operation, key, nullptr);
+        if (!mSymKey) //rhbz#1614419 maybe failed due to FIPS, use 
rhbz#1461450 style workaround
+        {
+            /*
+             * Without FIPS it would be possible to just use
+             *  mSymKey = PK11_ImportSymKey( mSlot, mechanism, 
PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr );
+             * with FIPS NSS Level 2 certification has to be "workarounded" 
(so it becomes Level 1) by using
+             * following method:
+             * 1. Generate wrap key
+             * 2. Encrypt authkey with wrap key
+             * 3. Unwrap encrypted authkey using wrap key
+             */
+
+            /*
+             * Generate wrapping key
+             */
+            CK_MECHANISM_TYPE wrap_mechanism = 
PK11_GetBestWrapMechanism(mSlot);
+            int wrap_key_len = PK11_GetBestKeyLength(mSlot, wrap_mechanism);
+            mWrapKey = PK11_KeyGen(mSlot, wrap_mechanism, nullptr, 
wrap_key_len, nullptr);
+            if (!mWrapKey)
+                throw css::uno::RuntimeException("PK11_KeyGen SymKey failure",
+                                                 
css::uno::Reference<css::uno::XInterface>());
+
+            /*
+             * Encrypt authkey with wrapping key
+             */
+
+            /*
+             * Initialization of IV is not needed because 
PK11_GetBestWrapMechanism should return ECB mode
+             */
+            SECItem tmp_sec_item = {};
+            mWrapKeyContext
+                = PK11_CreateContextBySymKey(wrap_mechanism, CKA_ENCRYPT, 
mWrapKey, &tmp_sec_item);
+            if (!mWrapKeyContext)
+                throw css::uno::RuntimeException("PK11_CreateContextBySymKey 
failure",
+                                                 
css::uno::Reference<css::uno::XInterface>());
+
+            unsigned char wrapped_key_data[MAX_WRAPPED_KEY_LEN];
+            int wrapped_key_len = sizeof(wrapped_key_data);
+
+            if (PK11_CipherOp(mWrapKeyContext, wrapped_key_data, 
&wrapped_key_len,
+                              sizeof(wrapped_key_data), key->data, key->len)
+                != SECSuccess)
+            {
+                throw css::uno::RuntimeException("PK11_CipherOp failure",
+                                                 
css::uno::Reference<css::uno::XInterface>());
+            }
+
+            if (PK11_Finalize(mWrapKeyContext) != SECSuccess)
+                throw css::uno::RuntimeException("PK11_Finalize failure",
+                                                 
css::uno::Reference<css::uno::XInterface>());
+
+            /*
+             * Finally unwrap sym key
+             */
+            SECItem wrapped_key = {};
+            wrapped_key.data = wrapped_key_data;
+            wrapped_key.len = wrapped_key_len;
+
+            mSymKey = PK11_UnwrapSymKey(mWrapKey, wrap_mechanism, 
&tmp_sec_item, &wrapped_key,
+                                        mechanism, operation, key->len);
+        }
+        return mSymKey;
+    }
+
+    void setupEncryptContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
+                             CryptoType type) override
+    {
+        setupCryptoContext(key, iv, type, CKA_ENCRYPT);
+    }
+
+    void setupDecryptContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
+                             CryptoType type) override
+    {
+        setupCryptoContext(key, iv, type, CKA_DECRYPT);
+    }
+
+    void setupCryptoContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
+                            CryptoType type, CK_ATTRIBUTE_TYPE operation)
+    {
+        CK_MECHANISM_TYPE mechanism = static_cast<CK_ULONG>(-1);
+
+        SECItem ivItem;
+        ivItem.type = siBuffer;
+        if (iv.empty())
+            ivItem.data = nullptr;
+        else
+            ivItem.data = iv.data();
+        ivItem.len = iv.size();
+
+        SECItem* pIvItem = nullptr;
+
+        switch (type)
+        {
+            case CryptoType::AES_128_ECB:
+            case CryptoType::AES_256_ECB:
+                mechanism = CKM_AES_ECB;
+                break;
+            case CryptoType::AES_128_CBC:
+                mechanism = CKM_AES_CBC;
+                pIvItem = &ivItem;
+                break;
+            case CryptoType::AES_256_CBC:
+                mechanism = CKM_AES_CBC;
+                pIvItem = &ivItem;
+                break;
+            default:
+                break;
+        }
+
+        mSlot = PK11_GetBestSlot(mechanism, nullptr);
+
+        if (!mSlot)
+            throw css::uno::RuntimeException("NSS Slot failure",
+                                             
css::uno::Reference<css::uno::XInterface>());
+
+        SECItem keyItem;
+        keyItem.type = siBuffer;
+        keyItem.data = key.data();
+        keyItem.len = key.size();
+
+        mSymKey = ImportSymKey(mechanism, CKA_ENCRYPT, &keyItem);
+        if (!mSymKey)
+            throw css::uno::RuntimeException("NSS SymKey failure",
+                                             
css::uno::Reference<css::uno::XInterface>());
+
+        mSecParam = PK11_ParamFromIV(mechanism, pIvItem);
+        mContext = PK11_CreateContextBySymKey(mechanism, operation, mSymKey, 
mSecParam);
+    }
+
+    void setupCryptoHashContext(std::vector<sal_uInt8>& rKey, CryptoHashType 
eType) override
+    {
+        CK_MECHANISM_TYPE aMechanism = static_cast<CK_ULONG>(-1);
+
+        switch (eType)
+        {
+            case CryptoHashType::SHA1:
+                aMechanism = CKM_SHA_1_HMAC;
+                break;
+            case CryptoHashType::SHA256:
+                aMechanism = CKM_SHA256_HMAC;
+                break;
+            case CryptoHashType::SHA384:
+                aMechanism = CKM_SHA384_HMAC;
+                break;
+            case CryptoHashType::SHA512:
+                aMechanism = CKM_SHA512_HMAC;
+                break;
+        }
+
+        mSlot = PK11_GetBestSlot(aMechanism, nullptr);
+
+        if (!mSlot)
+            throw css::uno::RuntimeException("NSS Slot failure",
+                                             
css::uno::Reference<css::uno::XInterface>());
+
+        SECItem aKeyItem;
+        aKeyItem.data = rKey.data();
+        aKeyItem.len = rKey.size();
+
+        mSymKey = ImportSymKey(aMechanism, CKA_SIGN, &aKeyItem);
+        if (!mSymKey)
+            throw css::uno::RuntimeException("NSS SymKey failure",
+                                             
css::uno::Reference<css::uno::XInterface>());
+
+        SECItem param;
+        param.data = nullptr;
+        param.len = 0;
+        mContext = PK11_CreateContextBySymKey(aMechanism, CKA_SIGN, mSymKey, 
&param);
+
+        // Also call digest to begin
+        PK11_DigestBegin(mContext);
+    }
+
+    sal_uInt32 decryptUpdate(std::vector<sal_uInt8>& output, 
std::vector<sal_uInt8>& input,
+                             sal_uInt32 inputLength) override
+    {
+        if (!mContext)
+            return 0;
+        int outputLength = 0;
+        (void)PK11_CipherOp(mContext, output.data(), &outputLength, 
inputLength, input.data(),
+                            inputLength);
+        return outputLength;
+    }
+
+    sal_uInt32 encryptUpdate(std::vector<sal_uInt8>& output, 
std::vector<sal_uInt8>& input,
+                             sal_uInt32 inputLength) override
+    {
+        if (!mContext)
+            return 0;
+        int outputLength = 0;
+        (void)PK11_CipherOp(mContext, output.data(), &outputLength, 
inputLength, input.data(),
+                            inputLength);
+        return outputLength;
+    }
+
+    bool cryptoHashUpdate(std::vector<sal_uInt8>& rInput, sal_uInt32 
nInputLength) override
+    {
+        return PK11_DigestOp(mContext, rInput.data(), nInputLength) == 
SECSuccess;
+    }
+
+    bool cryptoHashFinalize(std::vector<sal_uInt8>& rHash) override
+    {
+        unsigned int nSizeWritten = 0;
+        PK11_DigestFinal(mContext, rHash.data(), &nSizeWritten, rHash.size());
+        return nSizeWritten == rHash.size();
+    }
+};
+
+} // anonymous namespace
+
+std::shared_ptr<ICryptoImplementation> ICryptoImplementation::createInstance()
+{
+    return std::shared_ptr<ICryptoImplementation>(new CryptoImplementationNSS);
+}
+
+} // namespace comphelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/comphelper/source/crypto/Crypto_None.cxx 
b/comphelper/source/crypto/Crypto_None.cxx
new file mode 100644
index 000000000000..b1c2d9712e51
--- /dev/null
+++ b/comphelper/source/crypto/Crypto_None.cxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <comphelper/crypto/Crypto.hxx>
+#include <sal/types.h>
+#include <config_oox.h>
+
+namespace comphelper
+{
+namespace
+{
+class CryptoImplementationNone : public ICryptoImplementation
+{
+public:
+    CryptoImplementationNone() = default;
+
+    virtual ~CryptoImplementationNone() {}
+
+    void setupEncryptContext(std::vector<sal_uInt8>& /*key*/, 
std::vector<sal_uInt8>& /*iv*/,
+                             CryptoType /*eType*/) override
+    {
+    }
+
+    void setupDecryptContext(std::vector<sal_uInt8>& /*key*/, 
std::vector<sal_uInt8>& /*iv*/,
+                             CryptoType /*eType*/) override
+    {
+    }
+
+    void setupCryptoHashContext(std::vector<sal_uInt8>& /*rKey*/, 
CryptoHashType /*eType*/) override
+    {
+    }
+
+    sal_uInt32 decryptUpdate(std::vector<sal_uInt8>& /*output*/, 
std::vector<sal_uInt8>& /*input*/,
+                             sal_uInt32 /*inputLength*/) override
+    {
+        return 0;
+    }
+
+    sal_uInt32 encryptUpdate(std::vector<sal_uInt8>& /*output*/, 
std::vector<sal_uInt8>& /*input*/,
+                             sal_uInt32 /*inputLength*/) override
+    {
+        return 0;
+    }
+
+    bool cryptoHashUpdate(std::vector<sal_uInt8>& /*rInput*/, sal_uInt32 
/*nInputLength*/) override
+    {
+        return false;
+    }
+
+    bool cryptoHashFinalize(std::vector<sal_uInt8>& /*rHash*/) override { 
return false; }
+};
+} // anonymous namespace
+
+std::shared_ptr<ICryptoImplementation> ICryptoImplementation::createInstance()
+{
+    return std::shared_ptr<ICryptoImplementation>(new 
CryptoImplementationNone);
+}
+
+} // namespace comphelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/comphelper/source/crypto/Crypto_OpenSSL.cxx 
b/comphelper/source/crypto/Crypto_OpenSSL.cxx
new file mode 100644
index 000000000000..37c5ff44e222
--- /dev/null
+++ b/comphelper/source/crypto/Crypto_OpenSSL.cxx
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <comphelper/crypto/Crypto.hxx>
+#include <sal/types.h>
+#include <config_oox.h>
+
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+
+namespace comphelper
+{
+namespace
+{
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
+
+static HMAC_CTX* HMAC_CTX_new(void)
+{
+    HMAC_CTX* pContext = new HMAC_CTX;
+    HMAC_CTX_init(pContext);
+    return pContext;
+}
+
+static void HMAC_CTX_free(HMAC_CTX* pContext)
+{
+    HMAC_CTX_cleanup(pContext);
+    delete pContext;
+}
+#endif
+
+namespace
+{
+struct cipher_delete
+{
+    void operator()(EVP_CIPHER_CTX* p) { EVP_CIPHER_CTX_free(p); }
+};
+
+struct hmac_delete
+{
+    SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_CTX_free' is deprecated
+        void
+        operator()(HMAC_CTX* p)
+    {
+        HMAC_CTX_free(p);
+    }
+    SAL_WNODEPRECATED_DECLARATIONS_POP
+};
+}
+
+class CryptoImplementationOpenSSL : public ICryptoImplementation
+{
+    std::unique_ptr<EVP_CIPHER_CTX, cipher_delete> mpContext;
+    std::unique_ptr<HMAC_CTX, hmac_delete> mpHmacContext;
+
+public:
+    CryptoImplementationOpenSSL() = default;
+
+    virtual ~CryptoImplementationOpenSSL()
+    {
+        if (mpContext)
+            EVP_CIPHER_CTX_cleanup(mpContext.get());
+    }
+
+    void setupEncryptContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
+                             CryptoType eType) override
+    {
+        mpContext.reset(EVP_CIPHER_CTX_new());
+        EVP_CIPHER_CTX_init(mpContext.get());
+
+        const EVP_CIPHER* cipher = getCipher(eType);
+        if (cipher == nullptr)
+            return;
+
+        if (iv.empty())
+            EVP_EncryptInit_ex(mpContext.get(), cipher, nullptr, key.data(), 
nullptr);
+        else
+            EVP_EncryptInit_ex(mpContext.get(), cipher, nullptr, key.data(), 
iv.data());
+        EVP_CIPHER_CTX_set_padding(mpContext.get(), 0);
+    }
+
+    void setupDecryptContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
+                             CryptoType eType) override
+    {
+        mpContext.reset(EVP_CIPHER_CTX_new());
+        EVP_CIPHER_CTX_init(mpContext.get());
+
+        const EVP_CIPHER* pCipher = getCipher(eType);
+        if (pCipher == nullptr)
+            return;
+
+        const size_t nMinKeySize = EVP_CIPHER_key_length(pCipher);
+        if (key.size() < nMinKeySize)
+            key.resize(nMinKeySize, 0);
+
+        if (iv.empty())
+            EVP_DecryptInit_ex(mpContext.get(), pCipher, nullptr, key.data(), 
nullptr);
+        else
+        {
+            const size_t nMinIVSize = EVP_CIPHER_iv_length(pCipher);
+            if (iv.size() < nMinIVSize)
+                iv.resize(nMinIVSize, 0);
+
+            EVP_DecryptInit_ex(mpContext.get(), pCipher, nullptr, key.data(), 
iv.data());
+        }
+        EVP_CIPHER_CTX_set_padding(mpContext.get(), 0);
+    }
+
+    void setupCryptoHashContext(std::vector<sal_uInt8>& rKey, CryptoHashType 
eType) override
+    {
+        SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_CTX_new' is deprecated
+            mpHmacContext.reset(HMAC_CTX_new());
+        SAL_WNODEPRECATED_DECLARATIONS_POP
+        const EVP_MD* aEvpMd = nullptr;
+        switch (eType)
+        {
+            case CryptoHashType::SHA1:
+                aEvpMd = EVP_sha1();
+                break;
+            case CryptoHashType::SHA256:
+                aEvpMd = EVP_sha256();
+                break;
+            case CryptoHashType::SHA384:
+                aEvpMd = EVP_sha384();
+                break;
+            case CryptoHashType::SHA512:
+                aEvpMd = EVP_sha512();
+                break;
+        }
+        SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_Init_ex' is deprecated
+            HMAC_Init_ex(mpHmacContext.get(), rKey.data(), rKey.size(), 
aEvpMd, nullptr);
+        SAL_WNODEPRECATED_DECLARATIONS_POP
+    }
+
+    static const EVP_CIPHER* getCipher(CryptoType type)
+    {
+        switch (type)
+        {
+            case CryptoType::AES_128_ECB:
+                return EVP_aes_128_ecb();
+            case CryptoType::AES_256_ECB:
+                return EVP_aes_256_ecb();
+            case CryptoType::AES_128_CBC:
+                return EVP_aes_128_cbc();
+            case CryptoType::AES_256_CBC:
+                return EVP_aes_256_cbc();
+            default:
+                break;
+        }
+        return nullptr;
+    }
+
+    sal_uInt32 decryptUpdate(std::vector<sal_uInt8>& output, 
std::vector<sal_uInt8>& input,
+                             sal_uInt32 inputLength) override
+    {
+        if (!mpContext)
+            return 0;
+        int outputLength = 0;
+        (void)EVP_DecryptUpdate(mpContext.get(), output.data(), &outputLength, 
input.data(),
+                                inputLength);
+        return outputLength;
+    }
+
+    sal_uInt32 encryptUpdate(std::vector<sal_uInt8>& output, 
std::vector<sal_uInt8>& input,
+                             sal_uInt32 inputLength) override
+    {
+        if (!mpContext)
+            return 0;
+        int outputLength = 0;
+        (void)EVP_EncryptUpdate(mpContext.get(), output.data(), &outputLength, 
input.data(),
+                                inputLength);
+        return sal_uInt32(outputLength);
+    }
+
+    bool cryptoHashUpdate(std::vector<sal_uInt8>& rInput, sal_uInt32 
nInputLength) override
+    {
+        SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_Update' is deprecated
+            return HMAC_Update(mpHmacContext.get(), rInput.data(), 
nInputLength)
+            != 0;
+        SAL_WNODEPRECATED_DECLARATIONS_POP
+    }
+
+    bool cryptoHashFinalize(std::vector<sal_uInt8>& rHash) override
+    {
+        unsigned int nSizeWritten = 0;
+        SAL_WNODEPRECATED_DECLARATIONS_PUSH // 'HMAC_Final' is deprecated
+            (void) HMAC_Final(mpHmacContext.get(), rHash.data(), 
&nSizeWritten);
+        SAL_WNODEPRECATED_DECLARATIONS_POP
+        return nSizeWritten == rHash.size();
+    }
+};
+
+} // anonymous namespace
+
+std::shared_ptr<ICryptoImplementation> ICryptoImplementation::createInstance()
+{
+    return std::shared_ptr<ICryptoImplementation>(new 
CryptoImplementationOpenSSL);
+}
+
+} // namespace comphelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/comphelper/crypto/Crypto.hxx 
b/include/comphelper/crypto/Crypto.hxx
index 151ee9d04565..abebf9440a5a 100644
--- a/include/comphelper/crypto/Crypto.hxx
+++ b/include/comphelper/crypto/Crypto.hxx
@@ -50,20 +50,41 @@ enum class CryptoType
     AES_256_CBC,
 };
 
-struct CryptoImpl;
+class ICryptoImplementation
+{
+public:
+    static std::shared_ptr<ICryptoImplementation> createInstance();
+
+    virtual void setupDecryptContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
+                                     CryptoType eType)
+        = 0;
+    virtual void setupEncryptContext(std::vector<sal_uInt8>& key, 
std::vector<sal_uInt8>& iv,
+                                     CryptoType type)
+        = 0;
+    virtual void setupCryptoHashContext(std::vector<sal_uInt8>& rKey, 
CryptoHashType eType) = 0;
+
+    virtual sal_uInt32 decryptUpdate(std::vector<sal_uInt8>& output, 
std::vector<sal_uInt8>& input,
+                                     sal_uInt32 inputLength)
+        = 0;
+    virtual sal_uInt32 encryptUpdate(std::vector<sal_uInt8>& output, 
std::vector<sal_uInt8>& input,
+                                     sal_uInt32 inputLength)
+        = 0;
+    virtual bool cryptoHashUpdate(std::vector<sal_uInt8>& rInput, sal_uInt32 
nInputLength) = 0;
+    virtual bool cryptoHashFinalize(std::vector<sal_uInt8>& rHash) = 0;
+};
 
 class COMPHELPER_DLLPUBLIC Crypto
 {
 protected:
-    std::unique_ptr<CryptoImpl> mpImpl;
+    std::shared_ptr<ICryptoImplementation> mpImpl;
 
-protected:
     Crypto();
 
 public:
     virtual ~Crypto();
 };
 
+/** Decrypt vector of bytes with AES encryption */
 class COMPHELPER_DLLPUBLIC Decrypt final : public Crypto
 {
 public:

Reply via email to