2 * Hashing function for CUPS.
4 * Copyright © 2015-2019 by Apple Inc.
6 * Licensed under Apache License v2.0. See the file "LICENSE" for more
11 * Include necessary headers...
14 #include "cups-private.h"
16 # include <CommonCrypto/CommonDigest.h>
17 #elif defined(HAVE_GNUTLS)
18 # include <gnutls/crypto.h>
19 # include "md5-internal.h"
21 # include "md5-internal.h"
22 #endif /* __APPLE__ */
26 * 'cupsHashData()' - Perform a hash function on the given data.
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.
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.
35 * The returned hash is binary data.
37 * @since CUPS 2.2/macOS 10.12@
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 */
47 if (!algorithm
|| !data
|| datalen
== 0 || !hash
|| hashsize
== 0)
49 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad arguments to function"), 1);
54 if (!strcmp(algorithm
, "md5"))
57 * MD5 (deprecated but widely used...)
60 CC_MD5_CTX ctx
; /* MD5 context */
62 if (hashsize
< CC_MD5_DIGEST_LENGTH
)
66 CC_MD5_Update(&ctx
, data
, (CC_LONG
)datalen
);
67 CC_MD5_Final(hash
, &ctx
);
69 return (CC_MD5_DIGEST_LENGTH
);
71 else if (!strcmp(algorithm
, "sha"))
77 CC_SHA1_CTX ctx
; /* SHA-1 context */
79 if (hashsize
< CC_SHA1_DIGEST_LENGTH
)
83 CC_SHA1_Update(&ctx
, data
, (CC_LONG
)datalen
);
84 CC_SHA1_Final(hash
, &ctx
);
86 return (CC_SHA1_DIGEST_LENGTH
);
88 else if (!strcmp(algorithm
, "sha2-224"))
90 CC_SHA256_CTX ctx
; /* SHA-224 context */
92 if (hashsize
< CC_SHA224_DIGEST_LENGTH
)
96 CC_SHA224_Update(&ctx
, data
, (CC_LONG
)datalen
);
97 CC_SHA224_Final(hash
, &ctx
);
99 return (CC_SHA224_DIGEST_LENGTH
);
101 else if (!strcmp(algorithm
, "sha2-256"))
103 CC_SHA256_CTX ctx
; /* SHA-256 context */
105 if (hashsize
< CC_SHA256_DIGEST_LENGTH
)
108 CC_SHA256_Init(&ctx
);
109 CC_SHA256_Update(&ctx
, data
, (CC_LONG
)datalen
);
110 CC_SHA256_Final(hash
, &ctx
);
112 return (CC_SHA256_DIGEST_LENGTH
);
114 else if (!strcmp(algorithm
, "sha2-384"))
116 CC_SHA512_CTX ctx
; /* SHA-384 context */
118 if (hashsize
< CC_SHA384_DIGEST_LENGTH
)
121 CC_SHA384_Init(&ctx
);
122 CC_SHA384_Update(&ctx
, data
, (CC_LONG
)datalen
);
123 CC_SHA384_Final(hash
, &ctx
);
125 return (CC_SHA384_DIGEST_LENGTH
);
127 else if (!strcmp(algorithm
, "sha2-512"))
129 CC_SHA512_CTX ctx
; /* SHA-512 context */
131 if (hashsize
< CC_SHA512_DIGEST_LENGTH
)
134 CC_SHA512_Init(&ctx
);
135 CC_SHA512_Update(&ctx
, data
, (CC_LONG
)datalen
);
136 CC_SHA512_Final(hash
, &ctx
);
138 return (CC_SHA512_DIGEST_LENGTH
);
140 else if (!strcmp(algorithm
, "sha2-512_224"))
142 CC_SHA512_CTX ctx
; /* SHA-512 context */
143 unsigned char temp
[CC_SHA512_DIGEST_LENGTH
];
147 * SHA2-512 truncated to 224 bits (28 bytes)...
150 if (hashsize
< CC_SHA224_DIGEST_LENGTH
)
153 CC_SHA512_Init(&ctx
);
154 CC_SHA512_Update(&ctx
, data
, (CC_LONG
)datalen
);
155 CC_SHA512_Final(temp
, &ctx
);
157 memcpy(hash
, temp
, CC_SHA224_DIGEST_LENGTH
);
159 return (CC_SHA224_DIGEST_LENGTH
);
161 else if (!strcmp(algorithm
, "sha2-512_256"))
163 CC_SHA512_CTX ctx
; /* SHA-512 context */
164 unsigned char temp
[CC_SHA512_DIGEST_LENGTH
];
168 * SHA2-512 truncated to 256 bits (32 bytes)...
171 if (hashsize
< CC_SHA256_DIGEST_LENGTH
)
174 CC_SHA512_Init(&ctx
);
175 CC_SHA512_Update(&ctx
, data
, (CC_LONG
)datalen
);
176 CC_SHA512_Final(temp
, &ctx
);
178 memcpy(hash
, temp
, CC_SHA256_DIGEST_LENGTH
);
180 return (CC_SHA256_DIGEST_LENGTH
);
183 #elif defined(HAVE_GNUTLS)
184 gnutls_digest_algorithm_t alg
= GNUTLS_DIG_UNKNOWN
;
186 unsigned char temp
[64]; /* Temporary hash buffer */
187 size_t tempsize
= 0; /* Truncate to this size? */
190 if (!strcmp(algorithm
, "md5"))
193 * Some versions of GNU TLS disable MD5 without warning...
196 _cups_md5_state_t state
; /* MD5 state info */
201 _cupsMD5Init(&state
);
202 _cupsMD5Append(&state
, data
, datalen
);
203 _cupsMD5Finish(&state
, hash
);
207 else if (!strcmp(algorithm
, "sha"))
208 alg
= GNUTLS_DIG_SHA1
;
209 else if (!strcmp(algorithm
, "sha2-224"))
210 alg
= GNUTLS_DIG_SHA224
;
211 else if (!strcmp(algorithm
, "sha2-256"))
212 alg
= GNUTLS_DIG_SHA256
;
213 else if (!strcmp(algorithm
, "sha2-384"))
214 alg
= GNUTLS_DIG_SHA384
;
215 else if (!strcmp(algorithm
, "sha2-512"))
216 alg
= GNUTLS_DIG_SHA512
;
217 else if (!strcmp(algorithm
, "sha2-512_224"))
219 alg
= GNUTLS_DIG_SHA512
;
222 else if (!strcmp(algorithm
, "sha2-512_256"))
224 alg
= GNUTLS_DIG_SHA512
;
228 if (alg
!= GNUTLS_DIG_UNKNOWN
)
233 * Truncate result to tempsize bytes...
236 if (hashsize
< tempsize
)
239 gnutls_hash_fast(alg
, data
, datalen
, temp
);
240 memcpy(hash
, temp
, tempsize
);
242 return ((ssize_t
)tempsize
);
245 if (hashsize
< gnutls_hash_get_len(alg
))
248 gnutls_hash_fast(alg
, data
, datalen
, hash
);
250 return ((ssize_t
)gnutls_hash_get_len(alg
));
255 * No hash support beyond MD5 without CommonCrypto or GNU TLS...
258 if (!strcmp(algorithm
, "md5"))
260 _cups_md5_state_t state
; /* MD5 state info */
265 _cupsMD5Init(&state
);
266 _cupsMD5Append(&state
, data
, datalen
);
267 _cupsMD5Finish(&state
, hash
);
271 else if (hashsize
< 64)
273 #endif /* __APPLE__ */
276 * Unknown hash algorithm...
279 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Unknown hash algorithm."), 1);
284 * We get here if the buffer is too small.
289 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Hash buffer too small."), 1);
295 * 'cupsHashString()' - Format a hash value as a hexadecimal string.
297 * The passed buffer must be at least 2 * hashsize + 1 characters in length.
302 const char * /* O - Formatted string */
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 */
309 char *bufptr
= buffer
; /* Pointer into buffer */
310 static const char *hex
= "0123456789abcdef";
311 /* Hex characters (lowercase!) */
315 * Range check input...
318 if (!hash
|| hashsize
< 1 || !buffer
|| bufsize
< (2 * hashsize
+ 1))
326 * Loop until we've converted the whole hash...
331 *bufptr
++ = hex
[*hash
>> 4];
332 *bufptr
++ = hex
[*hash
& 15];