Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/comphelper/source/misc/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 7 kB image not shown  

Quelle  hash.cxx   Sprache: C

 
/* -*- 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 <sal/config.h>

#include <com/sun/star/uno/RuntimeException.hpp>
#include <comphelper/hash.hxx>
#include <rtl/ustring.hxx>
#include <rtl/alloc.h>
#include <osl/endian.h>
#include <config_oox.h>
#include <sstream>
#include <iomanip>

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

namespace comphelper {

std::string hashToString(const std::vector<unsigned char>& rHash)
{
    std::stringstream aStringStream;
    for (auto& i: rHash)
    {
        aStringStream << std::setw(2) << std::setfill('0') << std::hex << int(i);
    }

    return aStringStream.str();
}

struct HashImpl
{

#if USE_TLS_NSS
    HASHContext* mpContext;

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

        return HASH_AlgNULL;
    }
#elif USE_TLS_OPENSSL
    EVP_MD_CTX* mpContext;

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

        return nullptr;
    }
#endif

    HashType const meType;

    HashImpl(HashType eType):
        meType(eType)
    {

#if USE_TLS_NSS
        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)) + ")");
            }
        }
        mpContext = HASH_Create(getNSSType());
#elif USE_TLS_OPENSSL
        mpContext = EVP_MD_CTX_create();
#endif

        initialize();
    }

    void initialize()
    {
#if USE_TLS_NSS
        HASH_Begin(mpContext);
#elif USE_TLS_OPENSSL
        EVP_DigestInit_ex(mpContext, getOpenSSLType(), nullptr);
#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);
#else
    (void)pInput;
    (void)length;
#endif
}

void Hash::initialize()
{
    mpImpl->initialize();
}

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);
#else
    (void)digestWrittenLength;
#endif

    return hash;
}

size_t Hash::getLength() const
{
    switch (mpImpl->meType)
    {
        case HashType::MD5:
            return MD5_HASH_LENGTH;
        case HashType::SHA1:
            return SHA1_HASH_LENGTH;
        case HashType::SHA256:
            return SHA256_HASH_LENGTH;
        case HashType::SHA384:
            return SHA384_HASH_LENGTH;
        case HashType::SHA512:
            return SHA512_HASH_LENGTH;
    }

    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();
}

std::vector<unsigned char> Hash::calculateHash(
        const unsigned char* pInput, size_t nLength,
        const unsigned char* pSalt, size_t nSaltLen,
        sal_uInt32 nSpinCount,
        IterCount eIterCount,
        HashType eType)
{
    if (!pSalt)
        nSaltLen = 0;

    if (!nSaltLen && !nSpinCount)
        return calculateHash( pInput, nLength, eType);

    Hash aHash(eType);
    if (nSaltLen)
    {
        std::vector<unsigned char> initialData( nSaltLen + nLength);
        std::copy( pSalt, pSalt + nSaltLen, initialData.begin());
        std::copy( pInput, pInput + nLength, initialData.begin() + nSaltLen);
        aHash.update( initialData.data(), initialData.size());
        rtl_secureZeroMemory( initialData.data(), initialData.size());
    }
    else
    {
        aHash.update( pInput, nLength);
    }
    std::vector<unsigned char> hash( aHash.finalize());

    if (nSpinCount)
    {
        // https://msdn.microsoft.com/en-us/library/dd920692
        // says the iteration is concatenated after the hash.
        // https://msdn.microsoft.com/en-us/library/dd924776 and
        // https://msdn.microsoft.com/en-us/library/dd925430
        // say the iteration is prepended to the hash.
        const size_t nAddIter = (eIterCount == IterCount::NONE ? 0 : 4);
        const size_t nIterPos = (eIterCount == IterCount::APPEND ? hash.size() : 0);
        const size_t nHashPos = (eIterCount == IterCount::PREPEND ? nAddIter : 0);
        std::vector<unsigned char> data( hash.size() + nAddIter, 0);
        for (sal_uInt32 i = 0; i < nSpinCount; ++i)
        {
            std::copy( hash.begin(), hash.end(), data.begin() + nHashPos);
            if (nAddIter)
            {
#ifdef OSL_BIGENDIAN
                sal_uInt32 be = i;
                sal_uInt8* p = reinterpret_cast<sal_uInt8*>(&be);
                std::swap( p[0], p[3] );
                std::swap( p[1], p[2] );
                memcpy( data.data() + nIterPos, &be, nAddIter);
#else
                memcpy( data.data() + nIterPos, &i, nAddIter);
#endif
            }
            /* TODO: isn't there something better than
             * creating/finalizing/destroying on each iteration? */

            Hash aReHash(eType);
            aReHash.update( data.data(), data.size());
            hash = aReHash.finalize();
        }
    }

    return hash;
}

std::vector<unsigned char> Hash::calculateHash(
        const OUString& rPassword,
        const std::vector<unsigned char>& rSaltValue,
        sal_uInt32 nSpinCount,
        IterCount eIterCount,
        HashType eType)
{
    const unsigned char* pPassBytes = reinterpret_cast<const unsigned char*>(rPassword.getStr());
    const size_t nPassBytesLen = rPassword.getLength() * 2;
#ifdef OSL_BIGENDIAN
    // Swap UTF16-BE to UTF16-LE
    std::vector<unsigned char> vPass;
    if (nPassBytesLen)
    {
        vPass.resize( nPassBytesLen);
        std::copy( pPassBytes, pPassBytes + nPassBytesLen, vPass.begin());
        unsigned char* p = vPass.data();
        unsigned char const * const pEnd = p + nPassBytesLen;
        for ( ; p < pEnd; p += 2 )
        {
            std::swap( p[0], p[1] );
        }
        pPassBytes = vPass.data();
    }
#endif
    return calculateHash( pPassBytes, nPassBytesLen, rSaltValue.data(), rSaltValue.size(), nSpinCount,
            eIterCount, eType);
}

}

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

Messung V0.5
C=94 H=93 G=93

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.