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