include/tscore/CryptoHash.h (134 lines of code) (raw):

/** @file Wrapper class for crypto hashes. @section license License Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #pragma once #include "tsutil/ts_bw_format.h" #include "tscore/ink_memory.h" #include <openssl/evp.h> #include <string_view> /// Apache Traffic Server commons. #if TS_ENABLE_FIPS == 1 #define CRYPTO_HASH_SIZE (256 / 8) #else #define CRYPTO_HASH_SIZE (128 / 8) #endif #define CRYPTO_HEX_SIZE ((CRYPTO_HASH_SIZE * 2) + 1) namespace ts { /// Crypto hash output. union CryptoHash { uint64_t b[CRYPTO_HASH_SIZE / sizeof(uint64_t)]; // Legacy placeholder uint64_t u64[CRYPTO_HASH_SIZE / sizeof(uint64_t)]; uint32_t u32[CRYPTO_HASH_SIZE / sizeof(uint32_t)]; uint8_t u8[CRYPTO_HASH_SIZE / sizeof(uint8_t)]; /// Default constructor - init to zero. CryptoHash() { memset(static_cast<void *>(this), 0, sizeof(*this)); } /// Copy constructor. CryptoHash(CryptoHash const &that) = default; /// Assignment - bitwise copy. CryptoHash & operator=(CryptoHash const &that) { if (this != &that) { memcpy(static_cast<void *>(this), &that, sizeof(*this)); } return *this; } /// Equality - bitwise identical. bool operator==(CryptoHash const &that) const { return ::memcmp(this, &that, sizeof(*this)) == 0; } /// Equality - bitwise identical. bool operator!=(CryptoHash const &that) const { return !(*this == that); } /// Reduce to 64 bit value. uint64_t fold() const { #if CRYPTO_HASH_SIZE == 16 return u64[0] ^ u64[1]; #elif CRYPTO_HASH_SIZE == 32 return u64[0] ^ u64[1] ^ u64[2] ^ u64[3]; #endif } /// Access 64 bit slice. uint64_t operator[](int i) const { return u64[i]; } /// Access 64 bit slice. /// @note Identical to @ operator[] but included for symmetry. uint64_t slice64(int i) const { return u64[i]; } /// Access 32 bit slice. uint32_t slice32(int i) const { return u32[i]; } /// Fast conversion to hex in fixed sized string. char *toHexStr(char buffer[(CRYPTO_HASH_SIZE * 2) + 1]) const; bool is_zero() const { constexpr uint8_t z64[sizeof(u64)] = {0}; return ::memcmp(u64, z64, sizeof(z64)) == 0; } void clear() { ink_zero(u64); } }; class CryptoContext { public: /** Protocol class for a crypto hash context. A hash of this type is used for strong hashing, such as for URLs. */ class Hasher { using self_type = Hasher; ///< Self reference type. public: /// Destructor (force virtual) virtual ~Hasher() {} /// Update the hash with @a data of @a length bytes. virtual bool update(void const *data, int length) = 0; /// Finalize and extract the @a hash. virtual bool finalize(CryptoHash &hash) = 0; /// Convenience overload. bool finalize(CryptoHash *hash); protected: EVP_MD_CTX *_ctx = nullptr; }; CryptoContext(); /// Update the hash with @a data of @a length bytes. bool update(void const *data, int length); /// Convenience - compute final @a hash for @a data. /// @note This is just as fast as the previous style, as a new context must be initialized /// every time this is done. bool hash_immediate(CryptoHash &hash, void const *data, int length); /// Finalize and extract the @a hash. bool finalize(CryptoHash &hash); enum HashType { UNSPECIFIED, #if TS_ENABLE_FIPS == 0 MD5, #endif SHA256, }; ///< What type of hash we really are. static HashType Setting; ~CryptoContext(); private: static size_t constexpr OBJ_SIZE = 256; char _base[OBJ_SIZE]; }; inline bool CryptoContext::Hasher::finalize(CryptoHash *hash) { return this->finalize(*hash); } inline bool CryptoContext::update(void const *data, int length) { return reinterpret_cast<Hasher *>(_base)->update(data, length); } inline bool CryptoContext::finalize(CryptoHash &hash) { return reinterpret_cast<Hasher *>(_base)->finalize(hash); } inline bool CryptoContext::hash_immediate(CryptoHash &hash, void const *data, int length) { return this->update(data, length) && this->finalize(hash); } inline CryptoContext::~CryptoContext() { std::destroy_at(reinterpret_cast<Hasher *>(_base)); } swoc::BufferWriter &bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, ts::CryptoHash const &hash); } // namespace ts using ts::CryptoContext; using ts::CryptoHash;