Coverage Report

Created: 2026-05-21 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/include/tscore/CryptoHash.h
Line
Count
Source
1
/** @file
2
    Wrapper class for crypto hashes.
3
4
    @section license License
5
6
    Licensed to the Apache Software Foundation (ASF) under one
7
    or more contributor license agreements.  See the NOTICE file
8
    distributed with this work for additional information
9
    regarding copyright ownership.  The ASF licenses this file
10
    to you under the Apache License, Version 2.0 (the
11
    "License"); you may not use this file except in compliance
12
    with the License.  You may obtain a copy of the License at
13
14
    http://www.apache.org/licenses/LICENSE-2.0
15
16
    Unless required by applicable law or agreed to in writing, software
17
    distributed under the License is distributed on an "AS IS" BASIS,
18
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
    See the License for the specific language governing permissions and
20
    limitations under the License.
21
 */
22
23
#pragma once
24
25
#include "tsutil/ts_bw_format.h"
26
#include "tscore/ink_memory.h"
27
#include <openssl/evp.h>
28
#include <string_view>
29
30
/// Apache Traffic Server commons.
31
32
#if TS_ENABLE_FIPS == 1
33
#define CRYPTO_HASH_SIZE (256 / 8)
34
#else
35
0
#define CRYPTO_HASH_SIZE (128 / 8)
36
#endif
37
#define CRYPTO_HEX_SIZE ((CRYPTO_HASH_SIZE * 2) + 1)
38
39
namespace ts
40
{
41
/// Crypto hash output.
42
union CryptoHash {
43
  uint64_t b[CRYPTO_HASH_SIZE / sizeof(uint64_t)]; // Legacy placeholder
44
  uint64_t u64[CRYPTO_HASH_SIZE / sizeof(uint64_t)];
45
  uint32_t u32[CRYPTO_HASH_SIZE / sizeof(uint32_t)];
46
  uint8_t  u8[CRYPTO_HASH_SIZE / sizeof(uint8_t)];
47
48
  /// Default constructor - init to zero.
49
0
  CryptoHash() { memset(static_cast<void *>(this), 0, sizeof(*this)); }
50
  /// Copy constructor.
51
  CryptoHash(CryptoHash const &that) = default;
52
53
  /// Assignment - bitwise copy.
54
  CryptoHash &
55
  operator=(CryptoHash const &that)
56
0
  {
57
0
    if (this != &that) {
58
0
      memcpy(static_cast<void *>(this), &that, sizeof(*this));
59
0
    }
60
0
    return *this;
61
0
  }
62
63
  /// Equality - bitwise identical.
64
  bool
65
  operator==(CryptoHash const &that) const
66
0
  {
67
0
    return ::memcmp(this, &that, sizeof(*this)) == 0;
68
0
  }
69
70
  /// Equality - bitwise identical.
71
  bool
72
  operator!=(CryptoHash const &that) const
73
0
  {
74
0
    return !(*this == that);
75
0
  }
76
77
  /// Reduce to 64 bit value.
78
  uint64_t
79
  fold() const
80
0
  {
81
0
#if CRYPTO_HASH_SIZE == 16
82
0
    return u64[0] ^ u64[1];
83
0
#elif CRYPTO_HASH_SIZE == 32
84
0
    return u64[0] ^ u64[1] ^ u64[2] ^ u64[3];
85
0
#endif
86
0
  }
87
88
  /// Access 64 bit slice.
89
  uint64_t
90
  operator[](int i) const
91
0
  {
92
0
    return u64[i];
93
0
  }
94
95
  /// Access 64 bit slice.
96
  /// @note Identical to @ operator[] but included for symmetry.
97
  uint64_t
98
  slice64(int i) const
99
0
  {
100
0
    return u64[i];
101
0
  }
102
103
  /// Access 32 bit slice.
104
  uint32_t
105
  slice32(int i) const
106
0
  {
107
0
    return u32[i];
108
0
  }
109
110
  /// Fast conversion to hex in fixed sized string.
111
  char *toHexStr(char buffer[(CRYPTO_HASH_SIZE * 2) + 1]) const;
112
113
  bool
114
  is_zero() const
115
0
  {
116
0
    constexpr uint8_t z64[sizeof(u64)] = {0};
117
0
    return ::memcmp(u64, z64, sizeof(z64)) == 0;
118
0
  }
119
120
  void
121
  clear()
122
0
  {
123
0
    ink_zero(u64);
124
0
  }
125
};
126
127
class CryptoContext
128
{
129
public:
130
  /** Protocol class for a crypto hash context.
131
132
     A hash of this type is used for strong hashing, such as for URLs.
133
   */
134
  class Hasher
135
  {
136
    using self_type = Hasher; ///< Self reference type.
137
  public:
138
    /// Destructor (force virtual)
139
0
    virtual ~Hasher() {}
140
    /// Update the hash with @a data of @a length bytes.
141
    virtual bool update(void const *data, int length) = 0;
142
    /// Finalize and extract the @a hash.
143
    virtual bool finalize(CryptoHash &hash) = 0;
144
145
    /// Convenience overload.
146
    bool finalize(CryptoHash *hash);
147
148
  protected:
149
    EVP_MD_CTX *_ctx = nullptr;
150
  };
151
152
  CryptoContext();
153
154
  /// Update the hash with @a data of @a length bytes.
155
  bool update(void const *data, int length);
156
157
  /// Convenience - compute final @a hash for @a data.
158
  /// @note This is just as fast as the previous style, as a new context must be initialized
159
  /// every time this is done.
160
  bool hash_immediate(CryptoHash &hash, void const *data, int length);
161
162
  /// Finalize and extract the @a hash.
163
  bool finalize(CryptoHash &hash);
164
165
  enum HashType {
166
    UNSPECIFIED,
167
#if TS_ENABLE_FIPS == 0
168
    MD5,
169
#endif
170
    SHA256,
171
  }; ///< What type of hash we really are.
172
  static HashType Setting;
173
174
  ~CryptoContext();
175
176
private:
177
  static size_t constexpr OBJ_SIZE = 256;
178
  char _base[OBJ_SIZE];
179
};
180
181
inline bool
182
CryptoContext::Hasher::finalize(CryptoHash *hash)
183
0
{
184
0
  return this->finalize(*hash);
185
0
}
186
187
inline bool
188
CryptoContext::update(void const *data, int length)
189
0
{
190
0
  return reinterpret_cast<Hasher *>(_base)->update(data, length);
191
0
}
192
193
inline bool
194
CryptoContext::finalize(CryptoHash &hash)
195
0
{
196
0
  return reinterpret_cast<Hasher *>(_base)->finalize(hash);
197
0
}
198
199
inline bool
200
CryptoContext::hash_immediate(CryptoHash &hash, void const *data, int length)
201
0
{
202
0
  return this->update(data, length) && this->finalize(hash);
203
0
}
204
205
inline CryptoContext::~CryptoContext()
206
0
{
207
0
  std::destroy_at(reinterpret_cast<Hasher *>(_base));
208
0
}
209
210
swoc::BufferWriter &bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, ts::CryptoHash const &hash);
211
212
} // namespace ts
213
214
using ts::CryptoContext;
215
using ts::CryptoHash;