Branch data Line data Source code
1 : : #include "test_libsha512_utils.h"
2 : :
3 : : /**
4 : : * @brief Fill a test message with deterministic bytes
5 : : * @details The exact text is not important for this test. A stable byte pattern
6 : : * makes every boundary case reproducible while still exercising ordinary binary
7 : : * input rather than a special empty buffer
8 : : *
9 : : * @param message Descriptor that receives the generated bytes
10 : : * @param message_size Number of bytes to generate
11 : : * @return SUCCESS when the message descriptor is ready to hash
12 : : */
13 : 6 : static Return prepare_boundary_message(
14 : : memory *message,
15 : : size_t message_size)
16 : : {
17 : : /* Status returned by this function through provide()
18 : : Default value assumes successful completion */
19 : 6 : Return status = SUCCESS;
20 : :
21 : 6 : unsigned char *message_data = NULL;
22 : :
23 : : /* Require a real descriptor and a non-empty size before writing the pattern */
24 : 6 : ASSERT(message != NULL);
25 : 6 : ASSERT(message_size > 0U);
26 : 6 : ASSERT(SUCCESS == m_resize(message,message_size,ZERO_NEW_MEMORY));
27 : :
28 : : /* Ask libmem for writable bytes only after the descriptor has the requested
29 : : length */
30 : 6 : IF(message != NULL)
31 : : {
32 : 6 : message_data = m_data(unsigned char,message);
33 : : }
34 : :
35 : 6 : ASSERT(message_data != NULL);
36 : :
37 : : /* Fill with a predictable alphabet pattern. It is simple to inspect, but it
38 : : still exercises binary hashing rather than relying on string helpers */
39 [ + - + + ]: 726 : for(size_t byte_index = 0U; SUCCESS == status && byte_index < message_size; byte_index++)
40 : : {
41 : 720 : message_data[byte_index] = (unsigned char)('A' + (byte_index % 26U));
42 : : }
43 : :
44 : 6 : provide(status);
45 : : }
46 : :
47 : : /**
48 : : * @brief Prepare a two-piece chunk plan for one boundary message
49 : : * @details The first chunk leaves one byte for the second update call. For a
50 : : * 128-byte message this specifically exercises the path where buffered input
51 : : * completes a full SHA-512 block
52 : : *
53 : : * @param chunks Descriptor that receives two size_t chunk lengths
54 : : * @param message_size Total message size that the chunks must cover
55 : : * @return SUCCESS when the chunk descriptor contains a complete plan
56 : : */
57 : 6 : static Return prepare_boundary_chunks(
58 : : memory *chunks,
59 : : size_t message_size)
60 : : {
61 : : /* Status returned by this function through provide()
62 : : Default value assumes successful completion */
63 : 6 : Return status = SUCCESS;
64 : :
65 : 6 : size_t *chunk_data = NULL;
66 : :
67 : : /* The boundary comparison needs exactly two chunks: almost the whole message
68 : : first, then one final byte */
69 : 6 : ASSERT(chunks != NULL);
70 : 6 : ASSERT(message_size > 0U);
71 : 6 : ASSERT(SUCCESS == m_resize(chunks,2U,ZERO_NEW_MEMORY));
72 : :
73 : : /* Retrieve writable chunk storage after libmem has allocated two entries */
74 : 6 : IF(chunks != NULL)
75 : : {
76 : 6 : chunk_data = m_data(size_t,chunks);
77 : : }
78 : :
79 : 6 : ASSERT(chunk_data != NULL);
80 : :
81 : : /* The final one-byte update is the important part of this scenario because
82 : : it can complete a buffered SHA-512 block */
83 : 6 : IF(chunk_data != NULL)
84 : : {
85 : 6 : chunk_data[0] = message_size - 1U;
86 : 6 : chunk_data[1] = 1U;
87 : : }
88 : :
89 : 6 : provide(status);
90 : : }
91 : :
92 : : /**
93 : : * @brief Compare one-shot and chunked hashing at one SHA-512 boundary
94 : : * @details A size close to the 128-byte block or 112-byte padding threshold can
95 : : * use different internal paths. The public digest must stay the same no matter
96 : : * which path is used
97 : : *
98 : : * @param message_size Boundary size to exercise
99 : : * @return SUCCESS when both hashing styles produce one digest
100 : : */
101 : 6 : static Return check_sha512_boundary_size(size_t message_size)
102 : : {
103 : : /* Status returned by this function through provide()
104 : : Default value assumes successful completion */
105 : 6 : Return status = SUCCESS;
106 : :
107 : : /* Keep all temporary buffers in libmem descriptors so setup, hashing, and
108 : : cleanup follow the same rules as the rest of the test environment */
109 : 6 : m_create(unsigned char,message);
110 : 6 : m_create(size_t,chunks);
111 : 6 : m_create(unsigned char,one_shot_digest);
112 : 6 : m_create(unsigned char,chunked_digest);
113 : 6 : m_create(unsigned char,monocypher_digest);
114 : :
115 : : /* Build one deterministic boundary-sized message and a chunk plan that
116 : : finishes it with a one-byte update */
117 : 6 : ASSERT(SUCCESS == prepare_boundary_message(message,message_size));
118 : 6 : ASSERT(SUCCESS == prepare_boundary_chunks(chunks,message_size));
119 : :
120 : : /* Hash the exact same bytes through both libsha512 paths and the Monocypher
121 : : reference. Boundary behavior is correct only if every digest matches */
122 : 6 : ASSERT(SUCCESS == calculate_sha512_digest(
123 : : m_data_ro(unsigned char,message),
124 : : message->length,
125 : : one_shot_digest));
126 : 6 : ASSERT(SUCCESS == calculate_sha512_digest_monocypher(
127 : : m_data_ro(unsigned char,message),
128 : : message->length,
129 : : monocypher_digest));
130 : 6 : ASSERT(SUCCESS == calculate_sha512_digest_in_chunks(
131 : : m_data_ro(unsigned char,message),
132 : : message->length,
133 : : chunks,
134 : : chunked_digest));
135 : 6 : ASSERT(SUCCESS == assert_sha512_digest_matches(one_shot_digest,monocypher_digest));
136 : 6 : ASSERT(SUCCESS == assert_sha512_digest_matches(chunked_digest,monocypher_digest));
137 : :
138 : : /* Free descriptors with call() so a failed boundary check does not leak the
139 : : buffers allocated for that size */
140 : 6 : call(m_del(message));
141 : 6 : call(m_del(chunks));
142 : 6 : call(m_del(one_shot_digest));
143 : 6 : call(m_del(chunked_digest));
144 : 6 : call(m_del(monocypher_digest));
145 : :
146 : 6 : provide(status);
147 : : }
148 : :
149 : : /**
150 : : * @brief Check the byte just before the SHA-512 padding threshold
151 : : * @details A 111-byte message leaves exactly enough room for padding and the
152 : : * length field in one final block, so one-shot and chunked hashing must agree
153 : : *
154 : : * @return SUCCESS when the 111-byte digest is stable across input styles
155 : : */
156 : 1 : static Return test_libsha512_0004_1(void)
157 : : {
158 : 1 : INITTEST;
159 : :
160 : : /* Exercise the byte immediately before the 112-byte padding boundary */
161 : 1 : run(check_sha512_boundary_size(111U));
162 : :
163 : 1 : RETURN_STATUS;
164 : : }
165 : :
166 : : /**
167 : : * @brief Check the SHA-512 padding threshold itself
168 : : * @details A 112-byte message reaches the point where final padding must spill
169 : : * into an additional block, which is a classic edge for SHA-512 implementations
170 : : *
171 : : * @return SUCCESS when the 112-byte digest is stable across input styles
172 : : */
173 : 1 : static Return test_libsha512_0004_2(void)
174 : : {
175 : 1 : INITTEST;
176 : :
177 : : /* Exercise the exact boundary where SHA-512 final padding changes shape */
178 : 1 : run(check_sha512_boundary_size(112U));
179 : :
180 : 1 : RETURN_STATUS;
181 : : }
182 : :
183 : : /**
184 : : * @brief Check the byte just after the SHA-512 padding threshold
185 : : * @details A 113-byte message confirms that the post-threshold finalization
186 : : * path still produces the same digest for one-shot and chunked callers
187 : : *
188 : : * @return SUCCESS when the 113-byte digest is stable across input styles
189 : : */
190 : 1 : static Return test_libsha512_0004_3(void)
191 : : {
192 : 1 : INITTEST;
193 : :
194 : : /* Exercise the first byte after the 112-byte padding boundary */
195 : 1 : run(check_sha512_boundary_size(113U));
196 : :
197 : 1 : RETURN_STATUS;
198 : : }
199 : :
200 : : /**
201 : : * @brief Check the byte just before a full SHA-512 block
202 : : * @details A 127-byte message leaves one byte to complete the 128-byte block
203 : : * size, making it a useful streaming boundary for chunked updates
204 : : *
205 : : * @return SUCCESS when the 127-byte digest is stable across input styles
206 : : */
207 : 1 : static Return test_libsha512_0004_4(void)
208 : : {
209 : 1 : INITTEST;
210 : :
211 : : /* Exercise the byte immediately before a full SHA-512 block */
212 : 1 : run(check_sha512_boundary_size(127U));
213 : :
214 : 1 : RETURN_STATUS;
215 : : }
216 : :
217 : : /**
218 : : * @brief Check an exact full SHA-512 block
219 : : * @details A 128-byte message verifies the path where update processing can
220 : : * compress a full block before final padding is added
221 : : *
222 : : * @return SUCCESS when the 128-byte digest is stable across input styles
223 : : */
224 : 1 : static Return test_libsha512_0004_5(void)
225 : : {
226 : 1 : INITTEST;
227 : :
228 : : /* Exercise the exact 128-byte SHA-512 block size */
229 : 1 : run(check_sha512_boundary_size(128U));
230 : :
231 : 1 : RETURN_STATUS;
232 : : }
233 : :
234 : : /**
235 : : * @brief Check the byte just after a full SHA-512 block
236 : : * @details A 129-byte message proves that hashing remains stable immediately
237 : : * after a block is compressed and new buffered input begins
238 : : *
239 : : * @return SUCCESS when the 129-byte digest is stable across input styles
240 : : */
241 : 1 : static Return test_libsha512_0004_6(void)
242 : : {
243 : 1 : INITTEST;
244 : :
245 : : /* Exercise the first byte after a full SHA-512 block */
246 : 1 : run(check_sha512_boundary_size(129U));
247 : :
248 : 1 : RETURN_STATUS;
249 : : }
250 : :
251 : : /**
252 : : * @brief Check SHA-512 behavior around block and padding boundaries
253 : : * @details The selected sizes sit on both sides of important internal limits:
254 : : * 112 bytes for final padding and 128 bytes for a full SHA-512 block
255 : : *
256 : : * @return SUCCESS when all boundary sizes produce stable digests
257 : : */
258 : 1 : Return test_libsha512_0004(void)
259 : : {
260 : 1 : INITTEST;
261 : :
262 : : /* Exercise each boundary independently so a failure points to the exact
263 : : message size that broke the one-shot versus chunked guarantee */
264 : 1 : TEST(test_libsha512_0004_1,"111-byte input stays stable just before SHA-512 padding spillover");
265 : 1 : TEST(test_libsha512_0004_2,"112-byte input stays stable at SHA-512 padding spillover");
266 : 1 : TEST(test_libsha512_0004_3,"113-byte input stays stable just after SHA-512 padding spillover");
267 : 1 : TEST(test_libsha512_0004_4,"127-byte input stays stable just before a full SHA-512 block");
268 : 1 : TEST(test_libsha512_0004_5,"128-byte input stays stable at a full SHA-512 block");
269 : 1 : TEST(test_libsha512_0004_6,"129-byte input stays stable just after a full SHA-512 block");
270 : :
271 : 1 : RETURN_STATUS;
272 : : }
|