sha512.c revision 9dc0df1bac950d6e491f9a7c7e4888f2b301cb15
/* ====================================================================
* Copyright (c) 2004 The OpenSSL Project. All rights reserved
* according to the OpenSSL license [found in ../../LICENSE].
* ====================================================================
*/
#include <openssl/opensslconf.h>
#if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA512)
/*
* IMPLEMENTATION NOTES.
*
* As you might have noticed 32-bit hash algorithms:
*
* - permit SHA_LONG to be wider than 32-bit (case on CRAY);
* - optimized versions implement two transform functions: one operating
* on [aligned] data in host byte order and one - on data in input
* stream byte order;
* - share common byte-order neutral collector and padding function
* implementations, ../md32_common.h;
*
* Neither of the above applies to this SHA-512 implementations. Reasons
* [in reverse order] are:
*
* - it's the only 64-bit hash algorithm for the moment of this writing,
* - by supporting only one transform function [which operates on
* *aligned* data in input stream byte order, big-endian in this case]
* function is simpler; b) only one transform function to stare at;
* - SHA_LONG64 is required to be exactly 64-bit in order to be able to
* apply a number of optimizations to mitigate potential performance
* penalties caused by previous design decision;
*
* Caveat lector.
*
* Implementation relies on the fact that "long long" is 64-bit on
* both 32- and 64-bit platforms. If some compiler vendor comes up
* with 128-bit long long, adjustment to sha.h would be required.
* As this implementation relies on 64-bit integer type, it's totally
* inappropriate for platforms which don't support it, most notably
* 16-bit platforms.
* <appro@fy.chalmers.se>
*/
#include <stdlib.h>
#include <string.h>
#include <openssl/opensslv.h>
#include "cryptlib.h"
#endif
int SHA384_Init (SHA512_CTX *c)
{
c->h[0]=U64(0xcbbb9d5dc1059ed8);
return 1;
}
int SHA512_Init (SHA512_CTX *c)
{
c->h[0]=U64(0x6a09e667f3bcc908);
return 1;
}
#ifndef SHA512_ASM
static
#endif
{
unsigned char *p=(unsigned char *)c->u.p;
p[n]=0x80; /* There always is a room for one */
n++;
if (n > (sizeof(c->u)-16))
memset (p+n,0,sizeof(c->u)-n), n=0,
sha512_block (c,p,1);
memset (p+n,0,sizeof(c->u)-16-n);
#ifdef B_ENDIAN
#else
p[sizeof(c->u)-1] = (unsigned char)(c->Nl);
p[sizeof(c->u)-9] = (unsigned char)(c->Nh);
#endif
sha512_block (c,p,1);
if (md==0) return 0;
switch (c->md_len)
{
/* Let compiler decide if it's appropriate to unroll... */
case SHA384_DIGEST_LENGTH:
for (n=0;n<SHA384_DIGEST_LENGTH/8;n++)
{
SHA_LONG64 t = c->h[n];
*(md++) = (unsigned char)(t>>56);
*(md++) = (unsigned char)(t>>48);
*(md++) = (unsigned char)(t>>40);
*(md++) = (unsigned char)(t>>32);
*(md++) = (unsigned char)(t>>24);
*(md++) = (unsigned char)(t>>16);
*(md++) = (unsigned char)(t>>8);
*(md++) = (unsigned char)(t);
}
break;
case SHA512_DIGEST_LENGTH:
for (n=0;n<SHA512_DIGEST_LENGTH/8;n++)
{
SHA_LONG64 t = c->h[n];
*(md++) = (unsigned char)(t>>56);
*(md++) = (unsigned char)(t>>48);
*(md++) = (unsigned char)(t>>40);
*(md++) = (unsigned char)(t>>32);
*(md++) = (unsigned char)(t>>24);
*(md++) = (unsigned char)(t>>16);
*(md++) = (unsigned char)(t>>8);
*(md++) = (unsigned char)(t);
}
break;
/* ... as well as make sure md_len is not abused. */
default: return 0;
}
return 1;
}
{ return SHA512_Final (md,c); }
{
SHA_LONG64 l;
unsigned char *p=c->u.p;
if (len==0) return 1;
c->Nl=l;
if (c->num != 0)
{
if (len < n)
{
return 1;
}
else {
sha512_block (c,p,1);
}
}
if (len >= sizeof(c->u))
{
while (len >= sizeof(c->u))
sha512_block (c,p,1),
len -= sizeof(c->u),
data += sizeof(c->u);
else
#endif
len %= sizeof(c->u),
}
return 1;
}
{
SHA512_CTX c;
static unsigned char m[SHA384_DIGEST_LENGTH];
SHA384_Init(&c);
SHA512_Update(&c,d,n);
SHA512_Final(md,&c);
OPENSSL_cleanse(&c,sizeof(c));
return(md);
}
{
SHA512_CTX c;
static unsigned char m[SHA512_DIGEST_LENGTH];
SHA512_Init(&c);
SHA512_Update(&c,d,n);
SHA512_Final(md,&c);
OPENSSL_cleanse(&c,sizeof(c));
return(md);
}
#ifndef SHA512_ASM
#ifndef PEDANTIC
# if defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
# if defined(__x86_64) || defined(__x86_64__)
asm ("bswapq %0" \
: "=r"(ret) \
# endif
# endif
#endif
#ifndef PULL64
#endif
#ifndef PEDANTIC
# if defined(_MSC_VER)
# if defined(_WIN64) /* applies to both IA-64 and AMD64 */
# endif
# elif defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM)
# if defined(__x86_64) || defined(__x86_64__)
asm ("rorq %1,%0" \
: "=r"(ret) \
: "J"(n),"0"(a) \
: "cc"); ret; })
asm ("rotrdi %0,%1,%2" \
: "=r"(ret) \
# endif
# endif
#endif
#ifndef ROTR
#define ROTR(x,s) (((x)>>s) | (x)<<(64-s))
#endif
#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
void sha512_block_sse2(void *,const void *,size_t); \
} while (0)
#endif
#ifdef OPENSSL_SMALL_FOOTPRINT
{
const SHA_LONG64 *W=in;
SHA_LONG64 X[16];
int i;
#ifdef GO_FOR_SSE2
#endif
while (num--) {
for (i=0;i<16;i++)
{
#ifdef B_ENDIAN
T1 = X[i] = W[i];
#else
#endif
h = g; g = f; f = e; e = d + T1;
}
for (;i<80;i++)
{
h = g; g = f; f = e; e = d + T1;
}
W+=SHA_LBLOCK;
}
}
#else
#define ROUND_00_15(i,a,b,c,d,e,f,g,h) do { \
#define ROUND_16_80(i,a,b,c,d,e,f,g,h,X) do { \
ROUND_00_15(i,a,b,c,d,e,f,g,h); } while (0)
{
const SHA_LONG64 *W=in;
SHA_LONG64 X[16];
int i;
#ifdef GO_FOR_SSE2
#endif
while (num--) {
#ifdef B_ENDIAN
T1 = X[0] = W[0]; ROUND_00_15(0,a,b,c,d,e,f,g,h);
#else
#endif
for (i=16;i<80;i+=8)
{
ROUND_16_80(i+0,a,b,c,d,e,f,g,h,X);
ROUND_16_80(i+1,h,a,b,c,d,e,f,g,X);
ROUND_16_80(i+2,g,h,a,b,c,d,e,f,X);
ROUND_16_80(i+3,f,g,h,a,b,c,d,e,X);
ROUND_16_80(i+4,e,f,g,h,a,b,c,d,X);
ROUND_16_80(i+5,d,e,f,g,h,a,b,c,X);
ROUND_16_80(i+6,c,d,e,f,g,h,a,b,X);
ROUND_16_80(i+7,b,c,d,e,f,g,h,a,X);
}
W+=SHA_LBLOCK;
}
}
#endif
#endif /* SHA512_ASM */
#endif /* OPENSSL_NO_SHA512 */