[Libreoffice-commits] core.git: include/oox oox/CppunitTest_oox_crypto.mk oox/qa oox/source

Tomaž Vajngerl tomaz.vajngerl at collabora.co.uk
Fri Jul 6 16:26:43 UTC 2018


 include/oox/crypto/CryptTools.hxx |   90 ++++----
 oox/CppunitTest_oox_crypto.mk     |   15 +
 oox/qa/unit/CryptoTest.cxx        |   65 ++++++
 oox/source/crypto/CryptTools.cxx  |  402 +++++++++++++++++++++++++++-----------
 4 files changed, 413 insertions(+), 159 deletions(-)

New commits:
commit 6db3aeb6e698b07d2fb4985a0c529358b7323f55
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Wed Jul 4 16:25:37 2018 +0200

    CryptoTools: add HMAC, move crypto impl. details to CryptoImpl
    
    Change-Id: I8edb24ee5d9595ef54bd49526b631baf8a7415b1
    Reviewed-on: https://gerrit.libreoffice.org/56970
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/include/oox/crypto/CryptTools.hxx b/include/oox/crypto/CryptTools.hxx
index d5bc5b95bda3..90c60b2a6313 100644
--- a/include/oox/crypto/CryptTools.hxx
+++ b/include/oox/crypto/CryptTools.hxx
@@ -21,26 +21,41 @@
 #define INCLUDED_OOX_CRYPTO_CRYPTTOOLS_HXX
 
 #include <config_oox.h>
-
-#if USE_TLS_OPENSSL
-#include <openssl/evp.h>
-#include <openssl/sha.h>
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
-#include <nss.h>
-#include <pk11pub.h>
-#include <sechash.h>
-#endif // USE_TLS_NSS
+#include <oox/dllapi.h>
+#include <sal/types.h>
 
 #include <vector>
-
-#include <sal/types.h>
+#include <memory>
 
 namespace oox {
 namespace core {
 
-class Crypto
+/** Rounds up the input to the nearest multiple
+ *
+ *  For example:
+ *  input  1, multiple 16 = 16
+ *  input 16, multiple 16 = 16
+ *  input 17, multiple 16 = 32
+ *  input 31, multiple 16 = 32
+ */
+template<typename T>
+T roundUp(T input, T multiple)
+{
+    if (input % multiple == 0)
+        return input;
+    return ((input / multiple) * multiple) + multiple;
+}
+
+enum class CryptoHashType
+{
+    SHA1,
+    SHA256,
+    SHA512
+};
+
+struct CryptoImpl;
+
+class OOX_DLLPUBLIC Crypto
 {
 public:
     enum CryptoType
@@ -52,47 +67,24 @@ public:
     };
 
 protected:
-#if USE_TLS_OPENSSL
-    EVP_CIPHER_CTX mContext;
-#endif
-#if USE_TLS_NSS
-    PK11Context* mContext;
-    SECItem*     mSecParam;
-    PK11SymKey*  mSymKey;
-#endif
-
-#if USE_TLS_OPENSSL
-    const EVP_CIPHER* getCipher(CryptoType type);
-#endif
-#if USE_TLS_NSS
-    void setupContext(
-            std::vector<sal_uInt8>& key,
-            std::vector<sal_uInt8>& iv,
-            CryptoType type,
-            CK_ATTRIBUTE_TYPE operation);
-#endif
+    std::unique_ptr<CryptoImpl> mpImpl;
 
 protected:
     Crypto();
 
 public:
     virtual ~Crypto();
-
-    virtual sal_uInt32 update(
-                    std::vector<sal_uInt8>& output,
-                    std::vector<sal_uInt8>& input,
-                    sal_uInt32 inputLength = 0) = 0;
 };
 
-class Decrypt : public Crypto
+class OOX_DLLPUBLIC Decrypt : public Crypto
 {
 public:
     Decrypt(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, CryptoType type);
 
-    virtual sal_uInt32 update(
+    sal_uInt32 update(
                     std::vector<sal_uInt8>& output,
                     std::vector<sal_uInt8>& input,
-                    sal_uInt32 inputLength = 0) override;
+                    sal_uInt32 inputLength = 0);
 
 
     static sal_uInt32 aes128ecb(
@@ -102,17 +94,27 @@ public:
 
 };
 
-class Encrypt : public Crypto
+class OOX_DLLPUBLIC Encrypt : public Crypto
 {
 public:
     Encrypt(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, CryptoType type);
 
-    virtual sal_uInt32 update(
+    sal_uInt32 update(
                     std::vector<sal_uInt8>& output,
                     std::vector<sal_uInt8>& input,
-                    sal_uInt32 inputLength = 0) override;
+                    sal_uInt32 inputLength = 0);
+};
+
+class OOX_DLLPUBLIC CryptoHash : public Crypto
+{
+    sal_Int32 mnHashSize;
+public:
+    CryptoHash(std::vector<sal_uInt8>& rKey, CryptoHashType eType);
+    bool update(std::vector<sal_uInt8>& rInput, sal_uInt32 nInputLength = 0);
+    std::vector<sal_uInt8> finalize();
 };
 
+
 } // namespace core
 } // namespace oox
 
