]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/hash.c
Fix clang warning.
[thirdparty/cups.git] / cups / hash.c
CommitLineData
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
39ssize_t /* O - Size of hash or -1 on error */
40cupsHashData(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
282const char * /* O - Formatted string */
283cupsHashString(
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}