/*- * Copyright (c) 2001-2003 Allan Saddi * Copyright (c) 2012 Moinak Ghosh moinakg gm0il com * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Define WORDS_BIGENDIAN if compiling on a big-endian architecture. */ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #if HAVE_INTTYPES_H # include #else # if HAVE_STDINT_H # include # endif #endif #include #include #include #include "sha512.h" #ifdef WORDS_BIGENDIAN #define BYTESWAP(x) (x) #define BYTESWAP64(x) (x) #else /* WORDS_BIGENDIAN */ #define BYTESWAP(x) htonl(x) #define BYTESWAP64(x) htonll(x) #endif /* WORDS_BIGENDIAN */ typedef void (*update_func_ptr)(const void *input_data, void *digest, uint64_t num_blks); static const uint8_t padding[SHA512_BLOCK_SIZE] = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const uint64_t iv512[SHA512_HASH_WORDS] = { 0x6a09e667f3bcc908LL, 0xbb67ae8584caa73bLL, 0x3c6ef372fe94f82bLL, 0xa54ff53a5f1d36f1LL, 0x510e527fade682d1LL, 0x9b05688c2b3e6c1fLL, 0x1f83d9abfb41bd6bLL, 0x5be0cd19137e2179LL }; static const uint64_t iv256[SHA512_HASH_WORDS] = { 0x22312194fc2bf72cLL, 0x9f555fa3c84c64c2LL, 0x2393b86b6f53b151LL, 0x963877195940eabdLL, 0x96283ee2a88effe3LL, 0xbe5e1e2553863992LL, 0x2b0199fc2c85b8aaLL, 0x0eb72ddc81c52ca2LL }; static update_func_ptr sha512_update_func; int APS_NAMESPACE(Init_SHA512) (processor_info_t *pc) { if (pc->proc_type == PROC_X64_INTEL || pc->proc_type == PROC_X64_AMD) { if (pc->avx_level > 0) { sha512_update_func = sha512_avx; } else if (pc->sse_level >= 4) { sha512_update_func = sha512_sse4; } else { return (1); } return (0); } return (1); } static void _init (SHA512_Context *sc, const uint64_t iv[SHA512_HASH_WORDS]) { int i; sc->totalLength[0] = 0LL; sc->totalLength[1] = 0LL; for (i = 0; i < SHA512_HASH_WORDS; i++) sc->hash[i] = iv[i]; sc->bufferLength = 0L; } void APS_NAMESPACE(SHA512_Init) (SHA512_Context *sc) { _init (sc, iv512); } void APS_NAMESPACE(SHA512t256_Init) (SHA512_Context *sc) { _init (sc, iv256); } void APS_NAMESPACE(SHA512_Update) (SHA512_Context *sc, const void *vdata, size_t len) { const uint8_t *data = (const uint8_t *)vdata; uint32_t bufferBytesLeft; size_t bytesToCopy; int rem; uint64_t carryCheck; if (sc->bufferLength) { do { bufferBytesLeft = SHA512_BLOCK_SIZE - sc->bufferLength; bytesToCopy = bufferBytesLeft; if (bytesToCopy > len) bytesToCopy = len; memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy); carryCheck = sc->totalLength[1]; sc->totalLength[1] += bytesToCopy * 8L; if (sc->totalLength[1] < carryCheck) sc->totalLength[0]++; sc->bufferLength += bytesToCopy; data += bytesToCopy; len -= bytesToCopy; if (sc->bufferLength == SHA512_BLOCK_SIZE) { sc->blocks = 1; sha512_update_func(sc->buffer.words, sc->hash, sc->blocks); sc->bufferLength = 0L; } else { return; } } while (len > 0 && len <= SHA512_BLOCK_SIZE); if (!len) return; } sc->blocks = len >> 7; rem = len - (sc->blocks << 7); len = sc->blocks << 7; carryCheck = sc->totalLength[1]; sc->totalLength[1] += rem * 8L; if (sc->totalLength[1] < carryCheck) sc->totalLength[0]++; if (len) { carryCheck = sc->totalLength[1]; sc->totalLength[1] += len * 8L; if (sc->totalLength[1] < carryCheck) sc->totalLength[0]++; sha512_update_func((uint32_t *)data, sc->hash, sc->blocks); } if (rem) { memcpy (&sc->buffer.bytes[0], data + len, rem); sc->bufferLength = rem; } } void APS_NAMESPACE(SHA512t256_Update) (SHA512_Context *sc, const void *data, size_t len) { APS_NAMESPACE(SHA512_Update) (sc, data, len); } static void _final (SHA512_Context *sc, uint8_t *hash, int hashWords, int halfWord) { uint32_t bytesToPad; uint64_t lengthPad[2]; int i; bytesToPad = 240L - sc->bufferLength; if (bytesToPad > SHA512_BLOCK_SIZE) bytesToPad -= SHA512_BLOCK_SIZE; lengthPad[0] = BYTESWAP64(sc->totalLength[0]); lengthPad[1] = BYTESWAP64(sc->totalLength[1]); APS_NAMESPACE(SHA512_Update) (sc, padding, bytesToPad); APS_NAMESPACE(SHA512_Update) (sc, lengthPad, 16L); if (hash) { for (i = 0; i < hashWords; i++) { *((uint64_t *) hash) = BYTESWAP64(sc->hash[i]); hash += 8; } if (halfWord) { hash[0] = (uint8_t) (sc->hash[i] >> 56); hash[1] = (uint8_t) (sc->hash[i] >> 48); hash[2] = (uint8_t) (sc->hash[i] >> 40); hash[3] = (uint8_t) (sc->hash[i] >> 32); } } } void APS_NAMESPACE(SHA512_Final) (SHA512_Context *sc, uint8_t hash[SHA512_HASH_SIZE]) { _final (sc, hash, SHA512_HASH_WORDS, 0); } void APS_NAMESPACE(SHA512t256_Final) (SHA512_Context *sc, uint8_t hash[SHA512t256_HASH_SIZE]) { _final (sc, hash, SHA512t256_HASH_WORDS, 0); } #define HASH_CONTEXT SHA512_Context #define HASH_INIT APS_NAMESPACE(SHA512_Init) #define HASH_UPDATE APS_NAMESPACE(SHA512_Update) #define HASH_FINAL APS_NAMESPACE(SHA512_Final) #define HASH_SIZE SHA512_HASH_SIZE #define HASH_BLOCK_SIZE SHA512_BLOCK_SIZE #define HMAC_CONTEXT HMAC_SHA512_Context #define HMAC_INIT APS_NAMESPACE(HMAC_SHA512_Init) #define HMAC_UPDATE APS_NAMESPACE(HMAC_SHA512_Update) #define HMAC_FINAL APS_NAMESPACE(HMAC_SHA512_Final) #include "_hmac.c" #undef HASH_CONTEXT #undef HASH_INIT #undef HASH_UPDATE #undef HASH_FINAL #undef HASH_SIZE #undef HASH_BLOCK_SIZE #undef HMAC_CONTEXT #undef HMAC_INIT #undef HMAC_UPDATE #undef HMAC_FINAL #define HASH_CONTEXT SHA512_Context #define HASH_INIT APS_NAMESPACE(SHA512t256_Init) #define HASH_UPDATE APS_NAMESPACE(SHA512t256_Update) #define HASH_FINAL APS_NAMESPACE(SHA512t256_Final) #define HASH_SIZE SHA512t256_HASH_SIZE #define HASH_BLOCK_SIZE SHA512_BLOCK_SIZE #define HMAC_CONTEXT HMAC_SHA512_Context #define HMAC_INIT APS_NAMESPACE(HMAC_SHA512t256_Init) #define HMAC_UPDATE APS_NAMESPACE(HMAC_SHA512t256_Update) #define HMAC_FINAL APS_NAMESPACE(HMAC_SHA512t256_Final) #include "_hmac.c"