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 "tscore/BufferWriter.h"
26 #include <string_view>
27
28 /// Apache Traffic Server commons.
29
30 #if TS_ENABLE_FIPS == 1
31 #define CRYPTO_HASH_SIZE (256 / 8)
32 #else
33 #define CRYPTO_HASH_SIZE (128 / 8)
34 #endif
35 #define CRYPTO_HEX_SIZE ((CRYPTO_HASH_SIZE * 2) + 1)
36
37 namespace ats
38 {
39 /// Crypto hash output.
40 union CryptoHash {
41 uint64_t b[CRYPTO_HASH_SIZE / sizeof(uint64_t)]; // Legacy placeholder
42 uint64_t u64[CRYPTO_HASH_SIZE / sizeof(uint64_t)];
43 uint32_t u32[CRYPTO_HASH_SIZE / sizeof(uint32_t)];
44 uint8_t u8[CRYPTO_HASH_SIZE / sizeof(uint8_t)];
45
46 /// Default constructor - init to zero.
CryptoHash()47 CryptoHash() { memset(this, 0, sizeof(*this)); }
48 /// Copy constructor.
49 CryptoHash(CryptoHash const &that) = default;
50
51 /// Assignment - bitwise copy.
52 CryptoHash &
53 operator=(CryptoHash const &that)
54 {
55 if (this != &that) {
56 memcpy(this, &that, sizeof(*this));
57 }
58 return *this;
59 }
60
61 /// Equality - bitwise identical.
62 bool
63 operator==(CryptoHash const &that) const
64 {
65 return memcmp(this, &that, sizeof(*this)) == 0;
66 }
67
68 /// Equality - bitwise identical.
69 bool
70 operator!=(CryptoHash const &that) const
71 {
72 return !(*this == that);
73 }
74
75 /// Reduce to 64 bit value.
76 uint64_t
fold()77 fold() const
78 {
79 #if CRYPTO_HASH_SIZE == 16
80 return u64[0] ^ u64[1];
81 #elif CRYPTO_HASH_SIZE == 32
82 return u64[0] ^ u64[1] ^ u64[2] ^ u64[3];
83 #endif
84 }
85
86 /// Access 64 bit slice.
87 uint64_t
88 operator[](int i) const
89 {
90 return u64[i];
91 }
92 /// Access 64 bit slice.
93 /// @note Identical to @ operator[] but included for symmetry.
94 uint64_t
slice64(int i)95 slice64(int i) const
96 {
97 return u64[i];
98 }
99
100 /// Access 32 bit slice.
101 uint32_t
slice32(int i)102 slice32(int i) const
103 {
104 return u32[i];
105 }
106
107 /// Fast conversion to hex in fixed sized string.
108 char *toHexStr(char buffer[(CRYPTO_HASH_SIZE * 2) + 1]) const;
109 };
110
111 extern CryptoHash const CRYPTO_HASH_ZERO;
112
113 /** Protocol class for a crypto hash context.
114
115 A hash of this type is used for strong hashing, such as for URLs.
116 */
117 class CryptoContextBase
118 {
119 typedef CryptoContextBase self; ///< Self reference type.
120 public:
121 /// Destructor (force virtual)
~CryptoContextBase()122 virtual ~CryptoContextBase() {}
123 /// Update the hash with @a data of @a length bytes.
124 virtual bool update(void const *data, int length) = 0;
125 /// Finalize and extract the @a hash.
126 virtual bool finalize(CryptoHash &hash) = 0;
127
128 /// Convenience overload.
129 bool finalize(CryptoHash *hash);
130
131 /// Convenience - compute final @a hash for @a data.
132 /// @note This is just as fast as the previous style, as a new context must be initialized
133 /// every time this is done.
134 bool hash_immediate(CryptoHash &hash, void const *data, int length);
135 };
136
137 inline bool
hash_immediate(CryptoHash & hash,void const * data,int length)138 CryptoContextBase::hash_immediate(CryptoHash &hash, void const *data, int length)
139 {
140 return this->update(data, length) && this->finalize(hash);
141 }
142
143 inline bool
finalize(CryptoHash * hash)144 CryptoContextBase::finalize(CryptoHash *hash)
145 {
146 return this->finalize(*hash);
147 }
148
149 class CryptoContext : public CryptoContextBase
150 {
151 public:
152 CryptoContext();
153 /// Update the hash with @a data of @a length bytes.
154 bool update(void const *data, int length) override;
155 /// Finalize and extract the @a hash.
156 bool finalize(CryptoHash &hash) override;
157
158 enum HashType {
159 UNSPECIFIED,
160 #if TS_ENABLE_FIPS == 0
161 MD5,
162 MMH,
163 #endif
164 SHA256,
165 }; ///< What type of hash we really are.
166 static HashType Setting;
167
168 /// Size of storage for placement @c new of hashing context.
169 static size_t const OBJ_SIZE = 256;
170
171 protected:
172 char _obj[OBJ_SIZE]; ///< Raw storage for instantiated context.
173 };
174
175 inline bool
update(void const * data,int length)176 CryptoContext::update(void const *data, int length)
177 {
178 return reinterpret_cast<CryptoContextBase *>(_obj)->update(data, length);
179 }
180
181 inline bool
finalize(CryptoHash & hash)182 CryptoContext::finalize(CryptoHash &hash)
183 {
184 return reinterpret_cast<CryptoContextBase *>(_obj)->finalize(hash);
185 }
186
187 ts::BufferWriter &bwformat(ts::BufferWriter &w, ts::BWFSpec const &spec, ats::CryptoHash const &hash);
188
189 } // namespace ats
190
191 using ats::CryptoHash;
192 using ats::CryptoContext;
193 using ats::CRYPTO_HASH_ZERO;
194