SHA224 and SHA256 hash algorithm principle and Implementation (with source code)

Related articles:

Recently, a number of hash algorithm wheels have been built successively, including MD family (including MD2/MD4/MD5), SHA1, SHA2 family (SHA224, SHA256, SHA384, SHA512), SHA3 family and state secret SM3 algorithm.

It was originally intended to analyze and implement each algorithm in detail. Now it seems that this work may not be completed in a short time, so send the source code first.

The source code of this part of the implementation fully refers to the algorithm description in the official document. Even the variable name should be consistent with the variables in the official document as much as possible to facilitate learning.

In addition, the SHA256 and SHA224 hash call interfaces encapsulated in the code refer to the official openssl interface, which is fully compatible and seamless. If you can use the interface here, you can use the library function interface of openssl, and you don't even need to modify the code.

In addition to the source code of the implementation, a test example is also attached. This test example is not only used to test whether the implementation of the hash algorithm is correct, but also provides "- f"/"-s" and other options for hashing any file and string. Therefore, it is used as a tool, similar to the built-in md5sum/sha1sum of the system.

SHA224 and SHA256 implementation source code

1. Header file sha256 c

/*
 * @        file: sha256.h
 * @ description: header file for sha256.c
 * @      author: Gu Yongqiang
 * @        blog: https://blog.csdn.net/guyongqiangx
 */
#ifndef __ROCKY_SHA256__H
#define __ROCKY_SHA256__H

#define ERR_OK           0
#define ERR_ERR         -1  /* generic error */
#define ERR_INV_PARAM   -2  /* invalid parameter */
#define ERR_TOO_LONG    -3  /* too long */
#define ERR_STATE_ERR   -4  /* state error */

typedef unsigned char      uint8_t;
typedef unsigned short     uint16_t;
typedef unsigned int       uint32_t;
typedef unsigned long long uint64_t;

typedef struct sha256_context {
    /* message total length in bytes */
    uint64_t total;

    /* intermedia hash value for each block */
    struct {
        uint32_t a;
        uint32_t b;
        uint32_t c;
        uint32_t d;
        uint32_t e;
		uint32_t f;
		uint32_t g;
		uint32_t h;
    }hash;

    /* last block */
    struct {
        uint32_t used;     /* used bytes */
        uint8_t  buf[64];  /* block data buffer */
    }last;
}SHA256_CTX;

/* https://www.openssl.org/docs/man1.1.1/man3/SHA256_Final.html */
int SHA224_Init(SHA256_CTX *c);
int SHA224_Update(SHA256_CTX *c, const void *data, size_t len);
int SHA224_Final(unsigned char *md, SHA256_CTX *c);
unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md);

int SHA256_Init(SHA256_CTX *c);
int SHA256_Update(SHA256_CTX *c, const void *data, size_t len);
int SHA256_Final(unsigned char *md, SHA256_CTX *c);
unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md);
#endif

2. Code file sha256 c

/*
 * @        file: sha256.c
 * @ description: implementation for the SHA224/SHA256 Secure Hash Algorithm
 * @      author: Gu Yongqiang
 * @        blog: https://blog.csdn.net/guyongqiangx
 */
#include <stdio.h>
#include <string.h>

#include "utils.h"
#include "sha256.h"

//#define DEBUG

#ifdef DEBUG
#define DBG(...) printf(__VA_ARGS__)
#define DUMP_BLOCK_DATA 1
#define DUMP_BLOCK_HASH 1
#define DUMP_ROUND_DATA 1
#else
#define DBG(...)
#define DUMP_BLOCK_DATA 0
#define DUMP_BLOCK_HASH 0
#define DUMP_ROUND_DATA 0
#endif

#define SHA256_BLOCK_SIZE           64  /* 512 bits = 64 Bytes */
#define SHA256_LEN_SIZE             8   /* 64 bits = 8 bytes */
#define SHA256_LEN_OFFSET           (SHA256_BLOCK_SIZE - SHA256_LEN_SIZE)

#define SHA256_DIGEST_SIZE          32 /* 256 bits = 32 bytes */
#define SHA224_DIGEST_SIZE          28 /* 224 bits = 28 bytes */

#define SHA256_PADDING_PATTERN      0x80
#define SHA256_ROUND_NUM            64

#define HASH_BLOCK_SIZE             SHA256_BLOCK_SIZE
#define HASH_LEN_SIZE               SHA256_LEN_SIZE
#define HASH_LEN_OFFSET             SHA256_LEN_OFFSET

