#include "cups-private.h"
#ifdef __APPLE__
# include <CommonCrypto/CommonDigest.h>
#elif defined(HAVE_GNUTLS)
# include <gnutls/crypto.h>
#endif
ssize_t
cupsHashData(const char *algorithm,
const void *data,
size_t datalen,
unsigned char *hash,
size_t hashsize)
{
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, "sha"))
{
CC_SHA1_CTX ctx;
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;
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;
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;
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;
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;
unsigned char temp[CC_SHA512_DIGEST_LENGTH];
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;
unsigned char temp[CC_SHA512_DIGEST_LENGTH];
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;
unsigned char temp[64];
size_t tempsize = 0;
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)
{
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 (gnutls_hash_get_len(alg));
}
#else
if (hashsize < 64)
goto too_small;
#endif
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown hash algorithm."), 1);
return (-1);
too_small:
_cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Hash buffer too small."), 1);
return (-1);
}