void psSha512Update(psDigestContext_t *md, const unsigned char *buf, uint32 len) { uint32 n; psAssert(md != NULL); psAssert(buf != NULL); while (len > 0) { if (md->sha512.curlen == 0 && len >= 128) { sha512_compress(md, (unsigned char *)buf); md->sha512.length += 1024; buf += 128; len -= 128; } else { n = min(len, (128 - md->sha512.curlen)); memcpy(md->sha512.buf + md->sha512.curlen, buf, (size_t)n); md->sha512.curlen += n; buf += n; len -= n; if (md->sha512.curlen == 128) { sha512_compress (md, md->sha512.buf); md->sha512.length += 1024; md->sha512.curlen = 0; } } } return; }
void sha512_hash(const uint8_t *message, uint32_t len, uint64_t hash[8]) { hash[0] = UINT64_C(0x6A09E667F3BCC908); hash[1] = UINT64_C(0xBB67AE8584CAA73B); hash[2] = UINT64_C(0x3C6EF372FE94F82B); hash[3] = UINT64_C(0xA54FF53A5F1D36F1); hash[4] = UINT64_C(0x510E527FADE682D1); hash[5] = UINT64_C(0x9B05688C2B3E6C1F); hash[6] = UINT64_C(0x1F83D9ABFB41BD6B); hash[7] = UINT64_C(0x5BE0CD19137E2179); uint32_t i; for (i = 0; len - i >= 128; i += 128) sha512_compress(hash, message + i); uint8_t block[128]; uint32_t rem = len - i; memcpy(block, message + i, rem); block[rem] = 0x80; rem++; if (128 - rem >= 16) memset(block + rem, 0, 120 - rem); else { memset(block + rem, 0, 128 - rem); sha512_compress(hash, block); memset(block, 0, 120); } uint64_t longLen = ((uint64_t)len) << 3; for (i = 0; i < 8; i++) block[128 - 1 - i] = (uint8_t)(longLen >> (i * 8)); sha512_compress(hash, block); }
/* Process a block of memory though the hash */ void _stdcall sha512_hash(sha512_ctx *ctx, const unsigned char *in, size_t inlen) { size_t n; while (inlen > 0) { if (ctx->curlen == 0 && inlen >= SHA512_BLOCK_SIZE) { sha512_compress(ctx, in); ctx->length += SHA512_BLOCK_SIZE * 8; in += SHA512_BLOCK_SIZE; inlen -= SHA512_BLOCK_SIZE; } else { n = min(inlen, (SHA512_BLOCK_SIZE - ctx->curlen)); memcpy(ctx->buf + ctx->curlen, in, n); ctx->curlen += n; in += n; inlen -= n; if (ctx->curlen == SHA512_BLOCK_SIZE) { sha512_compress(ctx, ctx->buf); ctx->length += 8 * SHA512_BLOCK_SIZE; ctx->curlen = 0; } } } }
int sha512_process(hash_state * md, const unsigned char *in, unsigned long inlen) { unsigned long n; int err; LTC_ARGCHK(md != NULL); LTC_ARGCHK(in != NULL); if (md-> sha512 .curlen > sizeof(md-> sha512 .buf)) { return CRYPT_INVALID_ARG; } while (inlen > 0) { if (md-> sha512 .curlen == 0 && inlen >= 128) { if ((err = sha512_compress(md, (unsigned char *)in)) != CRYPT_OK) { return err; } md-> sha512 .length += 128 * 8; in += 128; inlen -= 128; } else { n = MIN(inlen, (128 - md-> sha512 .curlen)); memcpy(md-> sha512 .buf + md-> sha512.curlen, in, (size_t)n); md-> sha512 .curlen += n; in += n; inlen -= n; if (md-> sha512 .curlen == 128) { if ((err = sha512_compress(md, md-> sha512 .buf)) != CRYPT_OK) { return err; } md-> sha512 .length += 8*128; md-> sha512 .curlen = 0; } } } return CRYPT_OK; }
/** Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (64 bytes) @return 0 if successful */ int sha512_final(sha512_context *md, void *vout) { unsigned char *out = vout; int i; if (md == NULL) return 1; if (out == NULL) return 1; if (md->curlen >= sizeof(md->buf)) { return 1; } /* increase the length of the message */ md->length += md->curlen * UINT64_C(8); /* append the '1' bit */ md->buf[md->curlen++] = 0x80; /* if the length is currently above 112 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if (md->curlen > 112) { while (md->curlen < 128) { md->buf[md->curlen++] = 0; } sha512_compress(md, md->buf); md->curlen = 0; } /* pad upto 120 bytes of zeroes * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash * > 2^64 bits of data... :-) */ while (md->curlen < 120) { md->buf[md->curlen++] = 0; } /* store length */ STORE64H(md->length, md->buf + 120); sha512_compress(md, md->buf); /* copy output */ for (i = 0; i < 8; i++) { STORE64H(md->state[i], out + (8 * i)); } return 0; }
/** Terminate the hash to get the digest @param md The hash state @param out [out] The destination of the hash (64 bytes) @return CRYPT_OK if successful */ int sha512_done(hash_state * md, unsigned char *out) { int i; LTC_ARGCHK(md != NULL); LTC_ARGCHK(out != NULL); if (md->sha512.curlen >= sizeof(md->sha512.buf)) { return CRYPT_INVALID_ARG; } /* increase the length of the message */ md->sha512.length += md->sha512.curlen * CONST64(8); /* append the '1' bit */ md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80; /* if the length is currently above 112 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if (md->sha512.curlen > 112) { while (md->sha512.curlen < 128) { md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; } sha512_compress(md, md->sha512.buf); md->sha512.curlen = 0; } /* pad upto 120 bytes of zeroes * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash * > 2^64 bits of data... :-) */ while (md->sha512.curlen < 120) { md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; } /* store length */ STORE64H(md->sha512.length, md->sha512.buf+120); sha512_compress(md, md->sha512.buf); /* copy output */ for (i = 0; i < 8; i++) { STORE64H(md->sha512.state[i], out+(8*i)); } #ifdef LTC_CLEAN_STACK zeromem(md, sizeof(hash_state)); #endif return CRYPT_OK; }
int32 psSha512Final(psDigestContext_t * md, unsigned char *out) { int i; psAssert(md != NULL); psAssert(out != NULL); if (md->sha512.curlen >= sizeof(md->sha512.buf)) { return PS_ARG_FAIL; } /* increase the length of the message */ md->sha512.length += md->sha512.curlen * CONST64(8); /* append the '1' bit */ md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80; /* if the length is currently above 112 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if (md->sha512.curlen > 112) { while (md->sha512.curlen < 128) { md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; } sha512_compress(md, md->sha512.buf); md->sha512.curlen = 0; } /* pad upto 120 bytes of zeroes * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash * > 2^64 bits of data... :-) */ while (md->sha512.curlen < 120) { md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; } /* store length */ STORE64H(md->sha512.length, md->sha512.buf+120); sha512_compress(md, md->sha512.buf); /* copy output */ for (i = 0; i < 8; i++) { STORE64H(md->sha512.state[i], out+(8*i)); } #ifdef USE_BURN_STACK psBurnStack(sizeof(psDigestContext_t)); #endif return SHA512_HASH_SIZE; }
/** Process a block of memory though the hash @param md The hash state @param in The data to hash @param inlen The length of the data (octets) @return 0 if successful */ int sha512_update(sha512_context *md, const void *vin, size_t inlen) { const unsigned char *in = vin; size_t n; size_t i; int err; if (md == NULL) return 1; if (in == NULL) return 1; if (md->curlen > sizeof(md->buf)) { return 1; } while (inlen > 0) { if (md->curlen == 0 && inlen >= 128) { if ((err = sha512_compress(md, in)) != 0) { return err; } md->length += 128 * 8; in += 128; inlen -= 128; } else { n = MIN(inlen, (128 - md->curlen)); for (i = 0; i < n; i++) { md->buf[i + md->curlen] = in[i]; } md->curlen += n; in += n; inlen -= n; if (md->curlen == 128) { if ((err = sha512_compress(md, md->buf)) != 0) { return err; } md->length += 8 * 128; md->curlen = 0; } } } return 0; }
/** Terminate the hash to get the digest */ void _stdcall sha512_done(sha512_ctx *ctx, unsigned char *out) { int i; /* increase the length of the message */ ctx->length += ctx->curlen * 8; /* append the '1' bit */ ctx->buf[ctx->curlen++] = 0x80; /* if the length is currently above 112 bytes we append zeros * then compress. Then we can fall back to padding zeros and length * encoding like normal. */ if (ctx->curlen > 112) { while (ctx->curlen < SHA512_BLOCK_SIZE) { ctx->buf[ctx->curlen++] = 0; } sha512_compress(ctx, ctx->buf); ctx->curlen = 0; } /* pad upto 120 bytes of zeroes * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash * > 2^64 bits of data... :-) */ while (ctx->curlen < 120) { ctx->buf[ctx->curlen++] = 0; } /* store length */ p64(ctx->buf)[15] = BE64(ctx->length); sha512_compress(ctx, ctx->buf); /* copy output */ for (i = 0; i < 8; i++) { p64(out)[i] = BE64(ctx->hash[i]); } }
int main(int argc, char **argv) { if (!self_check()) { printf("Self-check failed\n"); return 1; } printf("Self-check passed\n"); // Benchmark speed uint64_t state[8] = {}; uint64_t block[16] = {}; const int N = 3000000; clock_t start_time = clock(); int i; for (i = 0; i < N; i++) sha512_compress(state, (uint8_t *)block); // Type-punning printf("Speed: %.1f MiB/s\n", (double)N * sizeof(block) / (clock() - start_time) * CLOCKS_PER_SEC / 1048576); return 0; }