#define HASH_DIGEST_SIZE            SHA256_DIGEST_SIZE      /* use sha256 digest size */

#define HASH_PADDING_PATTERN        SHA256_PADDING_PATTERN
#define HASH_ROUND_NUM              SHA256_ROUND_NUM

/* SHA256 Constants */
static const uint32_t K256[HASH_ROUND_NUM] = {
    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
};

/* ROTate Right (cirular right shift) */
static uint32_t ROTR(uint32_t x, uint8_t shift)
{
    return (x >> shift) | (x << (32 - shift));
}

/* Right SHift */
static uint32_t SHR(uint32_t x, uint8_t shift)
{
    return (x >> shift);
}

/* Ch ... choose */
static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z)
{
    return (x & y) ^ (~x & z) ;
}

/* Maj ... majority */
static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z)
{
    return (x & y) ^ (x & z) ^ (y & z);
}

/* SIGMA0 */
static uint32_t SIGMA0(uint32_t x)
{
    return ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22);
}

/* SIGMA1 */
static uint32_t SIGMA1(uint32_t x)
{
    return ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25);
}

/* sigma0, different from SIGMA0 */
static uint32_t sigma0(uint32_t x)
{
    return ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3);
}

/* sigma1, different from SIGMA1 */
static uint32_t sigma1(uint32_t x)
{
    return ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10);
}

int SHA256_Init(SHA256_CTX *c)
{
    if (NULL == c)
    {
        return ERR_INV_PARAM;
    }

    memset(c, 0, sizeof(SHA256_CTX));

    /* Initial Value for SHA256 */
    c->hash.a = 0x6a09e667;
    c->hash.b = 0xbb67ae85;
    c->hash.c = 0x3c6ef372;
    c->hash.d = 0xa54ff53a;
    c->hash.e = 0x510e527f;
    c->hash.f = 0x9b05688c;
    c->hash.g = 0x1f83d9ab;
    c->hash.h = 0x5be0cd19;

    return ERR_OK;
}

static int SHA256_PrepareScheduleWord(const uint32_t *block, uint32_t *W)
{
    uint32_t t;

    if ((NULL == block) || (NULL == W))
    {
        return ERR_INV_PARAM;
    }

    for (t=0; t<HASH_ROUND_NUM; t++)
    {
        if (t<=15)  /*  0 <= t <= 15 */
            W[t] = be32toh(block[t]);
        else        /* 16 <= t <= 79 */
            W[t] = sigma1(W[t-2]) + W[t-7] + sigma0(W[t-15]) + W[t-16];
    }

    return ERR_OK;
}

static int SHA256_ProcessBlock(SHA256_CTX *ctx, const void *block)
{
    uint32_t t;
    uint32_t W[HASH_ROUND_NUM];
    uint32_t T1, T2;
    uint32_t a, b, c, d, e, f, g, h;

    if ((NULL == ctx) || (NULL == block))
    {
        return ERR_INV_PARAM;
    }

#if (DUMP_BLOCK_DATA == 1)
    DBG("---------------------------------------------------------\n");
    DBG("   BLOCK: %llu\n", ctx->total/HASH_BLOCK_SIZE);
    DBG("    DATA:\n");
    print_buffer(block, HASH_BLOCK_SIZE, "    ");
#endif

    /* prepare schedule word */
    SHA256_PrepareScheduleWord(block, W);

    a = ctx->hash.a;
    b = ctx->hash.b;
    c = ctx->hash.c;
    d = ctx->hash.d;
    e = ctx->hash.e;
    f = ctx->hash.f;
    g = ctx->hash.g;
    h = ctx->hash.h;

#if (DUMP_BLOCK_HASH == 1)
    DBG("      IV: %08x %08x %08x %08x %08x %08x %08x %08x\n",
        ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d, ctx->hash.e, ctx->hash.f, ctx->hash.g, ctx->hash.h);
#endif

    for (t=0; t<HASH_ROUND_NUM; t++)
    {
        T1 = h + SIGMA1(e) + Ch(e, f, g) + K256[t] + W[t];
        T2 = SIGMA0(a) + Maj(a, b, c);
        h = g;
        g = f;
        f = e;
        e = d + T1;
        d = c;
        c = b;
        b = a;
        a = T1 + T2;

#if (DUMP_ROUND_DATA == 1)
        DBG("      %02d: T1=0x%08x, T2=0x%08x, W=0x%08x, \n"\
            "           a=0x%08x,  b=0x%08x, c=0x%08x, d=0x%08x, e=0x%08x, f=0x%08x, g=0x%08x, h=0x%08x\n", \
                t, T1, T2, W[t], a, b, c, d, e, f, g, h);
#endif
    }

    ctx->hash.a += a;
    ctx->hash.b += b;
    ctx->hash.c += c;
    ctx->hash.d += d;
    ctx->hash.e += e;
    ctx->hash.f += f;
    ctx->hash.g += g;
    ctx->hash.h += h;

#if (DUMP_BLOCK_HASH == 1)
    DBG("    HASH: %08x %08x %08x %08x %08x %08x %08x %08x\n",
        ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d, ctx->hash.e, ctx->hash.f, ctx->hash.g, ctx->hash.h);
#endif

    return ERR_OK;
}


