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