1 /* Test that the prefix argument to crypt_gensalt affects only the
2 choice of hashing method, not any of the parameters or the salt.
3
4 Written by Zack Weinberg <zackw at panix.com> in 2018.
5 To the extent possible under law, Zack Weinberg has waived all
6 copyright and related or neighboring rights to this work.
7
8 See https://creativecommons.org/publicdomain/zero/1.0/ for further
9 details. */
10
11 #include "crypt-port.h"
12
13 #include <errno.h>
14 #include <stdio.h>
15
16 /* Random bytes used when calling crypt_gensalt; for determinism, these
17 are fixed from run to run. */
18 #define N_RBYTES 64ul
19
20 static const char rbytes1[] =
21 "90idUkI2+mu2E/tMTViD418j2sPdEYq9LYq0yRW7RYhr4RqQ+oVzIIEcfJBqpf/D";
22
23 static const char rbytes2[] =
24 "sEwXQxrjBTEADauxCpvOQqq7iU9oq6uJ+Iux/fbhtLRj1MWgBFyo/t+nh/nzm0Kn";
25
26 static_assert(sizeof rbytes1 == N_RBYTES + 1, "rbytes1 is wrong length");
27 static_assert(sizeof rbytes2 == N_RBYTES + 1, "rbytes2 is wrong length");
28
29 struct testcase
30 {
31 const char *prefix;
32 unsigned long count1;
33 unsigned long count2;
34 };
35
36 /* This list should include one entry for each potentially-supported
37 hash prefix. If the hash method has tunable cost, set count1 and
38 count2 to two different nonzero values, within the supported cost
39 range. Neither value should equal the default cost. If the hash
40 method does not have tunable cost, set count1 and count2 to zero. */
41 static const struct testcase testcases[] =
42 {
43 #if INCLUDE_descrypt || INCLUDE_bigcrypt
44 { "", 0, 0 },
45 #endif
46 #if INCLUDE_bsdicrypt
47 { "_", 7019, 1120211 },
48 #endif
49 #if INCLUDE_nt
50 { "$3$", 0, 0 },
51 #endif
52 #if INCLUDE_md5crypt
53 { "$1$", 0, 0 },
54 #endif
55 #if INCLUDE_sunmd5
56 { "$md5", 7019, 1120211 },
57 #endif
58 #if INCLUDE_sha1crypt
59 { "$sha1", 7019, 1120211 },
60 #endif
61 #if INCLUDE_sha256crypt
62 { "$5$", 7019, 1120211 },
63 #endif
64 #if INCLUDE_sha512crypt
65 { "$6$", 7019, 1120211 },
66 #endif
67 #if INCLUDE_bcrypt
68 { "$2b$", 7, 11 },
69 #endif
70 #if INCLUDE_bcrypt_y
71 { "$2y$", 7, 11 },
72 #endif
73 #if INCLUDE_bcrypt_a
74 { "$2a$", 7, 11 },
75 #endif
76 #if INCLUDE_scrypt
77 { "$7$", 7, 11, },
78 #endif
79 #if INCLUDE_yescrypt
80 { "$y$", 7, 11, },
81 #endif
82 #if INCLUDE_gost_yescrypt
83 { "$gy$", 7, 11, },
84 #endif
85 { 0, 0, 0, }
86 };
87
88 static int
89 do_crypt_gensalt(const char *prefix,
90 const char rbytes[MIN_SIZE(N_RBYTES)],
91 unsigned long count,
92 char outbuf[MIN_SIZE(CRYPT_GENSALT_OUTPUT_SIZE)])
93 {
94 /* Detect failure to NUL-terminate the output properly. */
95 static int ncalls = 0;
96 memset(outbuf, '!' + (ncalls % ('~' - '!' + 1)),
97 CRYPT_GENSALT_OUTPUT_SIZE - 1);
98 outbuf[CRYPT_GENSALT_OUTPUT_SIZE - 1] = 0;
99 ncalls++;
100
101 char *rv = crypt_gensalt_rn(prefix, count, rbytes, N_RBYTES,
102 outbuf, CRYPT_GENSALT_OUTPUT_SIZE);
103 if (rv == 0)
104 {
105 printf("ERROR: gensalt(%s, %lu, %c%c..., %lu, outbuf, %lu) = 0/%s\n",
106 prefix, count, rbytes[0], rbytes[1],
107 N_RBYTES, (unsigned long)CRYPT_GENSALT_OUTPUT_SIZE,
108 strerror(errno));
109 outbuf[0] = '*';
110 memset (outbuf+1, 0, CRYPT_GENSALT_OUTPUT_SIZE-1);
111 return 1;
112 }
113 else if (rv[0] == '*')
114 {
115 printf("ERROR: gensalt(%s, %lu, %c%c..., %lu, outbuf, %lu) = %s/%s\n",
116 prefix, count, rbytes[0], rbytes[1],
117 N_RBYTES, (unsigned long)CRYPT_GENSALT_OUTPUT_SIZE,
118 outbuf, strerror(errno));
119 outbuf[0] = '*';
120 memset (outbuf+1, 0, CRYPT_GENSALT_OUTPUT_SIZE-1);
121 return 1;
122 }
123 else
124 return 0;
125 }
126
127 static int
128 do_check_equal(const char *stst, const char *sref,
129 const char *prefix, const char rbytes[N_RBYTES],
130 unsigned long count, const char *setting)
131 {
132 if (!strcmp(stst, sref))
133 return 0;
134
135 printf("FAIL: expected %s\n"
136 " got %s\n"
137 " from %s, %lu, %c%c...\n"
138 " and %s\n",
139 sref, stst, prefix, count, rbytes[0], rbytes[1], setting);
140 return 1;
141 }
142
143 int
144 main(void)
145 {
146 int status = 0;
147 char sref[6][CRYPT_GENSALT_OUTPUT_SIZE];
148 char stst[CRYPT_GENSALT_OUTPUT_SIZE];
149
150 for (size_t i = 0; testcases[i].prefix; i++)
151 {
152 const char *prefix = testcases[i].prefix;
153 unsigned long count1 = testcases[i].count1;
154 unsigned long count2 = testcases[i].count2;
155 int ncases;
156
157 memset(sref, 0, sizeof sref);
158
159 /* If count1 and count2 are both nonzero, then they should also
160 be unequal, and we have six reference cases:
161 (0, count1, count2) x (rbytes1, rbytes2).
162 If count1 and count2 are both zero, then we only have two
163 reference cases: 0 x (rbytes1, rbytes2) (this happens when the
164 hash method doesn't have tunable cost).
165 It is incorrect for only one of count1 and count2 to be zero,
166 or for them to be equal but nonzero. */
167 if (count1 == 0 && count2 == 0)
168 {
169 ncases = 2;
170 status |= do_crypt_gensalt(prefix, rbytes1, 0, sref[0]);
171 status |= do_crypt_gensalt(prefix, rbytes2, 0, sref[1]);
172 }
173 else if (count1 != 0 && count2 != 0 && count1 != count2)
174 {
175 ncases = 6;
176 status |= do_crypt_gensalt(prefix, rbytes1, 0, sref[0]);
177 status |= do_crypt_gensalt(prefix, rbytes2, 0, sref[1]);
178 status |= do_crypt_gensalt(prefix, rbytes1, count1, sref[2]);
179 status |= do_crypt_gensalt(prefix, rbytes2, count1, sref[3]);
180 status |= do_crypt_gensalt(prefix, rbytes1, count2, sref[4]);
181 status |= do_crypt_gensalt(prefix, rbytes2, count2, sref[5]);
182 }
183 else
184 {
185 printf ("ERROR: %zu/%s: inappropriate count1=%lu count2=%lu\n",
186 i, prefix, count1, count2);
187 status = 1;
188 continue;
189 }
190
191 /* At this point, sref[0..ncases] are filled with setting
192 strings corresponding to different combinations of salt and
193 cost. If we reuse those strings as prefixes for crypt_gensalt,
194 none of the additional information should affect the output. */
195 for (int j = 0; j < ncases; j++)
196 {
197 if (sref[j][0] == '*')
198 continue; /* initial crypt_gensalt call failed */
199 if (count1 == 0 && count2 == 0)
200 {
201 status |= do_crypt_gensalt(sref[j], rbytes1, 0, stst);
202 status |= do_check_equal(stst, sref[0],
203 prefix, rbytes1, 0, sref[j]);
204
205 status |= do_crypt_gensalt(sref[j], rbytes2, 0, stst);
206 status |= do_check_equal(stst, sref[1],
207 prefix, rbytes2, 0, sref[j]);
208 }
209 else
210 {
211 status |= do_crypt_gensalt(sref[j], rbytes1, 0, stst);
212 status |= do_check_equal(stst, sref[0],
213 prefix, rbytes1, 0, sref[j]);
214
215 status |= do_crypt_gensalt(sref[j], rbytes2, 0, stst);
216 status |= do_check_equal(stst, sref[1],
217 prefix, rbytes2, 0, sref[j]);
218
219 status |= do_crypt_gensalt(sref[j], rbytes1, count1, stst);
220 status |= do_check_equal(stst, sref[2],
221 prefix, rbytes1, count1, sref[j]);
222
223 status |= do_crypt_gensalt(sref[j], rbytes2, count1, stst);
224 status |= do_check_equal(stst, sref[3],
225 prefix, rbytes2, count1, sref[j]);
226
227 status |= do_crypt_gensalt(sref[j], rbytes1, count2, stst);
228 status |= do_check_equal(stst, sref[4],
229 prefix, rbytes1, count2, sref[j]);
230
231 status |= do_crypt_gensalt(sref[j], rbytes2, count2, stst);
232 status |= do_check_equal(stst, sref[5],
233 prefix, rbytes2, count2, sref[j]);
234 }
235 }
236
237 }
238
239 return status;
240 }