add generic digest class

Change-Id: Ic5d2d8fbb0bb4edc4c966e185be81f6ca673950e
Reviewed-on: https://gerrit.libreoffice.org/36790
Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
Tested-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
diff --git a/comphelper/Library_comphelper.mk b/comphelper/Library_comphelper.mk
index 0cdd3f9..03c8a61 100644
--- a/comphelper/Library_comphelper.mk
+++ b/comphelper/Library_comphelper.mk
@@ -43,6 +43,20 @@ $(eval $(call gb_Library_use_externals,comphelper,\
    zlib \
))

ifeq ($(TLS),NSS)
$(eval $(call gb_Library_use_externals,comphelper,\
       plc4 \
       nss3 \
))
else
ifeq ($(TLS),OPENSSL)
$(eval $(call gb_Library_use_externals,comphelper,\
	openssl \
	openssl_headers \
))
endif
endif

$(eval $(call gb_Library_use_libraries,comphelper,\
    cppu \
    cppuhelper \
@@ -91,6 +105,7 @@ $(eval $(call gb_Library_add_exception_objects,comphelper,\
    comphelper/source/misc/evtmethodhelper \
    comphelper/source/misc/fileurl \
    comphelper/source/misc/getexpandeduri \
    comphelper/source/misc/hash \
    comphelper/source/misc/instancelocker \
    comphelper/source/misc/interaction \
    comphelper/source/misc/listenernotification \
diff --git a/comphelper/source/misc/hash.cxx b/comphelper/source/misc/hash.cxx
new file mode 100644
index 0000000..94607f4
--- /dev/null
+++ b/comphelper/source/misc/hash.cxx
@@ -0,0 +1,144 @@
/* -*- 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/hash.hxx>
#include <config_oox.h>

#if USE_TLS_NSS
#include <nss.h>
#include <pk11pub.h>
#include <sechash.h>
#elif USE_TLS_OPENSSL
#include <openssl/evp.h>
#include <openssl/sha.h>
#endif // USE_TLS_OPENSSL

namespace comphelper {

struct HashImpl
{

#if USE_TLS_NSS
    HASHContext* mpContext;

    HASH_HashType getNSSType() const
    {
        switch (meType)
        {
            case HashType::SHA1:
                return HASH_AlgSHA1;
            case HashType::SHA256:
                return HASH_AlgSHA256;
            case HashType::SHA512:
                return HASH_AlgSHA512;
        }

        return HASH_AlgNULL;
    }
#elif USE_TLS_OPENSSL
    EVP_MD_CTX* mpContext;

    EVP_MD* getOpenSSLType() const
    {
        switch (meType)
        {
            case HashType::SHA1:
                return EVP_sha1();
            case HashType::SHA256:
                return EVP_sha256();
            case HashType::SHA512:
                return EVP_sha512();
        }

        return nullptr;
    }
#endif

    HashType meType;

    HashImpl(HashType eType):
        meType(eType)
    {

#if USE_TLS_NSS
        NSS_NoDB_Init(nullptr);
        mpContext = HASH_Create(getNSSType());
        HASH_Begin(mpContext);
#elif USE_TLS_OPENSSL
        mpContext = EVP_MD_CTX_create();
        EVP_DigestInit_ex(mpContext, getOpenSSLType(), NULL);
#endif
    }

    ~HashImpl()
    {
#if USE_TLS_NSS
        HASH_Destroy(mpContext);
#elif USE_TLS_OPENSSL
        EVP_MD_CTX_destroy(mpContext);
#endif
    }
};

Hash::Hash(HashType eType):
    mpImpl(new HashImpl(eType))
{
}

Hash::~Hash()
{
}

void Hash::update(const unsigned char* pInput, size_t length)
{
#if USE_TLS_NSS
    HASH_Update(mpImpl->mpContext, pInput, length);
#elif USE_TLS_OPENSSL
    EVP_DigestUpdate(mpImpl->mpContext, pInput, length);
#endif
}

std::vector<unsigned char> Hash::finalize()
{
    std::vector<unsigned char> hash(getLength(), 0);
    unsigned int digestWrittenLength;
#if USE_TLS_NSS
    HASH_End(mpImpl->mpContext, hash.data(), &digestWrittenLength, getLength());
#elif USE_TLS_OPENSSL
    EVP_DigestFinal_ex(mpImpl->mpContext, hash.data(), &digestWrittenLength);
#endif

    return hash;
}

size_t Hash::getLength() const
{
    switch (mpImpl->meType)
    {
        case HashType::SHA1:
            return 20;
        case HashType::SHA256:
            return 32;
        case HashType::SHA512:
            return 64;
    }

    return 0;
}

std::vector<unsigned char> Hash::calculateHash(const unsigned char* pInput, size_t length, HashType eType)
{
    Hash aHash(eType);
    aHash.update(pInput, length);
    return aHash.finalize();
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/comphelper/hash.hxx b/include/comphelper/hash.hxx
new file mode 100644
index 0000000..c14c6c74
--- /dev/null
+++ b/include/comphelper/hash.hxx
@@ -0,0 +1,47 @@
/* -*- 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/comphelperdllapi.h>

#include <memory>
#include <vector>

namespace comphelper {

enum class HashType
{
    SHA1,
    SHA256,
    SHA512
};

struct HashImpl;

class COMPHELPER_DLLPUBLIC Hash
{
private:
    std::unique_ptr<HashImpl> mpImpl;

public:

    Hash(HashType eType);
    ~Hash();

    void update(const unsigned char* pInput, size_t length);

    std::vector<unsigned char> finalize();

    static std::vector<unsigned char> calculateHash(const unsigned char* pInput, size_t length, HashType eType);

    size_t getLength() const;
};

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */