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