225 lines
8.1 KiB
C++
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;
|
|
}
|