/****************************************************************************
**
** This file is part of GAP, a system for computational discrete algebra.
**
** Copyright of GAP belongs to its developers, whose names are too numerous
** to list here. Please refer to the COPYRIGHT file for details.
**
** SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "sha256.h"
#include "bool.h"
#include "error.h"
#include "integer.h"
#include "modules.h"
#include "objects.h"
#include "plist.h"
#include "stringobj.h"
#include "config.h"
#include <string.h>
static Obj GAP_SHA256_State_Type;
// Implements the SHA256 hash function as per the description in
// https://web.archive.org/web/20130526224224/http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf
//
// For the moment we assume the input is a string, we should probably have a
// list of bytes, or words or something
static inline UInt4 RotateRight(UInt4 x, const UInt4 n)
{
return (x >> n) | (x << (32 - n));
}
static inline UInt4 Ch(UInt4 x, UInt4 y, UInt4 z)
{
return (x & y) ^ (~x & z);
}
static inline UInt4 Maj(UInt4 x, UInt4 y, UInt4 z)
{
return (x & y) ^ (x & z) ^ (y & z);
}
static inline UInt4 Sigma0(UInt4 x)
{
return RotateRight(x, 2) ^ RotateRight(x, 13) ^ RotateRight(x, 22);
}
static inline UInt4 Sigma1(UInt4 x)
{
return RotateRight(x, 6) ^ RotateRight(x, 11) ^ RotateRight(x, 25);
}
static inline UInt4 sigma0(UInt4 x)
{
return RotateRight(x, 7) ^ RotateRight(x, 18) ^ (x >> 3);
}
static inline UInt4 sigma1(UInt4 x)
{
return RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10);
}
static const UInt4 k[] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
static const UInt4 rinit[] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
#ifdef WORDS_BIGENDIAN
#define be32decode(dst, src, len) memcpy(dst, src, len)
#define be32encode(dst, src, len) memcpy(dst, src, len)
#define store64be(dst, x) *dst = x
#else
static void be32decode(UInt4 * dst, const UInt1 * src, UInt len)
{
UInt i;
for (i = 0; i < (len >> 2); i++) {
dst[i] = (src[i * 4] << 24) | (src[i * 4 + 1] << 16) |
(src[i * 4 + 2] << 8) | (src[i * 4 + 3]);
}
}
static void be32encode(UInt1 * dst, const UInt4 * src, UInt len)
{
UInt i;
for (i = 0; i < (len >> 2); i++) {
dst[4 * i + 0] = (src[i] & 0xff000000) >> 24;
dst[4 * i + 1] = (src[i] & 0xff0000) >> 16;
dst[4 * i + 2] = (src[i] & 0xff00) >> 8;
dst[4 * i + 3] = (src[i] & 0xff);
}
}
static void store64be(UInt8 * dst, UInt8 x)
{
*dst = (((x >> 56) | ((x >> 40) & 0xff00) | ((x >> 24) & 0xff0000) |
((x >> 8) & 0xff000000) | ((x << 8) & ((UInt8)0xff << 32)) |
((x << 24) & ((UInt8)0xff << 40)) |
((x << 40) & ((UInt8)0xff << 48)) | ((x << 56))));
}
#endif
typedef struct sha256_state_t {
UInt4 r[8]; // Current hash value register
UInt count; // Nr of bits already hashed
UInt1 buf[64]; // One chunk, 512 bits
} sha256_state_t;
static int sha256_init(sha256_state_t * state)
{
memcpy(state->r, rinit, sizeof (rinit));
state->count = 0UL;
memset(state->buf, 0, 64);
return 0;
}
static void sha256_transform(UInt4 state[8],
const UInt1 block[64],
UInt4 w[64],
UInt4 r[8])
{
UInt i;
UInt4 temp1, temp2;
memcpy(r, state, 32);
be32decode(w, block, 64);
for (i = 16; i < 64; i++) {
w[i] = sigma1(w[i - 2]) + w[i - 7] + sigma0(w[i - 15]) + w[i - 16];
}
// A block is 512bit = 64bytes
for (i = 0; i < 64; i++) {
temp1 = r[7] + Sigma1(r[4]) + Ch(r[4], r[5], r[6]) + k[i] + w[i];
temp2 = Sigma0(r[0]) + Maj(r[0], r[1], r[2]);
r[7] = r[6];
r[6] = r[5];
r[5] = r[4];
r[4] = r[3] + temp1;
r[3] = r[2];
r[2] = r[1];
r[1] = r[0];
r[0] = temp1 + temp2;
}
for (i = 0; i < 8; i++) {
state[i] += r[i];
}
}
static int sha256_update(sha256_state_t * state, const UChar * buf, UInt8 len)
{
UInt4 i, rem;
UInt4 w[64];
UInt4 r[8];
// If there is buffered stuff in state, fill block
rem = (state->count >> 3) & 0x3f;
// Number of bits already hashed. Needed for continuation, and for
// padding
state->count += len << 3;
// Not enough to hash full block, just buffer
if (len < 64 - rem) {
for (i = 0; i < len; i++) {
state->buf[rem + i] = buf[i];
}
return 0;
}
for (i = 0; i < 64 - rem; i++) {
state->buf[rem + i] = buf[i];
}
// Filled a block, do the SHA256 transform
sha256_transform(state->r, state->buf, w, r);
buf += (UInt4)64 - rem;
len -= (UInt4)64 - rem;
// Hash full blocks
while (len >= 64) {
sha256_transform(state->r, (const UInt1 *)buf, w, r);
buf += 64;
len -= 64;
}
// Store remainder in buffer
for (i = 0; i < len; i++) {
state->buf[i] = buf[i];
}
memset(w, 0x0, sizeof (w));
memset(r, 0x0, sizeof (r));
return 0;
}
static int sha256_final(sha256_state_t * state)
{
UInt8 rem;
UInt8 i;
UInt4 w[64];
UInt4 r[8];
rem = (state->count >> 3) & 0x3f;
state->buf[rem] = 0x80;
if (rem < 56) {
for (i = 1; i < 56 - rem; i++) {
state->buf[rem + i] = 0x00;
}
}
else {
for (i = 1; i < (UInt4)64 - rem; i++) {
state->buf[rem + i] = 0x00;
}
sha256_transform(state->r, state->buf, w, r);
memset(state->buf, 0, 56);
}
store64be((UInt8 *)(&state->buf[56]), state->count);
sha256_transform(state->r, state->buf, w, r);
return 0;
}
Obj FuncGAP_SHA256_INIT(Obj self)
{
Obj result;
sha256_state_t * sptr;
result = NewBag(T_DATOBJ, sizeof (UInt4) + sizeof (sha256_state_t));
SET_TYPE_OBJ(result, GAP_SHA256_State_Type);
sptr = (sha256_state_t *)(&ADDR_OBJ(result)[1]);
sha256_init(sptr);
return result;
}
Obj FuncGAP_SHA256_UPDATE(Obj self, Obj state, Obj bytes)
{
sha256_state_t * sptr;
RequireArgumentCondition(SELF_NAME, state,
IS_DATOBJ(state) &&
TYPE_OBJ(state) == GAP_SHA256_State_Type,
"must be a SHA256 state" );
RequireStringRep(SELF_NAME, bytes);
sptr = (sha256_state_t *)(&ADDR_OBJ(state)[1]);
sha256_update(sptr, CHARS_STRING(bytes), GET_LEN_STRING(bytes));
CHANGED_BAG(state);
return 0;
}
Obj FuncGAP_SHA256_FINAL(Obj self, Obj state)
{
Obj result;
sha256_state_t * sptr;
int i;
RequireArgumentCondition(SELF_NAME, state,
IS_DATOBJ(state) &&
TYPE_OBJ(state) == GAP_SHA256_State_Type,
"must be a SHA256 state" );
result = NEW_PLIST(T_PLIST, 8);
SET_LEN_PLIST(result, 8);
sptr = (sha256_state_t *)(&ADDR_OBJ(state)[1]);
sha256_final(sptr);
CHANGED_BAG(state);
for (i = 0; i < 8; i++) {
SET_ELM_PLIST(result, i + 1, ObjInt_UInt(sptr->r[i]));
CHANGED_BAG(result);
}
return result;
}
Obj FuncGAP_SHA256_HMAC(Obj self, Obj key, Obj text)
{
UInt i, klen;
UInt1 k_ipad[64], k_opad[64];
UInt1 digest[32];
sha256_state_t st;
Obj result;
RequireStringRep(SELF_NAME, key);
RequireStringRep(SELF_NAME, text);
memset(k_ipad, 0x36, sizeof (k_ipad));
memset(k_opad, 0x5c, sizeof (k_opad));
klen = GET_LEN_STRING(key);
if (GET_LEN_STRING(key) > 64) {
sha256_init(&st);
sha256_update(&st, CHARS_STRING(key), klen);
sha256_final(&st);
be32encode(digest, st.r, sizeof (digest));
klen = 32;
for (i = 0; i < klen; i++) {
k_ipad[i] ^= digest[i];
k_opad[i] ^= digest[i];
}
}
else {
for (i = 0; i < klen; i++) {
k_ipad[i] ^= CHARS_STRING(key)[i];
k_opad[i] ^= CHARS_STRING(key)[i];
}
}
sha256_init(&st);
sha256_update(&st, k_ipad, 64);
sha256_update(&st, CHARS_STRING(text), GET_LEN_STRING(text));
sha256_final(&st);
be32encode(digest, st.r, sizeof (digest));
sha256_init(&st);
sha256_update(&st, k_opad, 64);
sha256_update(&st, digest, 32);
sha256_final(&st);
result = NEW_PLIST(T_PLIST, 8);
SET_LEN_PLIST(result, 8);
for (i = 0; i < 8; i++) {
SET_ELM_PLIST(result, i + 1, ObjInt_UInt(st.r[i]));
CHANGED_BAG(result);
}
return result;
}
// Table of functions to export
static StructGVarFunc GVarFuncs[] = {
GVAR_FUNC_0ARGS(GAP_SHA256_INIT),
GVAR_FUNC_2ARGS(GAP_SHA256_UPDATE, state, bytes),
GVAR_FUNC_1ARGS(GAP_SHA256_FINAL, state),
GVAR_FUNC_2ARGS(GAP_SHA256_HMAC, key, text),
{ 0 } // Finish with an empty entry
};
/****************************************************************************
**
*F InitKernel( <module> ) . . . . . . . initialise kernel data structures
*/
static Int InitKernel(StructInitInfo * module)
{
ImportGVarFromLibrary("GAP_SHA256_State_Type" , &GAP_SHA256_State_Type);
// init filters and functions
InitHdlrFuncsFromTable(GVarFuncs);
// return success
return 0;
}
/****************************************************************************
**
*F InitLibrary( <module> ) . . . . . . . initialise library data structures
*/
static Int InitLibrary(StructInitInfo * module)
{
// init filters and functions
InitGVarFuncsFromTable(GVarFuncs);
return 0;
}
/****************************************************************************
**
*F InitSHA256() . . . . . . . . . . . . . . . . . . table of init functions
*/
static StructInitInfo module = {
// init struct using C99 designated initializers; for a full list of
// fields, please refer to the definition of StructInitInfo
.type = MODULE_BUILTIN,
.name = "crypting" ,
.initKernel = InitKernel,
.initLibrary = InitLibrary,
};
StructInitInfo * InitSHA256(void )
{
return &module;
}
quality 69%
¤ Dauer der Verarbeitung: 0.31 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland