SHA224和SHA256哈希算法原理及实现(附源码)

相关文章:

最近陆续造了一批哈希算法的轮子,包括MD家族(包括MD2/MD4/MD5), SHA1, SHA2家族(SHA224, SHA256, SHA384, SHA512),SHA3家族以及国密SM3算法。

原来打算将每一个算法都详细分析并实现,现在看来,这个工作短时间可能无法完成,所以先将源码发上来。

这部分实现的源码完全参考官方文档的算法描述,连变量名也尽可能和官方文档中的变量保持一致,方便学习。

另外, 代码封装的SHA256和SHA224哈希调用接口参考了openssl官方的接口,完全兼容,无缝对接。会使用这里的接口,就会使用openssl的库函数接口,甚至连代码都不需要修改。

除了实现的源码外,还另外附带了一个测试例子,这个测试例子不仅仅是用于测试哈希算法的实现是否正确,还可以提供了"-f"/"-s"等选项用于对任意文件和字符串进行哈希,因此作为一个工具使用,类似系统内置的md5sum/sha1sum。

SHA224和SHA256实现源码

1. 头文件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. 代码文件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;
}

从上面的实现来看,SHA224和SHA256的主要区别在于:

  • SHA224_Init函数中,初始化变量不一致
  • SHA224_Final函数中,从基于SHA256得到的哈希中截取前面部分作为SHA224的哈希值

SHA256源码的编译和测试

我直接在Makefile中内置了一个test伪目标,编译时除了编译生成名为sha256的哈希工具外,还会直接调用内置的哈希测试。

编译和运行如下:

$ 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

最新版本的openssl工具已经支持sm3哈希算法,因此可以将sm3工具和openssl执行dgst计算的结果进行比较:

$ 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

#
# 计算SHA224哈希
#

# 使用"-f"和"-s"选项分别对文件和字符串计算sha224哈希值
$ sha256 -a sha224 -f sha256.o
sha256(sha256.o) = 3ab679330b579d31c032c29d648d873ee95b03e0be085640e468fba9
$ sha256 -a sha224 -s "I Love China!"
sha256("I Love China!") = ea5e741f52612d3897304d6a70c146a7fa21b965ed28739f091396e8

# 使用开源的openssl工具计算相应的哈希进行对比
$ openssl dgst -sha224 sha256.o
SHA224(sha256.o)= 3ab679330b579d31c032c29d648d873ee95b03e0be085640e468fba9
$ echo -n "I Love China!" | openssl dgst -sha224
(stdin)= ea5e741f52612d3897304d6a70c146a7fa21b965ed28739f091396e8

#
# 计算SHA256哈希
#

# 使用"-f"和"-s"选项分别对文件和字符串计算sha256哈希值
$ sha256 -a sha256 -f sha256.o
sha256(sha256.o) = 08b4685632df74d8fc765fa70ccc4ab9763c9e4a6a69b3c5a53f73173122bac5
$ sha256 -a sha256 -s "I Love China!"
sha256("I Love China!") = 91c906339dbb1f46cfcb2a24dfe5bc445752a84fc04a8474b4260fd8bb679129

# 使用开源的openssl工具计算相应的哈希进行对比
$ openssl dgst -sha256 sha256.o
SHA256(sha256.o)= 08b4685632df74d8fc765fa70ccc4ab9763c9e4a6a69b3c5a53f73173122bac5
$ echo -n "I Love China!" | openssl dgst -sha256
(stdin)= 91c906339dbb1f46cfcb2a24dfe5bc445752a84fc04a8474b4260fd8bb679129

完整代码

完整的代码文件列表如下:

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

需要代码请访问:

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

其它

洛奇工作中常常会遇到自己不熟悉的问题,这些问题可能并不难,但因为不了解,找不到人帮忙而瞎折腾,往往导致浪费几天甚至更久的时间。

所以我组建了几个微信讨论群(记得微信我说加哪个群,如何加微信见后面),欢迎一起讨论:

  • 一个密码编码学讨论组,主要讨论各种加解密,签名校验等算法,请说明加密码学讨论群。
  • 一个Android OTA的讨论组,请说明加Android OTA群。
  • 一个git和repo的讨论组,请说明加git和repo群。

在工作之余,洛奇尽量写一些对大家有用的东西,如果洛奇的这篇文章让您有所收获,解决了您一直以来未能解决的问题,不妨赞赏一下洛奇,这也是对洛奇付出的最大鼓励。扫下面的二维码赞赏洛奇,金额随意:

收钱码

洛奇自己维护了一个公众号“洛奇看世界”,一个很佛系的公众号,不定期瞎逼逼。公号也提供个人联系方式,一些资源,说不定会有意外的收获,详细内容见公号提示。扫下方二维码关注公众号:

公众号

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洛奇看世界

一分也是爱~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值