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