| /** @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; |