// MakeSHA384.cpp: CMakeSHA384 クラスのインプリメンテーション
//
////////////////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MakeSHA384.h"


// SHA384は hinit と 出力するハッシュ(h0〜h5) 以外はSHA512と全く同じアルゴリズムである
void MakeSHA512Helper_c(const void *pBuffer, void *hash, DWORD len);
extern "C" void CDECL MakeSHA512Helper_asm(const void *pBuffer, void *hash, DWORD len);

static const QWORD hinit[] = {
    0xCBBB9D5DC1059ED8, 0x629A292A367CD507, 0x9159015A3070DD17, 0x152FECD8F70E5939,
    0x67332667FFC00B31, 0x8EB44A8768581511, 0xDB0C2E0D64F98FA7, 0x47B5481DBEFA4FA4
};



////////////////////////////////////////////////////////////////////////////////////////////////////

CMakeSHA384::CMakeSHA384()
{
    Initialize();
}

CMakeSHA384::~CMakeSHA384()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void CMakeSHA384::Initialize()
{
    CMakeHashAlgorithm::Initialize();
    memcpy(m_pHash, hinit, 64);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void CMakeSHA384::ComputeHashFinalHelper(void *msg_digest)
{
    BYTE buf[256], hash[64];
    DWORD len;
    QWORD string_bit_len;

    memcpy(hash, m_pHash, 64);

    len = m_dwRestLen;
    memcpy(buf, m_pRest, len);
    buf[len++] = 0x80;
    if ( len < 112 )
        memset(buf+len, 0, 112-len), len=112;
    else if ( len > 112 )
        memset(buf+len, 0, 240-len), len=240;
    string_bit_len = m_qwSrcLen * 8;
    memset(buf+len, 0, sizeof(QWORD));
    ReverseEndian64(buf+len+8, &string_bit_len, 8);
    len += 16;
    ComputeHashHelper(buf, hash, len);

    ReverseEndian64(msg_digest, hash, 48);
}

DWORD CMakeSHA384::ComputeHashHelper(const void *pBuffer, void *msg_digest, DWORD len)
{
#if (USE_ASSEMBLER_SHA384==0)
    MakeSHA512Helper_c(pBuffer, msg_digest, len);
#else
    MakeSHA512Helper_asm(pBuffer, msg_digest, len);
#endif
    return len % 128;
}



////////////////////////////////////////////////////////////////////////////////////////////////////
// test

BOOL CMakeSHA384::Test()
{
    static const char *q1 = "abc";
    static const char *q2 =
        "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";

    static const char *a0 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
    static const char *a1 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
    static const char *a2 = "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039";
    static const char *a3 = "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985";


    Initialize();
    if ( CmpHashValue(a0) ) {
        ASSERT(0);
        return FALSE;
    }

    Initialize();
    ComputeHash(q1, strlen(q1));
    if ( CmpHashValue(a1) ) {
        ASSERT(0);
        return FALSE;
    }

    Initialize();
    ComputeHash(q2, strlen(q2));
    if ( CmpHashValue(a2) ) {
        ASSERT(0);
        return FALSE;
    }

    Initialize();
    BYTE *pQ3=new BYTE[1000000];
    memset(pQ3, 'a', 1000000);
    ComputeHash(pQ3, 1000000);
    delete [] pQ3;
    if ( CmpHashValue(a3) ) {
        ASSERT(0);
        return FALSE;
    }

    return TRUE;
}