diff --git a/oox/CppunitTest_oox_crypto.mk b/oox/CppunitTest_oox_crypto.mk
index 64fd4df490b5..f4a641283152 100644
--- a/oox/CppunitTest_oox_crypto.mk
+++ b/oox/CppunitTest_oox_crypto.mk
@@ -16,6 +16,20 @@ $(eval $(call gb_CppunitTest_add_exception_objects,oox_crypto,\
 
 $(eval $(call gb_CppunitTest_use_sdk_api,oox_crypto))
 
+ifeq ($(TLS),OPENSSL)
+$(eval $(call gb_CppunitTest_externals,oox_crypto,\
+	openssl \
+	openssl_headers \
+))
+else
+ifeq ($(TLS),NSS)
+$(eval $(call gb_CppunitTest_use_externals,oox_crypto,\
+       plc4 \
+       nss3 \
+))
+endif
+endif
+
 $(eval $(call gb_CppunitTest_use_libraries,oox_crypto,\
     basegfx \
     comphelper \
@@ -68,6 +82,7 @@ $(eval $(call gb_CppunitTest_use_components,oox_crypto,\
     unotools/util/utl \
     uui/util/uui \
     vcl/vcl.common \
+    sax/source/expatwrap/expwrap \
 ))
 
 
diff --git a/oox/qa/unit/CryptoTest.cxx b/oox/qa/unit/CryptoTest.cxx
index efe3e0cb5d6e..c35fa2f7d9a0 100644
--- a/oox/qa/unit/CryptoTest.cxx
+++ b/oox/qa/unit/CryptoTest.cxx
@@ -15,6 +15,7 @@
 #include <tools/stream.hxx>
 #include <unotools/streamwrap.hxx>
 
+#include <oox/crypto/CryptTools.hxx>
 #include <oox/crypto/Standard2007Engine.hxx>
 #include <oox/helper/binaryinputstream.hxx>
 #include <oox/helper/binaryoutputstream.hxx>
@@ -24,13 +25,77 @@ using namespace css;
 class CryptoTest : public CppUnit::TestFixture
 {
 public:
+    void testCryptoHash();
+    void testRoundUp();
     void testStandard2007();
 
     CPPUNIT_TEST_SUITE(CryptoTest);
+    CPPUNIT_TEST(testCryptoHash);
+    CPPUNIT_TEST(testRoundUp);
     CPPUNIT_TEST(testStandard2007);
     CPPUNIT_TEST_SUITE_END();
 };
 
+namespace
+{
+std::string toString(std::vector<sal_uInt8> const& aInput)
+{
+    std::stringstream aStream;
+    for (auto const& aValue : aInput)
+    {
+        aStream << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(aValue);
+    }
+
+    return aStream.str();
+}
+}
+
+void CryptoTest::testCryptoHash()
+{
+    // Check examples from Wikipedia (https://en.wikipedia.org/wiki/HMAC)
+    OString aContentString("The quick brown fox jumps over the lazy dog");
+    std::vector<sal_uInt8> aContent(aContentString.getStr(),
+                                    aContentString.getStr() + aContentString.getLength());
+    std::vector<sal_uInt8> aKey = { 'k', 'e', 'y' };
+    {
+        oox::core::CryptoHash aCryptoHash(aKey, oox::core::CryptoHashType::SHA1);
+        aCryptoHash.update(aContent);
+        std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
+        CPPUNIT_ASSERT_EQUAL(std::string("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"),
+                             toString(aHash));
+    }
+
+    {
+        oox::core::CryptoHash aCryptoHash(aKey, oox::core::CryptoHashType::SHA256);
+        aCryptoHash.update(aContent);
+        std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
+        CPPUNIT_ASSERT_EQUAL(
+            std::string("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8"),
+            toString(aHash));
+    }
+
+    {
+        oox::core::CryptoHash aCryptoHash(aKey, oox::core::CryptoHashType::SHA512);
+        aCryptoHash.update(aContent);
+        std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
+        CPPUNIT_ASSERT_EQUAL(
+            std::string("b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549"
+                        "f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a"),
+            toString(aHash));
+    }
+}
+
+void CryptoTest::testRoundUp()
+{
+    CPPUNIT_ASSERT_EQUAL(16, oox::core::roundUp(16, 16));
+    CPPUNIT_ASSERT_EQUAL(32, oox::core::roundUp(32, 16));
+    CPPUNIT_ASSERT_EQUAL(64, oox::core::roundUp(64, 16));
+
+    CPPUNIT_ASSERT_EQUAL(16, oox::core::roundUp(01, 16));
+    CPPUNIT_ASSERT_EQUAL(32, oox::core::roundUp(17, 16));
+    CPPUNIT_ASSERT_EQUAL(32, oox::core::roundUp(31, 16));
+}
+
 void CryptoTest::testStandard2007()
 {
     oox::core::Standard2007Engine aEngine;
diff --git a/oox/source/crypto/CryptTools.cxx b/oox/source/crypto/CryptTools.cxx
index e0b39f67cca4..1f280b1c1196 100644
--- a/oox/source/crypto/CryptTools.cxx
+++ b/oox/source/crypto/CryptTools.cxx
@@ -12,105 +12,243 @@
 #include <filter/msfilter/mscodec.hxx>
 #include <com/sun/star/uno/RuntimeException.hpp>
 
-namespace oox {
-namespace core {
+#include <o3tl/make_unique.hxx>
+
+#if USE_TLS_OPENSSL
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#endif // USE_TLS_OPENSSL
 
-Crypto::Crypto()
-#if USE_TLS_NSS
-    : mContext(nullptr)
-    , mSecParam(nullptr)
-    , mSymKey(nullptr)
-#endif
-{
 #if USE_TLS_NSS
-    // Initialize NSS, database functions are not needed
-    NSS_NoDB_Init(nullptr);
+#include <nss.h>
+#include <pk11pub.h>
+#include <sechash.h>
 #endif // USE_TLS_NSS
-}
 
-Crypto::~Crypto()
-{
-#if USE_TLS_OPENSSL
-    EVP_CIPHER_CTX_cleanup( &mContext );
-#endif
-#if USE_TLS_NSS
-    if (mContext)
-        PK11_DestroyContext(mContext, PR_TRUE);
-    if (mSymKey)
-        PK11_FreeSymKey(mSymKey);
-    if (mSecParam)
-        SECITEM_FreeItem(mSecParam, PR_TRUE);
-#endif
-}
+namespace oox {
+namespace core {
 
 #if USE_TLS_OPENSSL
-const EVP_CIPHER* Crypto::getCipher(CryptoType type)
+struct CryptoImpl
 {
-    switch(type)
+    std::unique_ptr<EVP_CIPHER_CTX> mpContext;
+    std::unique_ptr<HMAC_CTX> mpHmacContext;
+
+    CryptoImpl() = default;
+
+    void setupEncryptContext(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, Crypto::CryptoType eType)
     {
-        case AES_128_ECB:
-            return EVP_aes_128_ecb();
-        case AES_128_CBC:
-            return EVP_aes_128_cbc();
-        case AES_256_CBC:
-            return EVP_aes_256_cbc();
-        default:
-            break;
+        mpContext.reset(new EVP_CIPHER_CTX);
+        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(), 0);
+        else
+            EVP_EncryptInit_ex(mpContext.get(), cipher, nullptr, key.data(), iv.data());
+        EVP_CIPHER_CTX_set_padding(mpContext.get(), 0);
     }
-    return NULL;
-}
-#endif
 
-#if USE_TLS_NSS
-void Crypto::setupContext(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);
+    void setupDecryptContext(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, Crypto::CryptoType eType)
+    {
+        mpContext.reset(new EVP_CIPHER_CTX);
+        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(), 0);
+        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);
+    }
 
-    SECItem ivItem;
-    ivItem.type = siBuffer;
-    if(iv.empty())
-        ivItem.data = nullptr;
-    else
-        ivItem.data = iv.data();
-    ivItem.len = iv.size();
+    void setupCryptoHashContext(std::vector<sal_uInt8>& rKey, CryptoHashType eType)
+    {
+        mpHmacContext.reset(new HMAC_CTX);
+        HMAC_CTX_init(mpHmacContext.get());
+        const EVP_MD* aEvpMd;
+        switch (eType)
+        {
+            case CryptoHashType::SHA1:
+                aEvpMd = EVP_sha1(); break;
+            case CryptoHashType::SHA256:
+                aEvpMd = EVP_sha256(); break;
+            case CryptoHashType::SHA512:
+                aEvpMd = EVP_sha512(); break;
+        }
+        HMAC_Init(mpHmacContext.get(), rKey.data(), rKey.size(), aEvpMd);
+    }
 
-    SECItem* pIvItem = nullptr;
+    ~CryptoImpl()
+    {
+        if (mpContext)
+            EVP_CIPHER_CTX_cleanup(mpContext.get());
+        if (mpHmacContext)
+            HMAC_CTX_cleanup(mpHmacContext.get());
+    }
 
-    switch(type)
+    const EVP_CIPHER* getCipher(Crypto::CryptoType type)
     {
-        case AES_128_ECB:
-            mechanism = CKM_AES_ECB;
-            break;
-        case AES_128_CBC:
-            mechanism = CKM_AES_CBC;
-            pIvItem = &ivItem;
-            break;
-        case AES_256_CBC:
-            mechanism = CKM_AES_CBC;
-            pIvItem = &ivItem;
-            break;
-        default:
-            break;
+        switch(type)
+        {
+            case Crypto::CryptoType::AES_128_ECB:
+                return EVP_aes_128_ecb();
+            case Crypto::CryptoType::AES_128_CBC:
+                return EVP_aes_128_cbc();
+            case Crypto::CryptoType::AES_256_CBC:
+                return EVP_aes_256_cbc();
+            default:
+                break;
+        }
+        return nullptr;
     }
+};
 
-    PK11SlotInfo* pSlot(PK11_GetBestSlot(mechanism, nullptr));
+#elif USE_TLS_NSS
 
-    if (!pSlot)
-        throw css::uno::RuntimeException("NSS Slot failure", css::uno::Reference<css::uno::XInterface>());
+struct CryptoImpl
+{
+    PK11Context* mContext;
+    SECItem*     mSecParam;
+    PK11SymKey*  mSymKey;
+    PK11SlotInfo* mpSlot;
+
+    CryptoImpl()
+        : mContext(nullptr)
+        , mSecParam(nullptr)
+        , mSymKey(nullptr)
+    {
+        // Initialize NSS, database functions are not needed
+        NSS_NoDB_Init(nullptr);
+    }
 
-    SECItem keyItem;
-    keyItem.type = siBuffer;
-    keyItem.data = key.data();
-    keyItem.len  = key.size();
+    ~CryptoImpl()
+    {
+        if (mContext)
+            PK11_DestroyContext(mContext, PR_TRUE);
+        if (mSymKey)
+            PK11_FreeSymKey(mSymKey);
+        if (mSecParam)
+            SECITEM_FreeItem(mSecParam, PR_TRUE);
+        if (mpSlot)
+            PK11_FreeSlot(mpSlot);
+    }
 
-    mSymKey = PK11_ImportSymKey(pSlot, mechanism, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr);
-    if (!mSymKey)
-        throw css::uno::RuntimeException("NSS SymKey failure", css::uno::Reference<css::uno::XInterface>());
+    void setupCryptoContext(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, Crypto::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 Crypto::CryptoType::AES_128_ECB:
+                mechanism = CKM_AES_ECB;
+                break;
+            case Crypto::CryptoType::AES_128_CBC:
+                mechanism = CKM_AES_CBC;
+                pIvItem = &ivItem;
+                break;
+            case Crypto::CryptoType::AES_256_CBC:
+                mechanism = CKM_AES_CBC;
+                pIvItem = &ivItem;
+                break;
+            default:
+                break;
+        }
+
+        mpSlot = PK11_GetBestSlot(mechanism, nullptr);
+
+        if (!mpSlot)
+            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 = PK11_ImportSymKey(mpSlot, mechanism, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr);
+        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);
+    }
 
-    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::SHA512:
+                aMechanism = CKM_SHA512_HMAC;
+                break;
+        }
+
+        mpSlot = PK11_GetBestSlot(aMechanism, nullptr);
+
+        if (!mpSlot)
+            throw css::uno::RuntimeException("NSS Slot failure", css::uno::Reference<css::uno::XInterface>());
+
+        SECItem aKeyItem;
+        aKeyItem.data = rKey.data();
+        aKeyItem.len  = rKey.size();
+
+        mSymKey = PK11_ImportSymKey(mpSlot, aMechanism, PK11_OriginUnwrap, CKA_SIGN, &aKeyItem, nullptr);
+        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(o3tl::make_unique<CryptoImpl>())
+{
+}
+
+Crypto::~Crypto()
+{
 }
-#endif // USE_TLS_NSS
 
 // DECRYPT
 
@@ -124,29 +262,11 @@ Decrypt::Decrypt(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, Crypto
 #endif
 
 #if USE_TLS_OPENSSL
-    EVP_CIPHER_CTX_init(&mContext);
-
-    const EVP_CIPHER* cipher = getCipher(type);
-
-    const size_t nMinKeySize = EVP_CIPHER_key_length(cipher);
-    if (key.size() < nMinKeySize)
-        key.resize(nMinKeySize, 0);
-
-    if (iv.empty())
-        EVP_DecryptInit_ex(&mContext, cipher, nullptr, key.data(), 0);
-    else
-    {
-        const size_t nMinIVSize = EVP_CIPHER_iv_length(cipher);
-        if (iv.size() < nMinIVSize)
-            iv.resize(nMinIVSize, 0);
-
-        EVP_DecryptInit_ex(&mContext, cipher, nullptr, key.data(), iv.data());
-    }
-    EVP_CIPHER_CTX_set_padding(&mContext, 0);
+    mpImpl->setupDecryptContext(key, iv, type);
 #endif
 
 #if USE_TLS_NSS
-    setupContext(key, iv, type, CKA_DECRYPT);
+    mpImpl->setupCryptoContext(key, iv, type, CKA_DECRYPT);
 #endif // USE_TLS_NSS
 }
 
@@ -163,11 +283,11 @@ sal_uInt32 Decrypt::update(std::vector<sal_uInt8>& output, std::vector<sal_uInt8
 #endif
 
 #if USE_TLS_OPENSSL
-    (void)EVP_DecryptUpdate(&mContext, output.data(), &outputLength, input.data(), actualInputLength);
+    (void)EVP_DecryptUpdate(mpImpl->mpContext.get(), output.data(), &outputLength, input.data(), actualInputLength);
 #endif // USE_TLS_OPENSSL
 
 #if USE_TLS_NSS
-    (void)PK11_CipherOp( mContext, output.data(), &outputLength, actualInputLength, input.data(), actualInputLength );
+    (void)PK11_CipherOp(mpImpl->mContext, output.data(), &outputLength, actualInputLength, input.data(), actualInputLength);
 #endif // USE_TLS_NSS
 
     return static_cast<sal_uInt32>(outputLength);
@@ -194,19 +314,9 @@ Encrypt::Encrypt(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, Crypto
 #endif
 
 #if USE_TLS_OPENSSL
-    EVP_CIPHER_CTX_init(&mContext);
-
-    const EVP_CIPHER* cipher = getCipher(type);
-
-    if (iv.empty())
-        EVP_EncryptInit_ex(&mContext, cipher, nullptr, key.data(), 0);
-    else
-        EVP_EncryptInit_ex(&mContext, cipher, nullptr, key.data(), iv.data());
-    EVP_CIPHER_CTX_set_padding(&mContext, 0);
-#endif
-
-#if USE_TLS_NSS
-    setupContext(key, iv, type, CKA_ENCRYPT);
+    mpImpl->setupEncryptContext(key, iv, type);
+#elif USE_TLS_NSS
+    mpImpl->setupCryptoContext(key, iv, type, CKA_ENCRYPT);
 #endif // USE_TLS_NSS
 }
 
@@ -223,16 +333,78 @@ sal_uInt32 Encrypt::update(std::vector<sal_uInt8>& output, std::vector<sal_uInt8
 #endif
 
 #if USE_TLS_OPENSSL
-    (void)EVP_EncryptUpdate(&mContext, output.data(), &outputLength, input.data(), actualInputLength);
+    (void)EVP_EncryptUpdate(mpImpl->mpContext.get(), output.data(), &outputLength, input.data(), actualInputLength);
 #endif // USE_TLS_OPENSSL
 
 #if USE_TLS_NSS
-    (void)PK11_CipherOp(mContext, output.data(), &outputLength, actualInputLength, input.data(), actualInputLength);
+    (void)PK11_CipherOp(mpImpl->mContext, output.data(), &outputLength, actualInputLength, input.data(), actualInputLength);
 #endif // USE_TLS_NSS
 
     return static_cast<sal_uInt32>(outputLength);
 }
 
+// CryptoHash - HMAC
+
+namespace
+{
+
+sal_Int32 getSizeForHashType(CryptoHashType eType)
+{
+    switch (eType)
+    {
+        case CryptoHashType::SHA1: return 20;
+        case CryptoHashType::SHA256: return 32;
+        case CryptoHashType::SHA512: return 64;
+    }
+    return 0;
+}
+
+} // end anonymous namespace
+
+CryptoHash::CryptoHash(std::vector<sal_uInt8>& rKey, CryptoHashType eType)
+    : Crypto()
+    , mnHashSize(getSizeForHashType(eType))
+{
+#if USE_TLS_OPENSSL
+    mpImpl->setupCryptoHashContext(rKey, eType);
+#elif USE_TLS_NSS
+    mpImpl->setupCryptoHashContext(rKey, eType);
+    PK11_DigestBegin(mpImpl->mContext);
+#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)input;
+    (void)inputLength;
+#endif
+
+#if USE_TLS_OPENSSL
+    return HMAC_Update(mpImpl->mpHmacContext.get(), rInput.data(), nActualInputLength) != 0;
+#elif USE_TLS_NSS
+    return PK11_DigestOp(mpImpl->mContext, rInput.data(), nActualInputLength) == SECSuccess;
+#endif
+}
+
+std::vector<sal_uInt8> CryptoHash::finalize()
+{
+    std::vector<sal_uInt8> aHash(mnHashSize, 0);
+    unsigned int nSizeWritten;
+#if USE_TLS_OPENSSL
+    (void) HMAC_Final(mpImpl->mpHmacContext.get(), aHash.data(), &nSizeWritten) != 0;
+#elif USE_TLS_NSS
+    PK11_DigestFinal(mpImpl->mContext, aHash.data(), &nSizeWritten, aHash.size());
+#endif
+    (void)nSizeWritten;
+
+    return aHash;
+}
+
 } // namespace core
 } // namespace oox
 


More information about the Libreoffice-commits mailing list