Kaitai-based Intel ACM and BootGuard parsers

As the first step towards automated parsing, this change set replaces outdated BootGuard-related parsers with shiny new KaitaiStruct-based ones.
It also does the following:
- improves Intel FIT definitions by using the relevant specification
- adds sha1, sha384, sha512 and sm3 digest implementations
- updates LZMA SDK to v22.01
- moves GUIDs out of include files to prevent multiple instantiations
- enforces C++11
- adds Kaitai-based parsers for Intel FIT, BootGuard v1 and BootGuard v2 structures
- makes many small refactorings here, there and everywhere
This commit is contained in:
Nikolaj Schlej 2022-08-29 08:23:38 +02:00
parent 8600bc3ab3
commit 934ce1f3f8
81 changed files with 15212 additions and 5279 deletions

230
common/digest/sha1.c Normal file
View file

@ -0,0 +1,230 @@
/* sha1.c
Copyright (c) 2022, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
//
// This implementations are based on LibTomCrypt that was released into
// public domain by Tom St Denis.
//
#include "sha1.h"
#include <stdint.h>
#include <string.h>
/* ulong64: 64-bit data type */
#ifdef _MSC_VER
#define CONST64(n) n ## ui64
typedef unsigned __int64 ulong64;
#else
#define CONST64(n) n ## ULL
typedef uint64_t ulong64;
#endif
typedef uint32_t ulong32;
#define LOAD32H(x, y) \
do { x = ((ulong32)((y)[0] & 255)<<24) | \
((ulong32)((y)[1] & 255)<<16) | \
((ulong32)((y)[2] & 255)<<8) | \
((ulong32)((y)[3] & 255)); } while(0)
#ifndef MIN
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
#define ROL(x, y) ( (((ulong32)(x)<<(ulong32)((y)&31)) | (((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL)
#define ROLc(x, y) ( (((ulong32)(x)<<(ulong32)((y)&31)) | (((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL)
#define STORE32H(x, y) \
do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
(y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0)
#define STORE64H(x, y) \
do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0)
#define F0(x,y,z) (z ^ (x & (y ^ z)))
#define F1(x,y,z) (x ^ y ^ z)
#define F2(x,y,z) ((x & y) | (z & (x | y)))
#define F3(x,y,z) (x ^ y ^ z)
struct sha1_state {
ulong64 length;
ulong32 state[5], curlen;
unsigned char buf[64];
};
static int s_sha1_compress(struct sha1_state *md, const unsigned char *buf)
{
ulong32 a,b,c,d,e,W[80],i;
ulong32 t;
/* copy the state into 512-bits into W[0..15] */
for (i = 0; i < 16; i++) {
LOAD32H(W[i], buf + (4*i));
}
/* copy state */
a = md->state[0];
b = md->state[1];
c = md->state[2];
d = md->state[3];
e = md->state[4];
/* expand it */
for (i = 16; i < 80; i++) {
W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
}
/* compress */
/* round one */
#define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
#define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
#define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
#define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);
for (i = 0; i < 20; ) {
FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
}
for (; i < 40; ) {
FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
}
for (; i < 60; ) {
FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
}
for (; i < 80; ) {
FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
}
#undef FF0
#undef FF1
#undef FF2
#undef FF3
/* store */
md->state[0] = md->state[0] + a;
md->state[1] = md->state[1] + b;
md->state[2] = md->state[2] + c;
md->state[3] = md->state[3] + d;
md->state[4] = md->state[4] + e;
return 0;
}
static int sha1_init(struct sha1_state * md)
{
if (md == NULL) return -1;
md->state[0] = 0x67452301UL;
md->state[1] = 0xefcdab89UL;
md->state[2] = 0x98badcfeUL;
md->state[3] = 0x10325476UL;
md->state[4] = 0xc3d2e1f0UL;
md->curlen = 0;
md->length = 0;
return 0;
}
static int sha1_process(struct sha1_state * md, const unsigned char *in, unsigned long inlen)
{
unsigned long n;
int err;
if (md == NULL) return -1;
if (in == NULL) return -1;
if (md->curlen > sizeof(md->buf)) {
return -1;
}
if (((md->length + inlen * 8) < md->length)
|| ((inlen * 8) < inlen)) {
return -1;
}
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 64) {
if ((err = s_sha1_compress(md, in)) != 0) {
return err;
}
md->length += 64 * 8;
in += 64;
inlen -= 64;
} else {
n = MIN(inlen, (64 - md->curlen));
memcpy(md->buf + md->curlen, in, (size_t)n);
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 64) {
if ((err = s_sha1_compress(md, md->buf)) != 0) {
return err;
}
md->length += 8 * 64;
md->curlen = 0;
}
}
}
return 0;
}
static int sha1_done(struct sha1_state * md, unsigned char *out)
{
int i;
if (md == NULL) return -1;
if (out == NULL) return -1;
if (md->curlen >= sizeof(md->buf)) {
return -1;
}
/* increase the length of the message */
md->length += md->curlen * 8;
/* append the '1' bit */
md->buf[md->curlen++] = (unsigned char)0x80;
/* if the length is currently above 56 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->curlen > 56) {
while (md->curlen < 64) {
md->buf[md->curlen++] = (unsigned char)0;
}
s_sha1_compress(md, md->buf);
md->curlen = 0;
}
/* pad upto 56 bytes of zeroes */
while (md->curlen < 56) {
md->buf[md->curlen++] = (unsigned char)0;
}
/* store length */
STORE64H(md->length, md->buf+56);
s_sha1_compress(md, md->buf);
/* copy output */
for (i = 0; i < 5; i++) {
STORE32H(md->state[i], out+(4*i));
}
return 0;
}
void sha1(const void *in, unsigned long inlen, void* out)
{
struct sha1_state ctx;
sha1_init(&ctx);
sha1_process(&ctx, (const unsigned char*)in, inlen);
sha1_done(&ctx, (unsigned char *)out);
}

