]>
Commit | Line | Data |
---|---|---|
5ae9fbb3 | 1 | /* |
5ae9fbb3 MS |
2 | * Hashing function for CUPS. |
3 | * | |
0057f146 | 4 | * Copyright © 2015-2019 by Apple Inc. |
5ae9fbb3 | 5 | * |
cff3f79f MS |
6 | * Licensed under Apache License v2.0. See the file "LICENSE" for more |
7 | * information. | |
5ae9fbb3 MS |
8 | */ |
9 | ||
10 | /* | |
11 | * Include necessary headers... | |
12 | */ | |
13 | ||
14 | #include "cups-private.h" | |
15 | #ifdef __APPLE__ | |
16 | # include <CommonCrypto/CommonDigest.h> | |
3ce45fb7 MS |
17 | #elif defined(HAVE_GNUTLS) |
18 | # include <gnutls/crypto.h> | |
68dc110f | 19 | # include "md5-internal.h" |
7ec11630 | 20 | #else |
fb863569 | 21 | # include "md5-internal.h" |
5ae9fbb3 MS |
22 | #endif /* __APPLE__ */ |
23 | ||
24 | ||
25 | /* | |
26 | * 'cupsHashData()' - Perform a hash function on the given data. | |
27 | * | |
28 | * The "algorithm" argument can be any of the registered, non-deprecated IPP | |
29 | * hash algorithms for the "job-password-encryption" attribute, including | |
30 | * "sha" for SHA-1, "sha-256" for SHA2-256, etc. | |
31 | * | |
32 | * The "hash" argument points to a buffer of "hashsize" bytes and should be at | |
33 | * least 64 bytes in length for all of the supported algorithms. | |
34 | * | |
35 | * The returned hash is binary data. | |
36 | * | |
b2e6c325 | 37 | * @since CUPS 2.2/macOS 10.12@ |
5ae9fbb3 MS |
38 | */ |
39 | ||
40 | ssize_t /* O - Size of hash or -1 on error */ | |
41 | cupsHashData(const char *algorithm, /* I - Algorithm name */ | |
42 | const void *data, /* I - Data to hash */ | |
43 | size_t datalen, /* I - Length of data to hash */ | |
44 | unsigned char *hash, /* I - Hash buffer */ | |
45 | size_t hashsize) /* I - Size of hash buffer */ | |
46 | { | |
47 | if (!algorithm || !data || datalen == 0 || !hash || hashsize == 0) | |
48 | { | |
49 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad arguments to function"), 1); | |
50 | return (-1); | |
51 | } | |
52 | ||
53 | #ifdef __APPLE__ | |
7ec11630 MS |
54 | if (!strcmp(algorithm, "md5")) |
55 | { | |
56 | /* | |
57 | * MD5 (deprecated but widely used...) | |
58 | */ | |
59 | ||
60 | CC_MD5_CTX ctx; /* MD5 context */ | |
61 | ||
62 | if (hashsize < CC_MD5_DIGEST_LENGTH) | |
63 | goto too_small; | |
64 | ||
65 | CC_MD5_Init(&ctx); | |
66 | CC_MD5_Update(&ctx, data, (CC_LONG)datalen); | |
67 | CC_MD5_Final(hash, &ctx); | |
68 | ||
69 | return (CC_MD5_DIGEST_LENGTH); | |
70 | } | |
71 | else if (!strcmp(algorithm, "sha")) | |
5ae9fbb3 MS |
72 | { |
73 | /* | |
74 | * SHA-1... | |
75 | */ | |
76 | ||
77 | CC_SHA1_CTX ctx; /* SHA-1 context */ | |
78 | ||
79 | if (hashsize < CC_SHA1_DIGEST_LENGTH) | |
80 | goto too_small; | |
81 | ||
82 | CC_SHA1_Init(&ctx); | |
83 | CC_SHA1_Update(&ctx, data, (CC_LONG)datalen); | |
84 | CC_SHA1_Final(hash, &ctx); | |
85 | ||
86 | return (CC_SHA1_DIGEST_LENGTH); | |
87 | } | |
012c3842 | 88 | else if (!strcmp(algorithm, "sha2-224")) |
5ae9fbb3 MS |
89 | { |
90 | CC_SHA256_CTX ctx; /* SHA-224 context */ | |
91 | ||
92 | if (hashsize < CC_SHA224_DIGEST_LENGTH) | |
93 | goto too_small; | |
94 | ||
95 | CC_SHA224_Init(&ctx); | |
96 | CC_SHA224_Update(&ctx, data, (CC_LONG)datalen); | |
97 | CC_SHA224_Final(hash, &ctx); | |
98 | ||
99 | return (CC_SHA224_DIGEST_LENGTH); | |
100 | } | |
012c3842 | 101 | else if (!strcmp(algorithm, "sha2-256")) |
5ae9fbb3 MS |
102 | { |
103 | CC_SHA256_CTX ctx; /* SHA-256 context */ | |
104 | ||
105 | if (hashsize < CC_SHA256_DIGEST_LENGTH) | |
106 | goto too_small; | |
107 | ||
108 | CC_SHA256_Init(&ctx); | |
109 | CC_SHA256_Update(&ctx, data, (CC_LONG)datalen); | |
110 | CC_SHA256_Final(hash, &ctx); | |
111 | ||
112 | return (CC_SHA256_DIGEST_LENGTH); | |
113 | } | |
012c3842 | 114 | else if (!strcmp(algorithm, "sha2-384")) |
5ae9fbb3 MS |
115 | { |
116 | CC_SHA512_CTX ctx; /* SHA-384 context */ | |
117 | ||
118 | if (hashsize < CC_SHA384_DIGEST_LENGTH) | |
119 | goto too_small; | |
120 | ||
121 | CC_SHA384_Init(&ctx); | |
122 | CC_SHA384_Update(&ctx, data, (CC_LONG)datalen); | |
123 | CC_SHA384_Final(hash, &ctx); | |
124 | ||
125 | return (CC_SHA384_DIGEST_LENGTH); | |
126 | } | |
012c3842 | 127 | else if (!strcmp(algorithm, "sha2-512")) |
5ae9fbb3 MS |
128 | { |
129 | CC_SHA512_CTX ctx; /* SHA-512 context */ | |
130 | ||
131 | if (hashsize < CC_SHA512_DIGEST_LENGTH) | |
132 | goto too_small; | |
133 | ||
134 | CC_SHA512_Init(&ctx); | |
135 | CC_SHA512_Update(&ctx, data, (CC_LONG)datalen); | |
136 | CC_SHA512_Final(hash, &ctx); | |
137 | ||
138 | return (CC_SHA512_DIGEST_LENGTH); | |
139 | } | |
012c3842 | 140 | else if (!strcmp(algorithm, "sha2-512_224")) |
5ae9fbb3 MS |
141 | { |
142 | CC_SHA512_CTX ctx; /* SHA-512 context */ | |
143 | unsigned char temp[CC_SHA512_DIGEST_LENGTH]; | |
144 | /* SHA-512 hash */ | |
145 | ||
146 | /* | |
147 | * SHA2-512 truncated to 224 bits (28 bytes)... | |
148 | */ | |
149 | ||
150 | if (hashsize < CC_SHA224_DIGEST_LENGTH) | |
151 | goto too_small; | |
152 | ||
153 | CC_SHA512_Init(&ctx); | |
154 | CC_SHA512_Update(&ctx, data, (CC_LONG)datalen); | |
155 | CC_SHA512_Final(temp, &ctx); | |
156 | ||
157 | memcpy(hash, temp, CC_SHA224_DIGEST_LENGTH); | |
158 | ||
159 | return (CC_SHA224_DIGEST_LENGTH); | |
160 | } | |
012c3842 | 161 | else if (!strcmp(algorithm, "sha2-512_256")) |
5ae9fbb3 MS |
162 | { |
163 | CC_SHA512_CTX ctx; /* SHA-512 context */ | |
164 | unsigned char temp[CC_SHA512_DIGEST_LENGTH]; | |
165 | /* SHA-512 hash */ | |
166 | ||
167 | /* | |
168 | * SHA2-512 truncated to 256 bits (32 bytes)... | |
169 | */ | |
170 | ||
171 | if (hashsize < CC_SHA256_DIGEST_LENGTH) | |
172 | goto too_small; | |
173 | ||
174 | CC_SHA512_Init(&ctx); | |
175 | CC_SHA512_Update(&ctx, data, (CC_LONG)datalen); | |
176 | CC_SHA512_Final(temp, &ctx); | |
177 | ||
178 | memcpy(hash, temp, CC_SHA256_DIGEST_LENGTH); | |
179 | ||
180 | return (CC_SHA256_DIGEST_LENGTH); | |
181 | } | |
182 | ||
183 | #elif defined(HAVE_GNUTLS) | |
184 | gnutls_digest_algorithm_t alg = GNUTLS_DIG_UNKNOWN; | |
185 | /* Algorithm */ | |
186 | unsigned char temp[64]; /* Temporary hash buffer */ | |
187 | size_t tempsize = 0; /* Truncate to this size? */ | |
188 | ||
9ec6124c | 189 | |
7ec11630 | 190 | if (!strcmp(algorithm, "md5")) |
68dc110f MS |
191 | { |
192 | /* | |
193 | * Some versions of GNU TLS disable MD5 without warning... | |
194 | */ | |
195 | ||
196 | _cups_md5_state_t state; /* MD5 state info */ | |
197 | ||
198 | if (hashsize < 16) | |
199 | goto too_small; | |
200 | ||
201 | _cupsMD5Init(&state); | |
064e50fb | 202 | _cupsMD5Append(&state, data, (int)datalen); |
68dc110f MS |
203 | _cupsMD5Finish(&state, hash); |
204 | ||
205 | return (16); | |
206 | } | |
7ec11630 | 207 | else if (!strcmp(algorithm, "sha")) |
5ae9fbb3 | 208 | alg = GNUTLS_DIG_SHA1; |
012c3842 | 209 | else if (!strcmp(algorithm, "sha2-224")) |
5ae9fbb3 | 210 | alg = GNUTLS_DIG_SHA224; |
012c3842 | 211 | else if (!strcmp(algorithm, "sha2-256")) |
5ae9fbb3 | 212 | alg = GNUTLS_DIG_SHA256; |
012c3842 | 213 | else if (!strcmp(algorithm, "sha2-384")) |
5ae9fbb3 | 214 | alg = GNUTLS_DIG_SHA384; |
012c3842 | 215 | else if (!strcmp(algorithm, "sha2-512")) |
5ae9fbb3 | 216 | alg = GNUTLS_DIG_SHA512; |
012c3842 | 217 | else if (!strcmp(algorithm, "sha2-512_224")) |
5ae9fbb3 MS |
218 | { |
219 | alg = GNUTLS_DIG_SHA512; | |
220 | tempsize = 28; | |
221 | } | |
012c3842 | 222 | else if (!strcmp(algorithm, "sha2-512_256")) |
5ae9fbb3 MS |
223 | { |
224 | alg = GNUTLS_DIG_SHA512; | |
225 | tempsize = 32; | |
226 | } | |
227 | ||
228 | if (alg != GNUTLS_DIG_UNKNOWN) | |
229 | { | |
230 | if (tempsize > 0) | |
231 | { | |
232 | /* | |
233 | * Truncate result to tempsize bytes... | |
234 | */ | |
235 | ||
236 | if (hashsize < tempsize) | |
237 | goto too_small; | |
238 | ||
239 | gnutls_hash_fast(alg, data, datalen, temp); | |
240 | memcpy(hash, temp, tempsize); | |
241 | ||
3ce45fb7 | 242 | return ((ssize_t)tempsize); |
5ae9fbb3 MS |
243 | } |
244 | ||
245 | if (hashsize < gnutls_hash_get_len(alg)) | |
246 | goto too_small; | |
247 | ||
248 | gnutls_hash_fast(alg, data, datalen, hash); | |
249 | ||
0057f146 | 250 | return ((ssize_t)gnutls_hash_get_len(alg)); |
5ae9fbb3 MS |
251 | } |
252 | ||
253 | #else | |
254 | /* | |
7ec11630 | 255 | * No hash support beyond MD5 without CommonCrypto or GNU TLS... |
5ae9fbb3 MS |
256 | */ |
257 | ||
7ec11630 MS |
258 | if (!strcmp(algorithm, "md5")) |
259 | { | |
260 | _cups_md5_state_t state; /* MD5 state info */ | |
261 | ||
68dc110f MS |
262 | if (hashsize < 16) |
263 | goto too_small; | |
264 | ||
7ec11630 MS |
265 | _cupsMD5Init(&state); |
266 | _cupsMD5Append(&state, data, datalen); | |
267 | _cupsMD5Finish(&state, hash); | |
268 | ||
269 | return (16); | |
270 | } | |
271 | else if (hashsize < 64) | |
5ae9fbb3 MS |
272 | goto too_small; |
273 | #endif /* __APPLE__ */ | |
274 | ||
275 | /* | |
276 | * Unknown hash algorithm... | |
277 | */ | |
278 | ||
279 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown hash algorithm."), 1); | |
280 | ||
281 | return (-1); | |
282 | ||
283 | /* | |
284 | * We get here if the buffer is too small. | |
285 | */ | |
286 | ||
287 | too_small: | |
288 | ||
289 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Hash buffer too small."), 1); | |
290 | return (-1); | |
291 | } | |
7ec11630 MS |
292 | |
293 | ||
294 | /* | |
295 | * 'cupsHashString()' - Format a hash value as a hexadecimal string. | |
296 | * | |
297 | * The passed buffer must be at least 2 * hashsize + 1 characters in length. | |
706a0485 | 298 | * |
cff3f79f | 299 | * @since CUPS 2.2.7@ |
7ec11630 MS |
300 | */ |
301 | ||
302 | const char * /* O - Formatted string */ | |
303 | cupsHashString( | |
304 | const unsigned char *hash, /* I - Hash */ | |
305 | size_t hashsize, /* I - Size of hash */ | |
306 | char *buffer, /* I - String buffer */ | |
307 | size_t bufsize) /* I - Size of string buffer */ | |
308 | { | |
309 | char *bufptr = buffer; /* Pointer into buffer */ | |
310 | static const char *hex = "0123456789abcdef"; | |
311 | /* Hex characters (lowercase!) */ | |
312 | ||
313 | ||
314 | /* | |
315 | * Range check input... | |
316 | */ | |
317 | ||
318 | if (!hash || hashsize < 1 || !buffer || bufsize < (2 * hashsize + 1)) | |
319 | { | |
320 | if (buffer) | |
321 | *buffer = '\0'; | |
322 | return (NULL); | |
323 | } | |
324 | ||
325 | /* | |
326 | * Loop until we've converted the whole hash... | |
327 | */ | |
328 | ||
329 | while (hashsize > 0) | |
330 | { | |
331 | *bufptr++ = hex[*hash >> 4]; | |
332 | *bufptr++ = hex[*hash & 15]; | |
333 | ||
334 | hash ++; | |
335 | hashsize --; | |
336 | } | |
337 | ||
338 | *bufptr = '\0'; | |
339 | ||
340 | return (buffer); | |
341 | } |