Branch data Line data Source code
1 : : #include "test_libsha512_utils.h"
2 : :
3 : : #include "monocypher-ed25519.h"
4 : :
5 : : /**
6 : : * @brief Hash one complete message with libsha512
7 : : * @details This helper gives tests a small, readable way to ask libsha512 for
8 : : * the digest of a message. The digest is stored in a libmem descriptor so the
9 : : * tests exercise the same memory-management style used by the other libraries
10 : : *
11 : : * @param message Message bytes that should be hashed
12 : : * @param message_size Number of bytes from @p message to include in the hash
13 : : * @param digest Output descriptor that receives the 64-byte SHA-512 digest
14 : : * @return SUCCESS when the digest was written, otherwise FAILURE
15 : : */
16 : 11 : Return calculate_sha512_digest(
17 : : const unsigned char *message,
18 : : size_t message_size,
19 : : memory *digest)
20 : : {
21 : : /* Status returned by this function through provide()
22 : : Default value assumes successful completion */
23 : 11 : Return status = SUCCESS;
24 : :
25 : 11 : SHA512_Context context = {0};
26 : 11 : unsigned char *digest_data = NULL;
27 : :
28 : : /* Validate the public helper inputs before allocating the digest buffer */
29 : 11 : ASSERT(message != NULL);
30 : 11 : ASSERT(digest != NULL);
31 : 11 : ASSERT(SUCCESS == m_resize(digest,SHA512_DIGEST_LENGTH,ZERO_NEW_MEMORY));
32 : :
33 : : /* Convert the digest descriptor to writable bytes after it has the required
34 : : SHA-512 digest length */
35 : 11 : IF(digest != NULL)
36 : : {
37 : 11 : digest_data = m_data(unsigned char,digest);
38 : : }
39 : :
40 : : /* Drive the normal one-shot SHA-512 flow: initialize, feed bytes, finalize */
41 : 11 : ASSERT(digest_data != NULL);
42 : 11 : ASSERT(CRYPT_OK == sha512_init(&context));
43 : 11 : ASSERT(CRYPT_OK == sha512_update(&context,message,message_size));
44 : 11 : ASSERT(CRYPT_OK == sha512_final(&context,digest_data));
45 : :
46 : 11 : provide(status);
47 : : }
48 : :
49 : : /**
50 : : * @brief Hash one complete message with Monocypher SHA512
51 : : * @details The tests use this helper as an independent reference implementation
52 : : * for libsha512. It keeps Monocypher setup and length validation in one place
53 : : * while the individual tests stay focused on the input shape they exercise
54 : : *
55 : : * @param message Message bytes that should be hashed
56 : : * @param message_size Number of bytes from @p message to include in the hash
57 : : * @param digest Output descriptor that receives the 64-byte SHA-512 digest
58 : : * @return SUCCESS when Monocypher produced one SHA-512 digest, otherwise FAILURE
59 : : */
60 : 11 : Return calculate_sha512_digest_monocypher(
61 : : const unsigned char *message,
62 : : size_t message_size,
63 : : memory *digest)
64 : : {
65 : : /* Status returned by this function through provide()
66 : : Default value assumes successful completion */
67 : 11 : Return status = SUCCESS;
68 : :
69 : 11 : unsigned char *digest_data = NULL;
70 : :
71 : 11 : ASSERT(message != NULL);
72 : 11 : ASSERT(digest != NULL);
73 : 11 : ASSERT(SUCCESS == m_resize(digest,SHA512_DIGEST_LENGTH,ZERO_NEW_MEMORY));
74 : :
75 : 11 : IF(digest != NULL)
76 : : {
77 : 11 : digest_data = m_data(unsigned char,digest);
78 : : }
79 : :
80 : 11 : ASSERT(digest_data != NULL);
81 : :
82 [ + - ]: 11 : if(SUCCESS == status)
83 : : {
84 : 11 : crypto_sha512(digest_data,message,message_size);
85 : : }
86 : :
87 : 11 : provide(status);
88 : : }
89 : :
90 : : /**
91 : : * @brief Hash one message by sending it to libsha512 in smaller pieces
92 : : * @details SHA-512 callers may provide input gradually instead of all at once.
93 : : * This helper checks that pattern by applying each requested chunk size to a
94 : : * single hash context and writing the final digest into a libmem descriptor
95 : : *
96 : : * @param message Full message bytes that should be hashed
97 : : * @param message_size Number of bytes available in @p message
98 : : * @param chunk_sizes Descriptor containing the piece sizes to feed in order
99 : : * @param digest Output descriptor that receives the 64-byte SHA-512 digest
100 : : * @return SUCCESS when every chunk was accepted and the digest was written
101 : : */
102 : 10 : Return calculate_sha512_digest_in_chunks(
103 : : const unsigned char *message,
104 : : size_t message_size,
105 : : const memory *chunk_sizes,
106 : : memory *digest)
107 : : {
108 : : /* Status returned by this function through provide()
109 : : Default value assumes successful completion */
110 : 10 : Return status = SUCCESS;
111 : :
112 : 10 : SHA512_Context context = {0};
113 : 10 : const size_t *chunks = NULL;
114 : 10 : unsigned char *digest_data = NULL;
115 : 10 : size_t offset = 0U;
116 : :
117 : : /* Validate the message, chunk plan, and output descriptor before hashing */
118 : 10 : ASSERT(message != NULL);
119 : 10 : ASSERT(chunk_sizes != NULL);
120 : 10 : ASSERT(digest != NULL);
121 : 10 : ASSERT(chunk_sizes->length > 0U);
122 : 10 : ASSERT(SUCCESS == m_resize(digest,SHA512_DIGEST_LENGTH,ZERO_NEW_MEMORY));
123 : :
124 : : /* Read chunk sizes from libmem and prepare writable storage for the digest */
125 : 10 : IF(chunk_sizes != NULL)
126 : : {
127 : 10 : chunks = m_data_ro(size_t,chunk_sizes);
128 : : }
129 : :
130 : 10 : IF(digest != NULL)
131 : : {
132 : 10 : digest_data = m_data(unsigned char,digest);
133 : : }
134 : :
135 : 10 : ASSERT(chunks != NULL);
136 : 10 : ASSERT(digest_data != NULL);
137 : 10 : ASSERT(CRYPT_OK == sha512_init(&context));
138 : :
139 : : /* Feed each requested chunk in order. The bounds checks keep the chunk plan
140 : : honest, so the final digest represents exactly the message under test */
141 [ + - + + ]: 76 : for(size_t chunk_index = 0U; SUCCESS == status && chunk_index < chunk_sizes->length; chunk_index++)
142 : : {
143 : 66 : ASSERT(offset <= message_size);
144 : 66 : ASSERT(chunks[chunk_index] <= message_size - offset);
145 : :
146 [ + - ]: 66 : if(SUCCESS == status)
147 : : {
148 : 66 : ASSERT(CRYPT_OK == sha512_update(&context,message + offset,chunks[chunk_index]));
149 : 66 : offset += chunks[chunk_index];
150 : : }
151 : : }
152 : :
153 : : /* Confirm that the chunk plan consumed the full message, then write the
154 : : digest from the completed SHA-512 context */
155 : 10 : ASSERT(offset == message_size);
156 : 10 : ASSERT(CRYPT_OK == sha512_final(&context,digest_data));
157 : :
158 : 10 : provide(status);
159 : : }
160 : :
161 : : /**
162 : : * @brief Compare two SHA-512 digest descriptors
163 : : * @details The check validates descriptor shape before comparing bytes, so a
164 : : * failing test points either to malformed test data or to a digest mismatch
165 : : *
166 : : * @param digest Digest produced by the code under test
167 : : * @param expected_digest Digest that the test expects
168 : : * @return SUCCESS when both descriptors contain the same 64 digest bytes
169 : : */
170 : 25 : Return assert_sha512_digest_matches(
171 : : const memory *digest,
172 : : const memory *expected_digest)
173 : : {
174 : : /* Status returned by this function through provide()
175 : : Default value assumes successful completion */
176 : 25 : Return status = SUCCESS;
177 : :
178 : 25 : const unsigned char *digest_data = NULL;
179 : 25 : const unsigned char *expected_data = NULL;
180 : 25 : size_t digest_size = 0U;
181 : 25 : size_t expected_size = 0U;
182 : :
183 : : /* First verify descriptor shape. A length failure is easier to understand
184 : : than a raw byte comparison against malformed data */
185 : 25 : ASSERT(digest != NULL);
186 : 25 : ASSERT(expected_digest != NULL);
187 : 25 : ASSERT(digest->length == SHA512_DIGEST_LENGTH);
188 : 25 : ASSERT(expected_digest->length == SHA512_DIGEST_LENGTH);
189 : 25 : ASSERT(SUCCESS == m_guarded_byte_size(digest,digest->length,&digest_size));
190 : 25 : ASSERT(SUCCESS == m_guarded_byte_size(expected_digest,expected_digest->length,&expected_size));
191 : 25 : ASSERT(digest_size == SHA512_DIGEST_LENGTH);
192 : 25 : ASSERT(expected_size == SHA512_DIGEST_LENGTH);
193 : :
194 : : /* Pull out read-only byte pointers only after descriptor validation passes */
195 : 25 : IF(digest != NULL)
196 : : {
197 : 25 : digest_data = m_data_ro(unsigned char,digest);
198 : : }
199 : :
200 : 25 : IF(expected_digest != NULL)
201 : : {
202 : 25 : expected_data = m_data_ro(unsigned char,expected_digest);
203 : : }
204 : :
205 : 25 : ASSERT(digest_data != NULL);
206 : 25 : ASSERT(expected_data != NULL);
207 : :
208 : : /* Finally compare the digest bytes themselves */
209 : 25 : IF(digest_data != NULL && expected_data != NULL)
210 : : {
211 : 25 : ASSERT(0 == memcmp(digest_data,expected_data,(size_t)SHA512_DIGEST_LENGTH));
212 : : }
213 : :
214 : 25 : provide(status);
215 : : }
216 : :
217 : : /**
218 : : * @brief Run one human-readable SHA-512 reference case
219 : : * @details The vector describes a message and the digest that public SHA-512
220 : : * references say it must produce. This helper prepares the message through
221 : : * libmem, hashes it, and compares the result with the expected bytes
222 : : *
223 : : * @param vector Message text and expected digest bytes for one reference case
224 : : * @return SUCCESS when libsha512 returns the expected digest
225 : : */
226 : 4 : Return check_sha512_vector(const sha512_digest_vector *vector)
227 : : {
228 : : /* Status returned by this function through provide()
229 : : Default value assumes successful completion */
230 : 4 : Return status = SUCCESS;
231 : :
232 : 4 : size_t message_length = 0U;
233 : :
234 : 4 : m_create(char,message,MEMORY_STRING);
235 : 4 : m_create(unsigned char,digest);
236 : 4 : m_create(unsigned char,expected_digest);
237 : 4 : m_create(unsigned char,monocypher_digest);
238 : :
239 : : /* Validate the vector and copy its text into libmem-managed storage. The
240 : : string length check catches accidental vector size drift */
241 : 4 : ASSERT(vector != NULL);
242 : 4 : ASSERT(vector->message_text != NULL);
243 : 4 : ASSERT(vector->expected_digest != NULL);
244 : 4 : ASSERT(SUCCESS == m_copy_fixed_string(message,vector->message_size + 1U,vector->message_text));
245 : 4 : ASSERT(SUCCESS == m_string_length(message,&message_length));
246 : 4 : ASSERT(message_length == vector->message_size);
247 : :
248 : : /* Hash the prepared message and copy the expected digest into the same
249 : : descriptor style before comparing both byte arrays */
250 : 4 : ASSERT(SUCCESS == calculate_sha512_digest(
251 : : (const unsigned char *)m_text(message),
252 : : message_length,
253 : : digest));
254 : 4 : ASSERT(SUCCESS == calculate_sha512_digest_monocypher(
255 : : (const unsigned char *)m_text(message),
256 : : message_length,
257 : : monocypher_digest));
258 : 4 : ASSERT(SUCCESS == m_copy_buffer(
259 : : expected_digest,
260 : : SHA512_DIGEST_LENGTH,
261 : : vector->expected_digest));
262 : 4 : ASSERT(SUCCESS == assert_sha512_digest_matches(expected_digest,monocypher_digest));
263 : 4 : ASSERT(SUCCESS == assert_sha512_digest_matches(digest,monocypher_digest));
264 : :
265 : : /* Clean up every descriptor even when a vector assertion fails */
266 : 4 : call(m_del(message));
267 : 4 : call(m_del(digest));
268 : 4 : call(m_del(expected_digest));
269 : 4 : call(m_del(monocypher_digest));
270 : :
271 : 4 : provide(status);
272 : : }
|