25
common/digest/sha1.h Normal file
View file

@ -0,0 +1,25 @@
/* sha1.h
Copyright (c) 2022, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef SHA1_H
#define SHA1_H
#ifdef __cplusplus
extern "C" {
#endif
void sha1(const void *in, unsigned long inlen, void* out);
#ifdef __cplusplus
}
#endif
#endif // SHA2_H

27
common/digest/sha2.h Normal file
View file

@ -0,0 +1,27 @@
/* sha2.h
Copyright (c) 2017, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
#ifndef SHA2_H
#define SHA2_H
#ifdef __cplusplus
extern "C" {
#endif
void sha256(const void *in, unsigned long inlen, void* out);
void sha384(const void *in, unsigned long inlen, void* out);
void sha512(const void *in, unsigned long inlen, void* out);
#ifdef __cplusplus
}
#endif
#endif // SHA2_H

279
common/digest/sha256.c Normal file
View file

@ -0,0 +1,279 @@
/* sha256.c
Copyright (c) 2017, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
//
// This implementations are based on LibTomCrypt that was released into
// public domain by Tom St Denis.
//
#include "sha2.h"
#include <stdint.h>
#include <string.h>
/* ulong64: 64-bit data type */
#ifdef _MSC_VER
#define CONST64(n) n ## ui64
typedef unsigned __int64 ulong64;
#else
#define CONST64(n) n ## ULL
typedef uint64_t ulong64;
#endif
typedef uint32_t ulong32;
#define LOAD32H(x, y) \
do { x = ((ulong32)((y)[0] & 255)<<24) | \
((ulong32)((y)[1] & 255)<<16) | \
((ulong32)((y)[2] & 255)<<8) | \
((ulong32)((y)[3] & 255)); } while(0)
#ifndef MIN
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
#define RORc(x, y) ( ((((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((y)&31)) | ((ulong32)(x)<<(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL)
#define STORE32H(x, y) \
do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
(y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0)
#define STORE64H(x, y) \
do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0)
/* Various logical functions */
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) RORc((x),(n))
#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
struct sha256_state {
ulong64 length;
ulong32 state[8], curlen;
unsigned char buf[32*2];
};
/* compress 512-bits */
static int s_sha256_compress(struct sha256_state * md, const unsigned char *buf)
{
ulong32 S[8], W[64], t0, t1;
int i;
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
}
/* copy the state into 512-bits into W[0..15] */
for (i = 0; i < 16; i++) {
LOAD32H(W[i], buf + (4*i));
}
/* fill W[16..63] */
for (i = 16; i < 64; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
/* Compress */
#define RND(a,b,c,d,e,f,g,h,i,ki) \
t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3);
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2);
#undef RND
/* feedback */
for (i = 0; i < 8; i++) {
md->state[i] = md->state[i] + S[i];
}
return 0;
}
static int sha256_init(struct sha256_state * md)
{
if (md == NULL) return -1;
md->curlen = 0;
md->length = 0;
md->state[0] = 0x6A09E667UL;
md->state[1] = 0xBB67AE85UL;
md->state[2] = 0x3C6EF372UL;
md->state[3] = 0xA54FF53AUL;
md->state[4] = 0x510E527FUL;
md->state[5] = 0x9B05688CUL;
md->state[6] = 0x1F83D9ABUL;
md->state[7] = 0x5BE0CD19UL;
return 0;
}
static int sha256_process(struct sha256_state * md, const unsigned char *in, unsigned long inlen)
{
unsigned long n;
int err;
if (md == NULL) return -1;
if (in == NULL) return -1;
if (md->curlen > sizeof(md->buf)) {
return -1;
}
if (((md->length + inlen * 8) < md->length)
|| ((inlen * 8) < inlen)) {
return -1;
}
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 64) {
if ((err = s_sha256_compress(md, in)) != 0) {
return err;
}
md->length += 64 * 8;
in += 64;
inlen -= 64;
} else {
n = MIN(inlen, (64 - md->curlen));
memcpy(md->buf + md->curlen, in, (size_t)n);
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 64) {
if ((err = s_sha256_compress(md, md->buf)) != 0) {
return err;
}
md->length += 8 * 64;
md->curlen = 0;
}
}
}
return 0;
}
static int sha256_done(struct sha256_state * md, unsigned char *out)
{
int i;
if (md == NULL) return -1;
if (out == NULL) return -1;
if (md->curlen >= sizeof(md->buf)) {
return -1;
}
/* increase the length of the message */
md->length += md->curlen * 8;
/* append the '1' bit */
md->buf[md->curlen++] = (unsigned char)0x80;
/* if the length is currently above 56 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->curlen > 56) {
while (md->curlen < 64) {
md->buf[md->curlen++] = (unsigned char)0;
}
s_sha256_compress(md, md->buf);
md->curlen = 0;
}
/* pad upto 56 bytes of zeroes */
while (md->curlen < 56) {
md->buf[md->curlen++] = (unsigned char)0;
}
/* store length */
STORE64H(md->length, md->buf+56);
s_sha256_compress(md, md->buf);
/* copy output */
for (i = 0; i < 8; i++) {
STORE32H(md->state[i], out+(4*i));
}
return 0;
}
void sha256(const void *in, unsigned long inlen, void* out)
{
struct sha256_state ctx;
sha256_init(&ctx);
sha256_process(&ctx, (const unsigned char*)in, inlen);
sha256_done(&ctx, (unsigned char *)out);
}