int SHA256_Update(SHA256_CTX *c, const void *data, size_t len)
{
    uint32_t copy_len = 0;

    if ((NULL == c) || (NULL == data))
    {
        return ERR_INV_PARAM;
    }

    /* has used data */
    if (c->last.used != 0)
    {
        /* less than 1 block in total, combine data */
        if (c->last.used + len < HASH_BLOCK_SIZE)
        {
            memcpy(&c->last.buf[c->last.used], data, len);
            c->last.used += len;

            return ERR_OK;
        }
        else /* more than 1 block */
        {
            /* process the block in context buffer */
            copy_len = HASH_BLOCK_SIZE - c->last.used;
            memcpy(&c->last.buf[c->last.used], data, copy_len);
            SHA256_ProcessBlock(c, &c->last.buf);
            c->total += HASH_BLOCK_SIZE;

            data = (uint8_t *)data + copy_len;
            len -= copy_len;

            /* reset context buffer */
            memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE);
            c->last.used = 0;
        }
    }

    /* less than 1 block, copy to context buffer */
    if (len < HASH_BLOCK_SIZE)
    {
        memcpy(&c->last.buf[c->last.used], data, len);
        c->last.used += len;

        return ERR_OK;
    }
    else
    {
        /* process data blocks */
        while (len >= HASH_BLOCK_SIZE)
        {
            SHA256_ProcessBlock(c, data);
            c->total += HASH_BLOCK_SIZE;

            data = (uint8_t *)data + HASH_BLOCK_SIZE;
            len -= HASH_BLOCK_SIZE;
        }

        /* copy rest data to context buffer */
        memcpy(&c->last.buf[0], data, len);
        c->last.used = len;
    }

    return ERR_OK;
}

int SHA256_Final(unsigned char *md, SHA256_CTX *c)
{
    uint32_t *temp;
    //uint64_t *buf;

    if ((NULL == c) || (NULL == md))
    {
        return ERR_INV_PARAM;
    }

    /* Last block should be less thant HASH_BLOCK_SIZE - HASH_LEN_SIZE */
    if (c->last.used >= (HASH_BLOCK_SIZE - HASH_LEN_SIZE))
    {
        c->total += c->last.used;

        /* one more block */
        c->last.buf[c->last.used] = HASH_PADDING_PATTERN;
        c->last.used++;

        memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - c->last.used);
        SHA256_ProcessBlock(c, &c->last.buf);

        memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE);
        c->last.used = 0;

        /* save length */
        //buf = (uint64_t *)&(c->last.buf[HASH_LEN_OFFSET]);
        //*buf = htobe64(c->total << 3);
        temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]);
        temp[0] = htobe32((c->total << 3) >> 32 & 0xFFFFFFFF);
        temp[1] = htobe32((c->total << 3) & 0xFFFFFFFF);

        SHA256_ProcessBlock(c, &c->last.buf);
    }
    else /* 0 <= last.used < HASH_BLOCK_SIZE - HASH_LEN_SIZE */
    {
        c->total += c->last.used;

        /* one more block */
        c->last.buf[c->last.used] = HASH_PADDING_PATTERN;
        c->last.used++;

        /* padding 0s */
        memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE - c->last.used);

        /* save length */
        //buf = (uint64_t *)&(c->last.buf[HASH_LEN_OFFSET]);
        //*buf = htobe64(c->total << 3);
        temp = (uint32_t *)&(c->last.buf[HASH_LEN_OFFSET]);
        temp[0] = htobe32((c->total << 3) >> 32 & 0xFFFFFFFF);
        temp[1] = htobe32((c->total << 3) & 0xFFFFFFFF);

        SHA256_ProcessBlock(c, &c->last.buf);
    }

    temp = (uint32_t *)md;
    temp[0] = htobe32(c->hash.a);
    temp[1] = htobe32(c->hash.b);
    temp[2] = htobe32(c->hash.c);
    temp[3] = htobe32(c->hash.d);
    temp[4] = htobe32(c->hash.e);
    temp[5] = htobe32(c->hash.f);
    temp[6] = htobe32(c->hash.g);
    temp[7] = htobe32(c->hash.h);

    return ERR_OK;
}

unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md)
{
    SHA256_CTX c;

    if ((NULL == d) || (NULL == md))
    {
        return NULL;
    }

    SHA256_Init(&c);
    SHA256_Update(&c, d, n);
    SHA256_Final(md, &c);

    return md;
}

int SHA224_Init(SHA256_CTX *c)
{
    if (NULL == c)
    {
        return ERR_INV_PARAM;
    }

    memset(c, 0, sizeof(SHA256_CTX));

    c->hash.a = 0xc1059ed8;
    c->hash.b = 0x367cd507;
    c->hash.c = 0x3070dd17;
    c->hash.d = 0xf70e5939;
    c->hash.e = 0xffc00b31;
    c->hash.f = 0x68581511;
    c->hash.g = 0x64f98fa7;
    c->hash.h = 0xbefa4fa4;

    return ERR_OK;
}

int SHA224_Update(SHA256_CTX *c, const void *data, size_t len)
{
    return SHA256_Update(c, data, len);
}

int SHA224_Final(unsigned char *md, SHA256_CTX *c)
{
    int rc = ERR_OK;
    unsigned char sha256_md[SHA256_DIGEST_SIZE];

    memset(&sha256_md, 0, sizeof(sha256_md));

    rc = SHA256_Final(sha256_md, c);

    memcpy(md, sha256_md, SHA224_DIGEST_SIZE);

    return rc;
}

unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md)
{
    SHA256_CTX c;

    if ((NULL == d) || (NULL == md))
    {
        return NULL;
    }

    SHA224_Init(&c);
    SHA224_Update(&c, d, n);
    SHA224_Final(md, &c);

    return md;
}

From the above implementation, the main differences between SHA224 and SHA256 are:

  • SHA224_ Initialization variables in init function are inconsistent
  • SHA224_ In the final function, the previous part is intercepted from the hash obtained based on SHA256 as the hash value of sha224

Compilation and testing of SHA256 source code

I directly built a test pseudo target in Makefile. During compilation, in addition to compiling into a hash tool named sha256, I will also directly call the built-in hash test.

Compile and run as follows:

$ make
gcc -Wall -g -O2 -c utils.c -o utils.o
gcc -Wall -g -O2 -c sha256.c -o sha256.o
gcc -Wall -g -O2 -c sha256test.c -o sha256test.o
gcc -Wall -g -O2 utils.o sha256.o sha256test.o -o sha256

Run Test...
./sha256 -a sha224 -x
Internal hash tests for ./sha256(SHA224):
./sha256("")
  Expect: d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f
  Result: d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f

./sha256("a")
  Expect: abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5
  Result: abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5

./sha256("abc")
  Expect: 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7
  Result: 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7

./sha256("message digest")
  Expect: 2cb21c83ae2f004de7e81c3c7019cbcb65b71ab656b22d6d0c39b8eb
  Result: 2cb21c83ae2f004de7e81c3c7019cbcb65b71ab656b22d6d0c39b8eb

./sha256("abcdefghijklmnopqrstuvwxyz")
  Expect: 45a5f72c39c5cff2522eb3429799e49e5f44b356ef926bcf390dccc2
  Result: 45a5f72c39c5cff2522eb3429799e49e5f44b356ef926bcf390dccc2

