You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

342 lines
7.6 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
* Hashing function for CUPS.
*
* Copyright © 2015-2019 by Apple Inc.
*
* Licensed under Apache License v2.0. See the file "LICENSE" for more
* information.
*/
/*
* Include necessary headers...
*/
#include "cups-private.h"
#ifdef __APPLE__
# include <CommonCrypto/CommonDigest.h>
#elif defined(HAVE_GNUTLS)
# include <gnutls/crypto.h>
# include "md5-internal.h"
#else
# include "md5-internal.h"
#endif /* __APPLE__ */
/*
* 'cupsHashData()' - Perform a hash function on the given data.
*
* The "algorithm" argument can be any of the registered, non-deprecated IPP
* hash algorithms for the "job-password-encryption" attribute, including
* "sha" for SHA-1, "sha-256" for SHA2-256, etc.
*
* The "hash" argument points to a buffer of "hashsize" bytes and should be at
* least 64 bytes in length for all of the supported algorithms.
*
* The returned hash is binary data.
*
* @since CUPS 2.2/macOS 10.12@
*/
ssize_t /* O - Size of hash or -1 on error */
cupsHashData(const char *algorithm, /* I - Algorithm name */
const void *data, /* I - Data to hash */
size_t datalen, /* I - Length of data to hash */
unsigned char *hash, /* I - Hash buffer */
size_t hashsize) /* I - Size of hash buffer */
{
if (!algorithm || !data || datalen == 0 || !hash || hashsize == 0)
{
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad arguments to function"), 1);
return (-1);
}
#ifdef __APPLE__
if (!strcmp(algorithm, "md5"))
{
/*
* MD5 (deprecated but widely used...)
*/
CC_MD5_CTX ctx; /* MD5 context */
if (hashsize < CC_MD5_DIGEST_LENGTH)
goto too_small;
CC_MD5_Init(&ctx);
CC_MD5_Update(&ctx, data, (CC_LONG)datalen);
CC_MD5_Final(hash, &ctx);
return (CC_MD5_DIGEST_LENGTH);
}
else if (!strcmp(algorithm, "sha"))
{
/*
* SHA-1...
*/
CC_SHA1_CTX ctx; /* SHA-1 context */
if (hashsize < CC_SHA1_DIGEST_LENGTH)
goto too_small;
CC_SHA1_Init(&ctx);
CC_SHA1_Update(&ctx, data, (CC_LONG)datalen);
CC_SHA1_Final(hash, &ctx);
return (CC_SHA1_DIGEST_LENGTH);
}
else if (!strcmp(algorithm, "sha2-224"))
{
CC_SHA256_CTX ctx; /* SHA-224 context */
if (hashsize < CC_SHA224_DIGEST_LENGTH)
goto too_small;
CC_SHA224_Init(&ctx);
CC_SHA224_Update(&ctx, data, (CC_LONG)datalen);
CC_SHA224_Final(hash, &ctx);
return (CC_SHA224_DIGEST_LENGTH);
}
else if (!strcmp(algorithm, "sha2-256"))
{
CC_SHA256_CTX ctx; /* SHA-256 context */
if (hashsize < CC_SHA256_DIGEST_LENGTH)
goto too_small;
CC_SHA256_Init(&ctx);
CC_SHA256_Update(&ctx, data, (CC_LONG)datalen);
CC_SHA256_Final(hash, &ctx);
return (CC_SHA256_DIGEST_LENGTH);
}
else if (!strcmp(algorithm, "sha2-384"))
{
CC_SHA512_CTX ctx; /* SHA-384 context */
if (hashsize < CC_SHA384_DIGEST_LENGTH)
goto too_small;
CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx, data, (CC_LONG)datalen);
CC_SHA384_Final(hash, &ctx);
return (CC_SHA384_DIGEST_LENGTH);
}
else if (!strcmp(algorithm, "sha2-512"))
{
CC_SHA512_CTX ctx; /* SHA-512 context */
if (hashsize < CC_SHA512_DIGEST_LENGTH)
goto too_small;
CC_SHA512_Init(&ctx);
CC_SHA512_Update(&ctx, data, (CC_LONG)datalen);
CC_SHA512_Final(hash, &ctx);
return (CC_SHA512_DIGEST_LENGTH);
}
else if (!strcmp(algorithm, "sha2-512_224"))
{
CC_SHA512_CTX ctx; /* SHA-512 context */
unsigned char temp[CC_SHA512_DIGEST_LENGTH];
/* SHA-512 hash */
/*
* SHA2-512 truncated to 224 bits (28 bytes)...
*/
if (hashsize < CC_SHA224_DIGEST_LENGTH)
goto too_small;
CC_SHA512_Init(&ctx);
CC_SHA512_Update(&ctx, data, (CC_LONG)datalen);
CC_SHA512_Final(temp, &ctx);
memcpy(hash, temp, CC_SHA224_DIGEST_LENGTH);
return (CC_SHA224_DIGEST_LENGTH);
}
else if (!strcmp(algorithm, "sha2-512_256"))
{
CC_SHA512_CTX ctx; /* SHA-512 context */
unsigned char temp[CC_SHA512_DIGEST_LENGTH];
/* SHA-512 hash */
/*
* SHA2-512 truncated to 256 bits (32 bytes)...
*/
if (hashsize < CC_SHA256_DIGEST_LENGTH)
goto too_small;
CC_SHA512_Init(&ctx);
CC_SHA512_Update(&ctx, data, (CC_LONG)datalen);
CC_SHA512_Final(temp, &ctx);
memcpy(hash, temp, CC_SHA256_DIGEST_LENGTH);
return (CC_SHA256_DIGEST_LENGTH);
}
#elif defined(HAVE_GNUTLS)
gnutls_digest_algorithm_t alg = GNUTLS_DIG_UNKNOWN;
/* Algorithm */
unsigned char temp[64]; /* Temporary hash buffer */
size_t tempsize = 0; /* Truncate to this size? */
if (!strcmp(algorithm, "md5"))
{
/*
* Some versions of GNU TLS disable MD5 without warning...
*/
_cups_md5_state_t state; /* MD5 state info */
if (hashsize < 16)
goto too_small;
_cupsMD5Init(&state);
_cupsMD5Append(&state, data, datalen);
_cupsMD5Finish(&state, hash);
return (16);
}
else if (!strcmp(algorithm, "sha"))
alg = GNUTLS_DIG_SHA1;
else if (!strcmp(algorithm, "sha2-224"))
alg = GNUTLS_DIG_SHA224;
else if (!strcmp(algorithm, "sha2-256"))
alg = GNUTLS_DIG_SHA256;
else if (!strcmp(algorithm, "sha2-384"))
alg = GNUTLS_DIG_SHA384;
else if (!strcmp(algorithm, "sha2-512"))
alg = GNUTLS_DIG_SHA512;
else if (!strcmp(algorithm, "sha2-512_224"))
{
alg = GNUTLS_DIG_SHA512;
tempsize = 28;
}
else if (!strcmp(algorithm, "sha2-512_256"))
{
alg = GNUTLS_DIG_SHA512;
tempsize = 32;
}
if (alg != GNUTLS_DIG_UNKNOWN)
{
if (tempsize > 0)
{
/*
* Truncate result to tempsize bytes...
*/
if (hashsize < tempsize)
goto too_small;
gnutls_hash_fast(alg, data, datalen, temp);
memcpy(hash, temp, tempsize);
return ((ssize_t)tempsize);
}
if (hashsize < gnutls_hash_get_len(alg))
goto too_small;
gnutls_hash_fast(alg, data, datalen, hash);
return ((ssize_t)gnutls_hash_get_len(alg));
}
#else
/*
* No hash support beyond MD5 without CommonCrypto or GNU TLS...
*/
if (!strcmp(algorithm, "md5"))
{
_cups_md5_state_t state; /* MD5 state info */
if (hashsize < 16)
goto too_small;
_cupsMD5Init(&state);
_cupsMD5Append(&state, data, datalen);
_cupsMD5Finish(&state, hash);
return (16);
}
else if (hashsize < 64)
goto too_small;
#endif /* __APPLE__ */
/*
* Unknown hash algorithm...
*/
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown hash algorithm."), 1);
return (-1);
/*
* We get here if the buffer is too small.
*/
too_small:
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Hash buffer too small."), 1);
return (-1);
}
/*
* 'cupsHashString()' - Format a hash value as a hexadecimal string.
*
* The passed buffer must be at least 2 * hashsize + 1 characters in length.
*
* @since CUPS 2.2.7@
*/
const char * /* O - Formatted string */
cupsHashString(
const unsigned char *hash, /* I - Hash */
size_t hashsize, /* I - Size of hash */
char *buffer, /* I - String buffer */
size_t bufsize) /* I - Size of string buffer */
{
char *bufptr = buffer; /* Pointer into buffer */
static const char *hex = "0123456789abcdef";
/* Hex characters (lowercase!) */
/*
* Range check input...
*/
if (!hash || hashsize < 1 || !buffer || bufsize < (2 * hashsize + 1))
{
if (buffer)
*buffer = '\0';
return (NULL);
}
/*
* Loop until we've converted the whole hash...
*/
while (hashsize > 0)
{
*bufptr++ = hex[*hash >> 4];
*bufptr++ = hex[*hash & 15];
hash ++;
hashsize --;
}
*bufptr = '\0';
return (buffer);
}