/*
*  Naamari - an AES/SHA-based manual file crypto-synchronizer for cloud transfers
*  Copyright (c) 2015-2017 Sunkware
*  Key FP = 6B6D C8E9 3438 6E9C 3D97  56E5 2CE9 A476 99EF 28F6
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  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/>.
*
*  ----------------------------------------------------------------
*  WWW:       sunkware.org
*  E-mail:    sunkware@gmail.com
*  ----------------------------------------------------------------
*/

#include "hasher.h"

namespace cryptrav
{


Hasher::Hasher()
{
 contextP = new SHA256_CTX;
 sha256_clear(contextP);
}


// Here we implement the "h_d" method described in
//
// Niels Ferguson, Bruce Schneier, Tadayoshi Kohno.
// Cryptography Engineering: Design Principles and Practical Applications. --- Wiley Publishing, Inc., 2010.
// (see 5.4.2; motivation's in 5.3)
//
// Simply speaking, we calculate SHA-256 of (SHA-256 of (two 0-blocks + data)).


void           Hasher::init(void)
{
 quint8        zeros[SHA256_COMPRESSION_BLOCK_SIZE];

 memset(zeros, 0, SHA256_COMPRESSION_BLOCK_SIZE);

 sha256_clear(contextP);
 sha256_init(contextP);

 sha256_update(contextP, zeros, SHA256_COMPRESSION_BLOCK_SIZE);
}

void           Hasher::update(quint8* data, quint32 len)
{
 sha256_update(contextP, data, len);
}

void           Hasher::final(quint8* hash)
{
 quint8        inter_hash[HASH_SIZE];
 SHA256_CTX    inter_context;

 sha256_final(contextP, inter_hash);
 sha256_clear(contextP);

 sha256_init(&inter_context);

 sha256_update(&inter_context, inter_hash, HASH_SIZE);
 memset(inter_hash, 0, HASH_SIZE);

 sha256_final(&inter_context, hash); // the result is in hash
 sha256_clear(&inter_context);
}


void           Hasher::calc(quint8* data, quint32 len, quint8* hash)
{
 init();
 update(data, len);
 final(hash);
}


Hasher::~Hasher()
{
 sha256_clear(contextP);
 delete contextP;
}


} // namespace "cryptrav"
