Files
2024-05-18 23:53:26 +08:00

225 lines
8.1 KiB
C++

/**
* @file kSha1Hash.cpp
*
* @internal
* Copyright (C) 2017-2021 by LMI Technologies Inc. All rights reserved.
* This code is inspired by the Sha1 implementation in Ghostscript (which is in Public Domain)
* http://svn.ghostscript.com/jbig2dec/trunk/sha1.c
*/
#include <kApi/Crypto/kSha1Hash.h>
#include <kApi/Data/kString.h>
kBeginClassEx(k, kSha1Hash)
kAddPrivateVMethod(kSha1Hash, kObject, VRelease)
kAddPrivateVMethod(kSha1Hash, kHash, VUpdate)
kAddPrivateVMethod(kSha1Hash, kHash, VDigest)
kAddPrivateVMethod(kSha1Hash, kHash, VClear)
kAddPrivateVMethod(kSha1Hash, kHash, VDigestSize)
kEndClassEx()
/* SHA1 initialization vectors*/
static const k32u kSha1Hash_sha1state[] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xc3d2e1f0 };
static const k32u kSha1Hash_sha1k[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
#define kSHA1_ROL32(val,bits) (((val)<<(bits))|((val)>>(32-(bits))))
#if K_ENDIANNESS == kENDIANNESS_BIG
# define kSHA1_BLK0(i) block[i]
#else
# define kSHA1_BLK0(i) (block[i] = (kSHA1_ROL32(block[i], 24) & 0xFF00FF00) |(kSHA1_ROL32(block[i], 8) & 0x00FF00FF))
#endif
#define kSHA1_BLK(i) (block[i & 15] = \
kSHA1_ROL32(block[(i + 13) & 15] ^ block[(i+8) & 15] ^ block[(i + 2) & 15] ^ block[i&15], 1))
#define kSHA1_R0(v,w,x,y,z,i) z+=((w&(x^y))^y) + kSHA1_BLK0(i) + kSha1Hash_sha1k[0] + kSHA1_ROL32(v,5); w = kSHA1_ROL32(w,30);
#define kSHA1_R1(v,w,x,y,z,i) z+=((w&(x^y))^y) + kSHA1_BLK(i) + kSha1Hash_sha1k[0] + kSHA1_ROL32(v,5); w = kSHA1_ROL32(w,30);
#define kSHA1_R2(v,w,x,y,z,i) z+=(w^x^y) + kSHA1_BLK(i) + kSha1Hash_sha1k[1] + kSHA1_ROL32(v,5); w = kSHA1_ROL32(w,30);
#define kSHA1_R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x)) + kSHA1_BLK(i) + kSha1Hash_sha1k[2] + kSHA1_ROL32(v,5); w = kSHA1_ROL32(w,30);
#define kSHA1_R4(v,w,x,y,z,i) z+=(w^x^y) + kSHA1_BLK(i) + kSha1Hash_sha1k[3] + kSHA1_ROL32(v,5); w = kSHA1_ROL32(w,30);
kFx(kStatus) kSha1Hash_Construct(kSha1Hash* hash, kAlloc allocator)
{
kAlloc alloc = kAlloc_Fallback(allocator);
kStatus status;
kCheck(kAlloc_GetObject(alloc, kTypeOf(kSha1Hash), hash));
if (!kSuccess(status = xkSha1Hash_Init(*hash, kTypeOf(kSha1Hash), alloc)))
{
kAlloc_FreeRef(alloc, hash);
}
return status;
}
kFx(kStatus) xkSha1Hash_Init(kSha1Hash hash, kType type, kAlloc alloc)
{
kObjR(kSha1Hash, hash);
kStatus status = kOK;
kCheck(xkHash_Init(hash, type, alloc));
kTry
{
kTest(kHash_Clear(hash));
}
kCatch(&status)
{
xkSha1Hash_VRelease(hash);
kEndCatch(status);
}
return kOK;
}
kFx(kStatus) xkSha1Hash_VRelease(kSha1Hash hash)
{
return xkHash_VRelease(hash);
}
kFx(kStatus) xkSha1Hash_VUpdate(kSha1Hash hash, const void* buffer, kSize size)
{
kObj(kSha1Hash, hash);
return xkSha1Hash_UpdateBuffer(obj->count, obj->state, obj->buffer, buffer, size);
}
kFx(kStatus) xkSha1Hash_VDigest(kSha1Hash hash, void* buffer, kSize size)
{
kObj(kSha1Hash, hash);
kByte finalCount[8];
kSize i;
k32u state[xkSHA1_HASH_STATE_SIZE];
kSize count[xkSHA1_HASH_COUNT_SIZE];
kByte hashBuffer[xkSHA1_HASH_BUFFER_SIZE];
kByte* bufferWriter = (kByte*) buffer;
if (size < kHash_DigestSize(hash))
{
return kERROR_INCOMPLETE;
}
/* Copy current state to local buffers so kHash_Update still can be called afterwards. */
kCheck(kMemCopy(state, obj->state, sizeof(state)));
kCheck(kMemCopy(count, obj->count, sizeof(count)));
kCheck(kMemCopy(hashBuffer, obj->buffer, xkSHA1_HASH_BUFFER_SIZE));
/* Take care of endianess */
for (i = 0; i < kCountOf(finalCount); i++)
{
finalCount[i] = (k8u)((count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255);
}
/* Add padding */
kCheck(xkSha1Hash_UpdateBuffer(count, state, hashBuffer, "\200", 1));
while ((count[0] & 504) != 448)
{
kCheck(xkSha1Hash_UpdateBuffer(count, state, hashBuffer, "\0", 1));
}
/* Could cause a call of xkSha1Hash_Transform */
kCheck(xkSha1Hash_UpdateBuffer(count, state, hashBuffer, finalCount, kCountOf(finalCount)));
/* Take care of endianess */
for (i = 0; i < xkSHA1_HASH_DIGEST_SIZE; i++)
{
bufferWriter[i] = (kByte)((state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
}
return kOK;
}
kFx(kSize) xkSha1Hash_VDigestSize(kSha1Hash hash)
{
return xkSHA1_HASH_DIGEST_SIZE;
}
kFx(kStatus) xkSha1Hash_VClear(kSha1Hash hash)
{
kObj(kSha1Hash, hash);
kCheck(kMemCopy(obj->state, kSha1Hash_sha1state, sizeof(obj->state)));
kCheck(kMemSet(obj->count, 0, sizeof(obj->count)));
kCheck(kMemSet(obj->buffer, 0, xkSHA1_HASH_BUFFER_SIZE));
return kOK;
}
kFx(void) xkSha1Hash_Transform(k32u* state5, const kByte *buffer64)
{
k32u* block = (k32u*)buffer64;
k32u a = state5[0];
k32u b = state5[1];
k32u c = state5[2];
k32u d = state5[3];
k32u e = state5[4];
kSHA1_R0(a, b, c, d, e, 0); kSHA1_R0(e, a, b, c, d, 1); kSHA1_R0(d, e, a, b, c, 2); kSHA1_R0(c, d, e, a, b, 3);
kSHA1_R0(b, c, d, e, a, 4); kSHA1_R0(a, b, c, d, e, 5); kSHA1_R0(e, a, b, c, d, 6); kSHA1_R0(d, e, a, b, c, 7);
kSHA1_R0(c, d, e, a, b, 8); kSHA1_R0(b, c, d, e, a, 9); kSHA1_R0(a, b, c, d, e, 10); kSHA1_R0(e, a, b, c, d, 11);
kSHA1_R0(d, e, a, b, c, 12); kSHA1_R0(c, d, e, a, b, 13); kSHA1_R0(b, c, d, e, a, 14); kSHA1_R0(a, b, c, d, e, 15);
kSHA1_R1(e, a, b, c, d, 16); kSHA1_R1(d, e, a, b, c, 17); kSHA1_R1(c, d, e, a, b, 18); kSHA1_R1(b, c, d, e, a, 19);
kSHA1_R2(a, b, c, d, e, 20); kSHA1_R2(e, a, b, c, d, 21); kSHA1_R2(d, e, a, b, c, 22); kSHA1_R2(c, d, e, a, b, 23);
kSHA1_R2(b, c, d, e, a, 24); kSHA1_R2(a, b, c, d, e, 25); kSHA1_R2(e, a, b, c, d, 26); kSHA1_R2(d, e, a, b, c, 27);
kSHA1_R2(c, d, e, a, b, 28); kSHA1_R2(b, c, d, e, a, 29); kSHA1_R2(a, b, c, d, e, 30); kSHA1_R2(e, a, b, c, d, 31);
kSHA1_R2(d, e, a, b, c, 32); kSHA1_R2(c, d, e, a, b, 33); kSHA1_R2(b, c, d, e, a, 34); kSHA1_R2(a, b, c, d, e, 35);
kSHA1_R2(e, a, b, c, d, 36); kSHA1_R2(d, e, a, b, c, 37); kSHA1_R2(c, d, e, a, b, 38); kSHA1_R2(b, c, d, e, a, 39);
kSHA1_R3(a, b, c, d, e, 40); kSHA1_R3(e, a, b, c, d, 41); kSHA1_R3(d, e, a, b, c, 42); kSHA1_R3(c, d, e, a, b, 43);
kSHA1_R3(b, c, d, e, a, 44); kSHA1_R3(a, b, c, d, e, 45); kSHA1_R3(e, a, b, c, d, 46); kSHA1_R3(d, e, a, b, c, 47);
kSHA1_R3(c, d, e, a, b, 48); kSHA1_R3(b, c, d, e, a, 49); kSHA1_R3(a, b, c, d, e, 50); kSHA1_R3(e, a, b, c, d, 51);
kSHA1_R3(d, e, a, b, c, 52); kSHA1_R3(c, d, e, a, b, 53); kSHA1_R3(b, c, d, e, a, 54); kSHA1_R3(a, b, c, d, e, 55);
kSHA1_R3(e, a, b, c, d, 56); kSHA1_R3(d, e, a, b, c, 57); kSHA1_R3(c, d, e, a, b, 58); kSHA1_R3(b, c, d, e, a, 59);
kSHA1_R4(a, b, c, d, e, 60); kSHA1_R4(e, a, b, c, d, 61); kSHA1_R4(d, e, a, b, c, 62); kSHA1_R4(c, d, e, a, b, 63);
kSHA1_R4(b, c, d, e, a, 64); kSHA1_R4(a, b, c, d, e, 65); kSHA1_R4(e, a, b, c, d, 66); kSHA1_R4(d, e, a, b, c, 67);
kSHA1_R4(c, d, e, a, b, 68); kSHA1_R4(b, c, d, e, a, 69); kSHA1_R4(a, b, c, d, e, 70); kSHA1_R4(e, a, b, c, d, 71);
kSHA1_R4(d, e, a, b, c, 72); kSHA1_R4(c, d, e, a, b, 73); kSHA1_R4(b, c, d, e, a, 74); kSHA1_R4(a, b, c, d, e, 75);
kSHA1_R4(e, a, b, c, d, 76); kSHA1_R4(d, e, a, b, c, 77); kSHA1_R4(c, d, e, a, b, 78); kSHA1_R4(b, c, d, e, a, 79);
state5[0] += a;
state5[1] += b;
state5[2] += c;
state5[3] += d;
state5[4] += e;
}
kFx(kStatus) xkSha1Hash_UpdateBuffer(kSize* count2, k32u* state5, kByte* bufferToUpdate64, const void* buffer, kSize size)
{
const kByte* data = (const kByte*) buffer;
kSize i, j;
j = (count2[0] >> 3) & 63;
if ((count2[0] += size << 3) < (size << 3))
{
count2[1]++;
}
count2[1] += (size >> 29);
if ((j + size) > 63)
{
kCheck(kMemCopy(&bufferToUpdate64[j], data, (64 - j)));
xkSha1Hash_Transform(state5, bufferToUpdate64);
for (i = 64 - j; i + 63 < size; i += 64)
{
xkSha1Hash_Transform(state5, data + i);
}
j = 0;
}
else
{
i = 0;
}
kCheck(kMemCopy(&bufferToUpdate64[j], &data[i], size - i));
return kOK;
}