312
common/digest/sha512.c Normal file
View file

@ -0,0 +1,312 @@
/* sha512.c
Copyright (c) 2022, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
//
// This implementations are based on LibTomCrypt that was released into
// public domain by Tom St Denis.
//
#include "sha2.h"
#include <stdint.h>
#include <string.h>
/* ulong64: 64-bit data type */
#ifdef _MSC_VER
#define CONST64(n) n ## ui64
typedef unsigned __int64 ulong64;
typedef __int64 long64;
#else
#define CONST64(n) n ## ULL
typedef unsigned long long ulong64;
typedef long long long64;
#endif
#define ROR64c(x, y) \
( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
((x)<<(((ulong64)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF))
#define LOAD64H(x, y) \
do { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
(((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
(((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
(((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); } while(0)
#define STORE64H(x, y) \
do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0)
#ifndef MIN
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
/* the K array */
static const ulong64 K[80] = {
CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)
};
/* Various logical functions */
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n)
#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
struct sha512_state {
ulong64 length, state[8];
unsigned long curlen;
unsigned char buf[128];
};
/* compress 1024-bits */
static int s_sha512_compress(struct sha512_state * md, const unsigned char *buf)
{
ulong64 S[8], W[80], t0, t1;
int i;
/* copy state into S */
for (i = 0; i < 8; i++) {
S[i] = md->state[i];
}
/* copy the state into 1024-bits into W[0..15] */
for (i = 0; i < 16; i++) {
LOAD64H(W[i], buf + (8*i));
}
/* fill W[16..79] */
for (i = 16; i < 80; i++) {
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
}
/* Compress */
#define RND(a,b,c,d,e,f,g,h,i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
for (i = 0; i < 80; i += 8) {
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
}
/* feedback */
for (i = 0; i < 8; i++) {
md->state[i] = md->state[i] + S[i];
}
return 0;
}
static int sha512_init(struct sha512_state * md)
{
if (md == NULL) return -1;
md->curlen = 0;
md->length = 0;
md->state[0] = CONST64(0x6a09e667f3bcc908);
md->state[1] = CONST64(0xbb67ae8584caa73b);
md->state[2] = CONST64(0x3c6ef372fe94f82b);
md->state[3] = CONST64(0xa54ff53a5f1d36f1);
md->state[4] = CONST64(0x510e527fade682d1);
md->state[5] = CONST64(0x9b05688c2b3e6c1f);
md->state[6] = CONST64(0x1f83d9abfb41bd6b);
md->state[7] = CONST64(0x5be0cd19137e2179);
return 0;
}
static int sha512_process(struct sha512_state * md, const unsigned char *in, unsigned long inlen)
{
unsigned long n;
int err;
if (md == NULL) return -1;
if (in == NULL) return -1;
if (md->curlen > sizeof(md->buf)) {
return -1;
}
if (((md->length + inlen * 8) < md->length)
|| ((inlen * 8) < inlen)) {
return -1;
}
while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) {
if ((err = s_sha512_compress(md, in)) != 0) {
return err;
}
md->length += 128 * 8;
in += 128;
inlen -= 128;
} else {
n = MIN(inlen, (128 - md->curlen));
memcpy(md->buf + md->curlen, in, (size_t)n);
md->curlen += n;
in += n;
inlen -= n;
if (md->curlen == 128) {
if ((err = s_sha512_compress(md, md->buf)) != 0) {
return err;
}
md->length += 8 * 128;
md->curlen = 0;
}
}
}
return 0;
}
static int sha512_done(struct sha512_state * md, unsigned char *out)
{
int i;
if (md == NULL) return -1;
if (out == NULL) return -1;
if (md->curlen >= sizeof(md->buf)) {
return -1;
}
/* increase the length of the message */
md->length += md->curlen * CONST64(8);
/* append the '1' bit */
md->buf[md->curlen++] = (unsigned char)0x80;
/* if the length is currently above 112 bytes we append zeros
* then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if (md->curlen > 112) {
while (md->curlen < 128) {
md->buf[md->curlen++] = (unsigned char)0;
}
s_sha512_compress(md, md->buf);
md->curlen = 0;
}
/* pad upto 120 bytes of zeroes
* note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
* > 2^64 bits of data... :-)
*/
while (md->curlen < 120) {
md->buf[md->curlen++] = (unsigned char)0;
}
/* store length */
STORE64H(md->length, md->buf+120);
s_sha512_compress(md, md->buf);
/* copy output */
for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out+(8*i));
}
return 0;
}
static int sha384_init(struct sha512_state * md)
{
if (md == NULL) return -1;
md->curlen = 0;
md->length = 0;
md->state[0] = CONST64(0xcbbb9d5dc1059ed8);
md->state[1] = CONST64(0x629a292a367cd507);
md->state[2] = CONST64(0x9159015a3070dd17);
md->state[3] = CONST64(0x152fecd8f70e5939);
md->state[4] = CONST64(0x67332667ffc00b31);
md->state[5] = CONST64(0x8eb44a8768581511);
md->state[6] = CONST64(0xdb0c2e0d64f98fa7);
md->state[7] = CONST64(0x47b5481dbefa4fa4);
return 0;
}
static int sha384_done(struct sha512_state * md, unsigned char *out)
{
unsigned char buf[64];
if (md == NULL) return -1;
if (out == NULL) return -1;;
if (md->curlen >= sizeof(md->buf)) {
return -1;
}
sha512_done(md, buf);
memcpy(out, buf, 48);
return 0;
}
void sha384(const void *in, unsigned long inlen, void* out)
{
struct sha512_state ctx;
sha384_init(&ctx);
sha512_process(&ctx, (const unsigned char*)in, inlen);
sha384_done(&ctx, (unsigned char *)out);
}
void sha512(const void *in, unsigned long inlen, void* out)
{
struct sha512_state ctx;
sha512_init(&ctx);
sha512_process(&ctx, (const unsigned char*)in, inlen);
sha512_done(&ctx, (unsigned char *)out);
}

234
common/digest/sm3.c Normal file
View file

@ -0,0 +1,234 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2019 Huawei Technologies Co., Ltd
*/
#include "sm3.h"
#include <string.h>
struct sm3_context {
uint32_t total[2]; /* number of bytes processed */
uint32_t state[8]; /* intermediate digest state */
uint8_t buffer[64]; /* data block being processed */
uint8_t ipad[64]; /* HMAC: inner padding */
uint8_t opad[64]; /* HMAC: outer padding */
};
static void sm3_init(struct sm3_context *ctx);
static void sm3_update(struct sm3_context *ctx, const uint8_t *input, size_t ilen);
static void sm3_final(struct sm3_context *ctx, uint8_t* output);
#define GET_UINT32_BE(n, b, i) \
do { \
(n) = ((uint32_t)(b)[(i)] << 24) | \
((uint32_t)(b)[(i) + 1] << 16) | \
((uint32_t)(b)[(i) + 2] << 8) | \
((uint32_t)(b)[(i) + 3]); \
} while (0)
#define PUT_UINT32_BE(n, b, i) \
do { \
(b)[(i)] = (uint8_t)((n) >> 24); \
(b)[(i) + 1] = (uint8_t)((n) >> 16); \
(b)[(i) + 2] = (uint8_t)((n) >> 8); \
(b)[(i) + 3] = (uint8_t)((n)); \
} while (0)
static void sm3_init(struct sm3_context *ctx)
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x7380166F;
ctx->state[1] = 0x4914B2B9;
ctx->state[2] = 0x172442D7;
ctx->state[3] = 0xDA8A0600;
ctx->state[4] = 0xA96F30BC;
ctx->state[5] = 0x163138AA;
ctx->state[6] = 0xE38DEE4D;
ctx->state[7] = 0xB0FB0E4E;
}
static void sm3_process(struct sm3_context *ctx, const uint8_t data[64])
{
uint32_t SS1, SS2, TT1, TT2, W[68], W1[64];
uint32_t A, B, C, D, E, F, G, H;
uint32_t T[64];
uint32_t Temp1, Temp2, Temp3, Temp4, Temp5;
int j;
for (j = 0; j < 16; j++)
T[j] = 0x79CC4519;
for (j = 16; j < 64; j++)
T[j] = 0x7A879D8A;
GET_UINT32_BE(W[0], data, 0);
GET_UINT32_BE(W[1], data, 4);
GET_UINT32_BE(W[2], data, 8);
GET_UINT32_BE(W[3], data, 12);
GET_UINT32_BE(W[4], data, 16);
GET_UINT32_BE(W[5], data, 20);
GET_UINT32_BE(W[6], data, 24);
GET_UINT32_BE(W[7], data, 28);
GET_UINT32_BE(W[8], data, 32);
GET_UINT32_BE(W[9], data, 36);
GET_UINT32_BE(W[10], data, 40);
GET_UINT32_BE(W[11], data, 44);
GET_UINT32_BE(W[12], data, 48);
GET_UINT32_BE(W[13], data, 52);
GET_UINT32_BE(W[14], data, 56);
GET_UINT32_BE(W[15], data, 60);
#define FF0(x, y, z) ((x) ^ (y) ^ (z))
#define FF1(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define GG0(x, y, z) ((x) ^ (y) ^ (z))
#define GG1(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
#define SHL(x, n) ((x) << (n))
#define ROTL(x, y) ( (((uint32_t)(x)<<(uint32_t)((y)&31)) | (((uint32_t)(x)&0xFFFFFFFFUL)>>(uint32_t)((32-((y)&31))&31))) & 0xFFFFFFFFUL)
#define P0(x) ((x) ^ ROTL((x), 9) ^ ROTL((x), 17))
#define P1(x) ((x) ^ ROTL((x), 15) ^ ROTL((x), 23))
for (j = 16; j < 68; j++) {
/*
* W[j] = P1( W[j-16] ^ W[j-9] ^ ROTL(W[j-3],15)) ^
* ROTL(W[j - 13],7 ) ^ W[j-6];
*/
Temp1 = W[j - 16] ^ W[j - 9];
Temp2 = ROTL(W[j - 3], 15);
Temp3 = Temp1 ^ Temp2;
Temp4 = P1(Temp3);
Temp5 = ROTL(W[j - 13], 7) ^ W[j - 6];
W[j] = Temp4 ^ Temp5;
}
for (j = 0; j < 64; j++)
W1[j] = W[j] ^ W[j + 4];
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
E = ctx->state[4];
F = ctx->state[5];
G = ctx->state[6];
H = ctx->state[7];
for (j = 0; j < 16; j++) {
SS1 = ROTL(ROTL(A, 12) + E + ROTL(T[j], j), 7);
SS2 = SS1 ^ ROTL(A, 12);
TT1 = FF0(A, B, C) + D + SS2 + W1[j];
TT2 = GG0(E, F, G) + H + SS1 + W[j];
D = C;
C = ROTL(B, 9);
B = A;
A = TT1;
H = G;
G = ROTL(F, 19);
F = E;
E = P0(TT2);
}
for (j = 16; j < 64; j++) {
SS1 = ROTL(ROTL(A, 12) + E + ROTL(T[j], j), 7);
SS2 = SS1 ^ ROTL(A, 12);
TT1 = FF1(A, B, C) + D + SS2 + W1[j];
TT2 = GG1(E, F, G) + H + SS1 + W[j];
D = C;
C = ROTL(B, 9);
B = A;
A = TT1;
H = G;
G = ROTL(F, 19);
F = E;
E = P0(TT2);
}
ctx->state[0] ^= A;
ctx->state[1] ^= B;
ctx->state[2] ^= C;
ctx->state[3] ^= D;
ctx->state[4] ^= E;
ctx->state[5] ^= F;
ctx->state[6] ^= G;
ctx->state[7] ^= H;
}
static void sm3_update(struct sm3_context *ctx, const uint8_t *input, size_t ilen)
{
size_t fill;
size_t left;
if (!ilen)
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += ilen;
if (ctx->total[0] < ilen)
ctx->total[1]++;
if (left && ilen >= fill) {
memcpy(ctx->buffer + left, input, fill);
sm3_process(ctx, ctx->buffer);
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= 64) {
sm3_process(ctx, input);
input += 64;
ilen -= 64;
}
if (ilen > 0)
memcpy(ctx->buffer + left, input, ilen);
}
static const uint8_t sm3_padding[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static void sm3_final(struct sm3_context *ctx, uint8_t* output)
{
uint32_t last, padn;
uint32_t high, low;
uint8_t msglen[8];
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low = ctx->total[0] << 3;
PUT_UINT32_BE(high, msglen, 0);
PUT_UINT32_BE(low, msglen, 4);
last = ctx->total[0] & 0x3F;
padn = (last < 56) ? (56 - last) : (120 - last);
sm3_update(ctx, sm3_padding, padn);
sm3_update(ctx, msglen, 8);
PUT_UINT32_BE(ctx->state[0], output, 0);
PUT_UINT32_BE(ctx->state[1], output, 4);
PUT_UINT32_BE(ctx->state[2], output, 8);
PUT_UINT32_BE(ctx->state[3], output, 12);
PUT_UINT32_BE(ctx->state[4], output, 16);
PUT_UINT32_BE(ctx->state[5], output, 20);
PUT_UINT32_BE(ctx->state[6], output, 24);
PUT_UINT32_BE(ctx->state[7], output, 28);
}
void sm3(const void *in, unsigned long inlen, void* out)
{
struct sm3_context ctx;
sm3_init(&ctx);
sm3_update(&ctx, (const uint8_t *)in, (size_t)inlen);
sm3_final(&ctx, (uint8_t*)out);
}

32
common/digest/sm3.h Normal file
View file

@ -0,0 +1,32 @@
/* sm3.h
Copyright (c) 2022, Nikolaj Schlej. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*/
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (c) 2019 Huawei Technologies Co., Ltd
*/
#ifndef SM3_H
#define SM3_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
void sm3(const void *in, unsigned long inlen, void* out);
#ifdef __cplusplus
}
#endif
#endif /* SM3_H */