85 lines
2.7 KiB
C
85 lines
2.7 KiB
C
/*
|
||
*
|
||
* Copyright (c) 2013
|
||
* ntldr <ntldr@diskcryptor.net> PGP key ID - 0x1B6A24550F33E44A
|
||
*
|
||
|
||
This program is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License version 3 as
|
||
published by the Free Software Foundation.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
#include <intrin.h>
|
||
#include "sha512_hmac.h"
|
||
|
||
void _stdcall sha512_hmac_init(sha512_hmac_ctx* ctx, const void* key, size_t keylen)
|
||
{
|
||
unsigned long i;
|
||
|
||
// zero-fill initial key state
|
||
memset(ctx->padded_key, 0, sizeof(ctx->padded_key));
|
||
|
||
// compress HMAC key if needed, or copy source key
|
||
if (keylen > SHA512_BLOCK_SIZE) {
|
||
sha512_init(&ctx->hash);
|
||
sha512_hash(&ctx->hash, (const unsigned char*)key, keylen);
|
||
sha512_done(&ctx->hash, ctx->padded_key);
|
||
} else {
|
||
memcpy(ctx->padded_key, key, keylen);
|
||
}
|
||
|
||
// start "inner" hash
|
||
for (i = 0; i < (SHA512_BLOCK_SIZE / 4); i++) {
|
||
((unsigned long*)ctx->padded_key)[i] ^= 0x36363636;
|
||
}
|
||
sha512_init(&ctx->hash);
|
||
sha512_hash(&ctx->hash, ctx->padded_key, SHA512_BLOCK_SIZE);
|
||
}
|
||
|
||
void _stdcall sha512_hmac_hash(sha512_hmac_ctx* ctx, const void* ptr, size_t length)
|
||
{
|
||
sha512_hash(&ctx->hash, (const unsigned char*)ptr, length);
|
||
}
|
||
|
||
void _stdcall sha512_hmac_done(sha512_hmac_ctx* ctx, unsigned char* out)
|
||
{
|
||
unsigned char inner_hash[SHA512_DIGEST_SIZE];
|
||
unsigned long i;
|
||
|
||
// finalize "inner" hash
|
||
sha512_done(&ctx->hash, inner_hash);
|
||
|
||
// calculate "outer" hash
|
||
for (i = 0; i < (SHA512_BLOCK_SIZE / 4); i++) {
|
||
((unsigned long*)ctx->padded_key)[i] ^= 0x6A6A6A6A; // 0x36 ^ 0x64 = 0x5С
|
||
}
|
||
sha512_init(&ctx->hash);
|
||
sha512_hash(&ctx->hash, ctx->padded_key, SHA512_BLOCK_SIZE);
|
||
sha512_hash(&ctx->hash, inner_hash, SHA512_DIGEST_SIZE);
|
||
sha512_done(&ctx->hash, out);
|
||
|
||
// prevent leaks
|
||
static_assert( !(sizeof(inner_hash) % sizeof(unsigned long)), "sizeof must be 4 byte aligned");
|
||
__stosd((unsigned long*)&inner_hash, 0, (sizeof(inner_hash) / sizeof(unsigned long)));
|
||
}
|
||
|
||
void _stdcall sha512_hmac(const void *k, size_t k_len, const void *d, size_t d_len, unsigned char *out)
|
||
{
|
||
sha512_hmac_ctx ctx;
|
||
|
||
sha512_hmac_init(&ctx, k, k_len);
|
||
sha512_hmac_hash(&ctx, d, d_len);
|
||
sha512_hmac_done(&ctx, out);
|
||
|
||
// prevent leaks
|
||
static_assert( !(sizeof(ctx) % sizeof(unsigned long)), "sizeof must be 4 byte aligned");
|
||
__stosd((unsigned long*)&ctx, 0, (sizeof(ctx) / sizeof(unsigned long)));
|
||
}
|