Thư viện hàm băm C ++ đơn giản

Oct 03 2020

Tôi đã tạo ra thư viện hàm băm ( MD5, MD4, SHA256, SHA384, SHA512, RipeMD128, RipeMD160, CRC16, CRC32, CRC64), viết bằng C ++.

Mọi thứ hoạt động tốt và Thư viện của tôi tạo ra cùng một đầu ra so với đầu ra PHP. (Ngoại trừ dòng CRC)

Các lớp trừu tượng thuật toán riêng lẻ bao gồm giao diện chash :: IAlgorithm và chash :: IDigest. Nhưng tôi muốn tinh chỉnh IDigest thanh lịch hơn. Tôi làm nó như thế nào?

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

Tôi có một câu hỏi tiếp theo dựa trên câu trả lời của G. Sliepen.

Trả lời

2 G.Sliepen Oct 03 2020 at 22:35

Sử dụng thư viện chuẩn

Nhưng tôi muốn tinh chỉnh IDigest thanh lịch hơn. Tôi làm nó như thế nào?

Cơ IDigestbản của bạn thực hiện lại std::vector<uint8_t>. Nhận ra điều này, do đó tôi sẽ loại bỏ hoàn toàn và thay thế bằng std::vector<uint8_t>. Bạn có thể thêm cái này vào không gian tên chashnếu bạn muốn:

using Digest = std::vector<uint8_t>;

Của bạn IDigestcó những hạn chế: bạn không thể so sánh hai tiêu chuẩn với nhau. Nhưng bạn có thể với std::vector<uint8_t>. Tính năng duy nhất mà lớp của bạn có là nó có chức năng chuyển nó thành một chuỗi chứa các ký tự thập lục phân. Tôi sẽ loại bỏ điều đó hoàn toàn và để ứng dụng thực hiện bất cứ điều gì họ cần để chuyển đổi một thông báo sang một số dạng khác, nếu họ cần điều đó. Nhưng nếu bạn muốn cung cấp tính năng này dưới dạng một tiện ích, chỉ cần tạo một hàm ngoài lớp để thực hiện việc này:

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

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

    return outHex;
}

Cân nhắc xem bạn có cần các lớp cơ sở ảo không

Bạn có thực sự cần các lớp cơ sở ảo không? Những điều này đi kèm với một chi phí: các lớp dẫn xuất bây giờ sẽ có một vtable và các lệnh gọi hàm cần phải trải qua một mức độ hướng dẫn bổ sung. Hãy xem xét sử dụng một lớp cơ sở không ảo và tạo phương thức khởi tạo của lớp cơ sở protected, vì vậy bạn không thể tạo một thể hiện của lớp cơ sở nữa.