./sha256("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
  Expect: bff72b4fcb7d75e5632900ac5f90d219e05e97a7bde72e740db393d9
  Result: bff72b4fcb7d75e5632900ac5f90d219e05e97a7bde72e740db393d9

./sha256("12345678901234567890123456789012345678901234567890123456789012345678901234567890")
  Expect: b50aecbe4e9bb0b57bc5f3ae760a8e01db24f203fb3cdcd13148046e
  Result: b50aecbe4e9bb0b57bc5f3ae760a8e01db24f203fb3cdcd13148046e

./sha256 -a sha256 -x
Internal hash tests for ./sha256(SHA256):
./sha256("")
  Expect: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  Result: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

./sha256("a")
  Expect: ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb
  Result: ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb

./sha256("abc")
  Expect: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
  Result: ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

./sha256("message digest")
  Expect: f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650
  Result: f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650

./sha256("abcdefghijklmnopqrstuvwxyz")
  Expect: 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73
  Result: 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73

./sha256("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
  Expect: db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0
  Result: db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0

./sha256("12345678901234567890123456789012345678901234567890123456789012345678901234567890")
  Expect: f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e
  Result: f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e

The latest version of openssl tool already supports sm3 hash algorithm, so you can compare the results of dgst calculation performed by sm3 tool and openssl:

$ sha256 -h
Usage:
Common options: [-x|-f file|-s string| -a sha224|sha256 | -h]
Hash a string:
        sha256 -a sha224|sha256 -s string
Hash a file:
        sha256 -a sha224|sha256 -f file [-k key]
-a      Secure hash algorithm: "sha224", "sha256"
-x      Internal string hash test
-h      Display this message

#
# Calculate SHA224 hash
#

# Use the "- f" and "- s" options to calculate sha224 hash values for files and strings, respectively
$ sha256 -a sha224 -f sha256.o
sha256(sha256.o) = 3ab679330b579d31c032c29d648d873ee95b03e0be085640e468fba9
$ sha256 -a sha224 -s "I Love China!"
sha256("I Love China!") = ea5e741f52612d3897304d6a70c146a7fa21b965ed28739f091396e8

# Use the open source openssl tool to calculate the corresponding hash for comparison
$ openssl dgst -sha224 sha256.o
SHA224(sha256.o)= 3ab679330b579d31c032c29d648d873ee95b03e0be085640e468fba9
$ echo -n "I Love China!" | openssl dgst -sha224
(stdin)= ea5e741f52612d3897304d6a70c146a7fa21b965ed28739f091396e8

#
# Calculate SHA256 hash
#

# Use the "- f" and "- s" options to calculate sha256 hash values for files and strings, respectively
$ sha256 -a sha256 -f sha256.o
sha256(sha256.o) = 08b4685632df74d8fc765fa70ccc4ab9763c9e4a6a69b3c5a53f73173122bac5
$ sha256 -a sha256 -s "I Love China!"
sha256("I Love China!") = 91c906339dbb1f46cfcb2a24dfe5bc445752a84fc04a8474b4260fd8bb679129

# Use the open source openssl tool to calculate the corresponding hash for comparison
$ openssl dgst -sha256 sha256.o
SHA256(sha256.o)= 08b4685632df74d8fc765fa70ccc4ab9763c9e4a6a69b3c5a53f73173122bac5
$ echo -n "I Love China!" | openssl dgst -sha256
(stdin)= 91c906339dbb1f46cfcb2a24dfe5bc445752a84fc04a8474b4260fd8bb679129

Complete code

The complete list of code files is as follows:

sha256$ ls -lh
total 52K
-rwxr--r-- 1 rocky rocky  649 Jun 20 15:47 Makefile
-rwxrwxr-x 1 rocky rocky  12K Jun 20 17:06 sha256.c
-rwxrwxr-x 1 rocky rocky 1.6K Jun 20 17:04 sha256.h
-rwxrwxr-x 1 rocky rocky  12K Jun 20 16:49 sha256test.c
-rwxr--r-- 1 rocky rocky 8.1K Jun 20 11:04 sha256test-new.c
-rwxr--r-- 1 rocky rocky  758 Jun 20 17:11 utils.c
-rwxr--r-- 1 rocky rocky 1.8K Jun 20 17:11 utils.h

Code required, please visit:

  • https://github.com/guyongqiangx/cryptography/

other

Rocky often encounters unfamiliar problems in his work. These problems may not be difficult, but because he doesn't understand and can't find help, he often wastes a few days or even longer.

So I set up several wechat discussion groups (remember which group I said to add and how to add wechat, see later). Welcome to discuss together:

  • A cryptology discussion group, which mainly discusses various encryption and decryption, signature verification and other algorithms. Please explain the cryptology discussion group.
  • For an Android OTA discussion group, please explain how to add Android OTA group.
  • For a discussion group of git and repo, please explain adding git and repo groups.

After work, rocky tries to write something useful to everyone. If Rocky's article makes you gain something and solves the problems you have been unable to solve, you might as well praise rocky, which is also the greatest encouragement to rocky. Scan the QR code below to admire rocky. The amount is optional:

Lodge himself maintained a public number, "loge," the world's official account of official account. The company also provides personal contact information and some resources. There may be unexpected gains. See the company's tips for details. Sweep the bottom of the two-dimensional code to pay attention to the official account.

Keywords: cryptology

Added by gazever on Fri, 28 Jan 2022 22:38:12 +0200