1 // Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef OPENSSL_HEADER_CRYPTO_FIPSMODULE_DIGEST_MD32_COMMON_H
16 #define OPENSSL_HEADER_CRYPTO_FIPSMODULE_DIGEST_MD32_COMMON_H
17 
18 #include <openssl/base.h>
19 #include <openssl/span.h>
20 
21 #include <assert.h>
22 
23 #include "../../internal.h"
24 
25 BSSL_NAMESPACE_BEGIN
26 
27 
28 // This is a generic 32-bit "collector" for message digest algorithms. It
29 // collects input character stream into chunks of 32-bit values and invokes the
30 // block function that performs the actual hash calculations.
31 //
32 // To make use of this mechanism, the hash context should be defined with the
33 // following parameters.
34 //
35 //     typedef struct <name>_state_st {
36 //       uint32_t h[<chaining length> / sizeof(uint32_t)];
37 //       uint32_t Nl, Nh;
38 //       uint8_t data[<block size>];
39 //       unsigned num;
40 //       ...
41 //     } <NAME>_CTX;
42 //
43 // <chaining length> is the output length of the hash in bytes, before
44 // any truncation (e.g. 64 for SHA-224 and SHA-256, 128 for SHA-384 and
45 // SHA-512).
46 //
47 // |h| is the hash state and is updated by a function of type
48 // |crypto_md32_block_func|. |data| is the partial unprocessed block and has
49 // |num| bytes. |Nl| and |Nh| maintain the number of bits processed so far.
50 //
51 // The template parameter is then a traits struct defined as follows:
52 //
53 //     struct HashTraits {
54 //       // HashContext is the hash type defined above.
55 //       using HashContext = <NAME>_CTX;
56 //
57 //       // kBlockSize is the block size of the hash function.
58 //       static constexpr size_t kBlockSize = <block size>;
59 //
60 //       // kLengthIsBigEndian determines whether the final length is encoded in
61 //       // big or little endian.
62 //       static constexpr bool kLengthIsBigEndian = ...;
63 //
64 //       // HashBlocks incorporates |num_blocks| blocks of input from |data|
65 //       // into |state|. It is assumed the caller has sized |state| and |data|
66 //       // for the hash function.
67 //       static void HashBlocks(uint32_t *state, const uint8_t *data,
68 //                              size_t num_blocks) {
69 //         <name>_block_data_order(state, data, num_blocks);
70 //       }
71 //     };
72 //
73 // The reason for this formulation is to encourage the compiler to specialize
74 // all the code for the block size and block function.
75 
76 // crypto_md32_update hashes |in| to |ctx|.
77 template <typename Traits>
crypto_md32_update(typename Traits::HashContext * ctx,Span<const uint8_t> in)78 inline void crypto_md32_update(typename Traits::HashContext *ctx,
79                                Span<const uint8_t> in) {
80   static_assert(Traits::kBlockSize == sizeof(ctx->data), "block size is wrong");
81   if (in.empty()) {
82     return;
83   }
84 
85   uint32_t l = ctx->Nl + ((static_cast<uint32_t>(in.size())) << 3);
86   if (l < ctx->Nl) {
87     // Handle carries.
88     ctx->Nh++;
89   }
90   ctx->Nh += static_cast<uint32_t>(in.size() >> 29);
91   ctx->Nl = l;
92 
93   size_t n = ctx->num;
94   if (n != 0) {
95     if (in.size() >= Traits::kBlockSize ||
96         in.size() + n >= Traits::kBlockSize) {
97       OPENSSL_memcpy(ctx->data + n, in.data(), Traits::kBlockSize - n);
98       Traits::HashBlocks(ctx->h, ctx->data, 1);
99       in = in.subspan(Traits::kBlockSize - n);
100       ctx->num = 0;
101       // Keep |data| zeroed when unused.
102       OPENSSL_memset(ctx->data, 0, Traits::kBlockSize);
103     } else {
104       OPENSSL_memcpy(ctx->data + n, in.data(), in.size());
105       ctx->num += static_cast<unsigned>(in.size());
106       return;
107     }
108   }
109 
110   n = in.size() / Traits::kBlockSize;
111   if (n > 0) {
112     Traits::HashBlocks(ctx->h, in.data(), n);
113     in = in.subspan(n * Traits::kBlockSize);
114   }
115 
116   if (!in.empty()) {
117     ctx->num = static_cast<unsigned>(in.size());
118     OPENSSL_memcpy(ctx->data, in.data(), in.size());
119   }
120 }
121 
122 // crypto_md32_final incorporates the partial block and trailing length into the
123 // digest state in |ctx|. The trailing length is encoded in little-endian if
124 // |is_big_endian| is zero and big-endian otherwise. |data| must be a buffer of
125 // length |block_size| with the first |*num| bytes containing a partial block.
126 // |Nh| and |Nl| contain the total number of bits processed. On return, this
127 // function clears the partial block in |data| and
128 // |*num|.
129 //
130 // This function does not serialize |h| into a final digest. This is the
131 // responsibility of the caller.
132 template <typename Traits>
crypto_md32_final(typename Traits::HashContext * ctx)133 inline void crypto_md32_final(typename Traits::HashContext *ctx) {
134   static_assert(Traits::kBlockSize == sizeof(ctx->data), "block size is wrong");
135   // |data| always has room for at least one byte. A full block would have
136   // been consumed.
137   size_t n = ctx->num;
138   assert(n < Traits::kBlockSize);
139   ctx->data[n] = 0x80;
140   n++;
141 
142   // Fill the block with zeros if there isn't room for a 64-bit length.
143   if (n > Traits::kBlockSize - 8) {
144     OPENSSL_memset(ctx->data + n, 0, Traits::kBlockSize - n);
145     n = 0;
146     Traits::HashBlocks(ctx->h, ctx->data, 1);
147   }
148   OPENSSL_memset(ctx->data + n, 0, Traits::kBlockSize - 8 - n);
149 
150   // Append a 64-bit length to the block and process it.
151   if constexpr (Traits::kLengthIsBigEndian) {
152     CRYPTO_store_u32_be(ctx->data + Traits::kBlockSize - 8, ctx->Nh);
153     CRYPTO_store_u32_be(ctx->data + Traits::kBlockSize - 4, ctx->Nl);
154   } else {
155     CRYPTO_store_u32_le(ctx->data + Traits::kBlockSize - 8, ctx->Nl);
156     CRYPTO_store_u32_le(ctx->data + Traits::kBlockSize - 4, ctx->Nh);
157   }
158   Traits::HashBlocks(ctx->h, ctx->data, 1);
159   ctx->num = 0;
160   OPENSSL_memset(ctx->data, 0, Traits::kBlockSize);
161 }
162 
163 
164 BSSL_NAMESPACE_END
165 
166 #endif  // OPENSSL_HEADER_CRYPTO_FIPSMODULE_DIGEST_MD32_COMMON_H
167