Biblioteca de funciones Hash de C ++ simple

Oct 03 2020

Que había creado biblioteca de funciones de hash ( MD5, MD4, SHA256, SHA384, SHA512, RipeMD128, RipeMD160, CRC16, CRC32, CRC64), escrito en C ++.

Todo funciona bien y Mi biblioteca produce exactamente la misma salida en comparación con la salida de PHP. (Excepto serie CRC)

Las capas de abstracción algorítmica individuales constan de la interfaz chash :: IAlgorithm y chash :: IDigest. Pero me gustaría refinar IDigest de manera más elegante. ¿Cómo puedo hacerlo?

https://github.com/whoamiho1006/chash

IAlgorithm.hpp

#pragma once
#include "Macros.hpp"

namespace chash {
    enum class EAlgorithm {
        Unknown     = 0x0000,
        CRC16       = 0x1000,       // --> IBM Poly-Nomial.
        CRC32       = 0x1001,       // --> IEEE 802.3
        CRC64       = 0x1002,       // --> ISO Poly-Nomial.
        SHA256      = 0x2000,
        SHA384      = 0x2001,
        SHA512      = 0x2002,
        MD5         = 0x3000,
        MD4         = 0x3001,
        RipeMD128   = 0x4000,
        RipeMD160   = 0x4001,
    };

    enum class EAlgorithmErrno {
        Succeed = 0,
        InvalidState,
        InvalidDigest
    };

    class IDigest;
    class IAlgorithm {
    public:
        IAlgorithm(EAlgorithm type)
            : _type(type), _errno(EAlgorithmErrno::Succeed)
        { 
        }

        virtual ~IAlgorithm() { }

    private:
        EAlgorithm _type;
        EAlgorithmErrno _errno;

    protected:
        inline void setError(EAlgorithmErrno _errno) {
            this->_errno = _errno;
        }

    public:
        /* get algorithm type. */
        inline EAlgorithm type() const { return _type; }

        /* get algorithm state. */
        inline EAlgorithmErrno error() const { return _errno; }

        /* create a new digest. */
        virtual IDigest* create() const = 0;

        /* initiate the algorithm. */
        virtual bool init() = 0;

        /* update the algorithm state by given bytes. */
        virtual bool update(const uint8_t* inBytes, size_t inSize) = 0;

        /* finalize the algorithm. */
        virtual bool finalize(IDigest* outDigest) = 0;

        /* compute hash with digest. */
        virtual EAlgorithmErrno compute(IDigest* outDigest, const uint8_t* inBytes, size_t inSize) {
            if (init()) {
                update(inBytes, inSize);
                finalize(outDigest);
                return error();
            }

            return error();
        }
    };

}

IDigest.hpp

#pragma once
#include "Macros.hpp"
#include <string>

namespace chash {
    class IDigest {
    public:
        virtual ~IDigest() { }

    public:
        /* get bytes pointer. */
        virtual uint8_t* bytes() const = 0;

        /* get size in bytes. */
        virtual size_t size() const = 0;

    public:
        inline std::string toHex() {
            std::string outHex;

            uint8_t* bytes = this->bytes();
            size_t size = this->size();

            outHex.reserve(size << 1);
            for (size_t i = 0; i < size; ++i) {
                int32_t b = bytes[i];

                int32_t fr = b / 16;
                int32_t bk = b % 16;

                if (fr < 10) outHex.push_back('0' + fr);
                else outHex.push_back('a' + (fr - 10));

                if (bk < 10) outHex.push_back('0' + bk);
                else outHex.push_back('a' + (bk - 10));
            }

            return outHex;
        }
    };

    /* Digest in template. */
    template<size_t Size>
    class TDigest : public IDigest {
    public:
        TDigest() {
            for (size_t i = 0; i < Size; ++i)
                _bytes[i] = 0;
        }

    private:
        mutable uint8_t _bytes[Size];

    public:
        /* get bytes pointer. */
        virtual uint8_t* bytes() const { return _bytes; }

        /* get size in bytes. */
        virtual size_t size() const { return Size;  }
    };
}

Tengo preguntas de seguimiento basadas en la respuesta de G. Sliepen.

Respuestas

2 G.Sliepen Oct 03 2020 at 22:35

Usa la biblioteca estándar

Pero me gustaría refinar IDigest de manera más elegante. ¿Cómo puedo hacerlo?

IDigestBásicamente, tus reimplementaciones std::vector<uint8_t>. Al darme cuenta de esto, lo eliminaría por completo y lo reemplazaría con std::vector<uint8_t>. Puede agregar esto al espacio de nombres chashsi lo desea:

using Digest = std::vector<uint8_t>;

Su IDigesttiene sus limitaciones: no se puede comparar dos compendios entre sí. Pero puedes con std::vector<uint8_t>. La única característica que tiene su clase es que tiene una función para convertirla en una cadena que contiene caracteres hexadecimales. Dejaría eso por completo, y dejaría que la aplicación implemente lo que necesiten para convertir un resumen en alguna otra forma, si es que lo necesitan. Pero si desea proporcionar esto como una utilidad, simplemente cree una función fuera de su clase para hacer esto:

std::string toHex(const Digest &digest) {
    std::string outHex;
    outHex.reserve(digest.size() * 2);

    for (auto b: digest) {
        ...
    }

    return outHex;
}

Considere si necesita clases base virtuales

¿Realmente necesitas clases base virtuales? Estos tienen un costo: las clases derivadas ahora tendrán una vtable, y las llamadas a funciones deben pasar por un nivel adicional de indirección. Considere usar una clase base no virtual y protectedcree el constructor de la clase base , de modo que ya no pueda crear una instancia de una clase base.