Home SHA-256 Algorithm Implementation in C
Post
Cancel

SHA-256 Algorithm Implementation in C

SHA-256 Algorithm Implementation in C

Author: Robert1037

Source: github.com/Robert1037/Crypto-in-C/tree/master/sha-256

Releases: github.com/Robert1037/Crypto-in-C/releases/tag/sha-256_v2.1_little-endian

Introduction

What is the SHA-256 algorithm? Here is the official explanation in Secure Hash Standard (SHS) :

This Standard specifies secure hash algorithms, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224 and SHA-512/256. All of the algorithms are iterative, one-way hash functions that can process a message to produce a condensed representation called a message digest. These algorithms enable the determination of a message’s integrity: any change to the message will, with a very high probability, result in a different message digest. This property is useful in the generation and verification of digital signatures and message authentication codes, and in the generation of random numbers or bits.

Each algorithm can be described in two stages: preprocessing and hash computation. Preprocessing involves padding a message, parsing the padded message into m-bit blocks, and setting initialization values to be used in the hash computation. The hash computation generates a message schedule from the padded message and uses that schedule, along with functions, constants, and word operations to iteratively generate a series of hash values. The final hash value generated by the hash computation is used to determine the message digest.

SHA-256 may be used to hash a message, M, having a length of l bits, where 0 <= l < 2^64. The algorithm uses 1) a message schedule of sixty-four 32-bit words, 2) eight working variables of 32 bits each, and 3) a hash value of eight 32-bit words. The final result of SHA-256 is a 256-bit message digest.

Algorithm

Read the following chapters and sections in Secure Hash Standard (SHS) :

2 3 4.1.2 4.2.2 5.1.1 5.2.1 5.3.3 6.2

or read: RFC 6234: US Secure Hash Algorithms

Implementation & Features

sha256full.c is the original version of sha256fast.c and sha256min.c. But sha256full.c and sha256fast.c are optimized, so their codes may be a little confusing. Thus I recommend reading sha256min.c first.

Here are the features (differences) :

features sha256full.c sha256fast.c sha256min.c
timer Yes (3) Yes (1) No
prompt Yes (detailed) Yes (brief) No
repetition Yes No No
string hashing Yes Yes (include NULL) No
file hashing Yes Yes Yes
unroll loop Yes (1) Yes (18) No

sha256min.c :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
 * MIT License
 * Copyright (c) 2023 Robert1037
 * sha256min.c v2.1 little-endian
 * Last modified: 2023-01-21
 **/
#include <stdio.h>
#include <stdlib.h>
#define M_LEN 64 //each M block is 512 bits == 64 bytes
#define Rn(X, n) ((X << (32 - n)) | (X >> n))
#define Sn(X, n) (X >> n)
#define Ch(X, Y, Z) ((X & Y) ^ (~X & Z))
#define Maj(X, Y, Z) ((X & Y) ^ (X & Z) ^ (Y & Z))
#define Sigma_E0(X) (Rn(X, 2) ^ Rn(X, 13) ^ Rn(X, 22)) //Σ0(X) = R2(X) ⊕ R13(X) ⊕ R22(X)
#define Sigma_E1(X) (Rn(X, 6) ^ Rn(X, 11) ^ Rn(X, 25)) //Σ1(X) = R6(X) ⊕ R11(X) ⊕ R25(X)
#define Sigma_o0(X) (Rn(X, 7) ^ Rn(X, 18) ^ Sn(X, 3)) //σ0(X) = R7(X) ⊕ R18(X) ⊕ S3(X)
#define Sigma_o1(X) (Rn(X, 17) ^ Rn(X, 19) ^ Sn(X, 10)) //σ1(X) = R17(X) ⊕ R19(X) ⊕ S10(X)
int main(int argc, char **argv)
{
    FILE *fp = fopen(argv[1], "rb");
    if (!fp)
        return 0;
    unsigned int K[64] = {
        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
    };
    register unsigned int *Kp, *W, *M, a, b, c, d, e, f, g, h, T1,
        H0 = 0x6a09e667,  H1 = 0xbb67ae85,  H2 = 0x3c6ef372,  H3 = 0xa54ff53a,
        H4 = 0x510e527f,  H5 = 0x9b05688c,  H6 = 0x1f83d9ab,  H7 = 0x5be0cd19;
    register char *chp, *ch, tmp;
    fseek(fp, 0, SEEK_END);
    a = ftell(fp);
    b = a & 63; // a % 64;
    b = a + ((b < 56) ? (M_LEN - b) : (M_LEN | (M_LEN - b)));
    if (!(ch = (char*)calloc(b + 256, 1))) // 256 == 64 * sizeof(int), it's for W.
        return 0;
    rewind(fp);
    if (fread(ch, 1, a, fp) != a)
        return 0;
    fclose(fp);
    ch[a] = 0x80;
    chp = ch + b - 12;
    do {
        tmp = chp[0];  chp[0] = chp[3];  chp[3] = tmp;
        tmp = chp[1];  chp[1] = chp[2];  chp[2] = tmp;
        chp -= 4;
    } while (ch <= chp);
    M = (unsigned int*)ch;
    b >>= 2;
    W = M + b;
    W[-2] = a >> 29;
    W[-1] = a << 3;
    do { // 1 -> N blocks of M
        a = H0;  b = H1;  c = H2;  d = H3;
        e = H4;  f = H5;  g = H6;  h = H7;
        Kp = W + 16;
        do { // j : 0 -> 15
            *W = *M;
            W++;  M++;
        } while (Kp != W);
        Kp += 48;
        do { // j : 16 -> 63
            *W = Sigma_o1(W[-2]) + W[-7] + Sigma_o0(W[-15]) + W[-16];
            W++;
        } while (Kp != W);
        Kp = K;  W -= 64;
        do {
            T1 = h + Sigma_E1(e) + Ch(e, f, g) + *W + *Kp; //T1 ← h + Σ1(e) + Ch(e, f, g) + Wj + Kj
            h = g;  g = f;  f = e;  e = d + T1;
            d = c;  c = b;  b = a;  a = T1 + Sigma_E0(b) + Maj(b, c, d); //T2 ← Σ0(a) + Maj(a, b, c)
            W++;  Kp++;
        } while (Kp <= &K[63]);
        H0 += a;  H1 += b;  H2 += c;  H3 += d;
        H4 += e;  H5 += f;  H6 += g;  H7 += h;
        W -= 64;
    } while (M != W);
    printf("%.8x%.8x%.8x%.8x%.8x%.8x%.8x%.8x\n", H0, H1, H2, H3, H4, H5, H6, H7);
    return 0;
}

Download

Windows

64-bit

win10_x64

sha256full_win10_x64.exe github sourceforge

sha256fast_win10_x64.exe github sourceforge

sha256min_win10_x64.exe github sourceforge

OS

  • Windows 10
  • Windows 11

CPU

  • Intel x64 (x86_64, amd64)
  • AMD x64 (x86_64, amd64)

Build Info

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Microsoft Windows 10

x64-based PC

GNU Make 4.2.1
Built for x86_64-w64-mingw32

gcc version 12.2.0 (x86_64-posix-seh-rev2, Built by MinGW-W64 project)
Using built-in specs.
COLLECT_GCC=D:\mingw64\bin\gcc.exe
COLLECT_LTO_WRAPPER=D:/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/12.2.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-12.2.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw-builds/ucrt64-seh-posix/x86_64-1220-posix-seh-ucrt-rt_v10-rev2/mingw64 --enable-hot 
-shared --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --enable-libstdcxx-filesystem-ts=yes --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev2, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw-builds/ucrt64-seh-posix/x86_64-1220-posix-seh-ucrt-rt_v10-rev2/mingw64/opt/include -I/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-zlib-static/include -I/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw-builds/ucrt64-seh-posix/x86_64-1220-posix-seh-ucrt-rt_v10-rev2/mingw64/opt/include -I/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-zlib-static/include -I/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw-builds/ucrt64-seh-posix/x86_64-1220-posix-seh-ucrt-rt_v10-rev2/mingw64/opt/include -I/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-zlib-static/include -I/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw-builds/ucrt64-seh-posix/x86_64-1220-posix-seh-ucrt-rt_v10-rev2/mingw64/opt/lib -L/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-zlib-static/lib -L/c/mingw-builds/ucrt64-seh-posix/prerequisites/x86_64-w64-mingw32-static/lib ' LD_FOR_TARGET=/c/mingw-builds/ucrt64-seh-posix/x86_64-1220-posix-seh-ucrt-rt_v10-rev2/mingw64/bin/ld.exe --with-boot-ldflags=' -Wl,--disable-dynamicbase -static-libstdc++ -static-libgcc'
Thread model: posix
Supported LTO compression algorithms: zlib

Linux

64-bit

deb11_x64

sha256full_deb11_x64 github sourceforge

sha256fast_deb11_x64 github sourceforge

sha256min_deb11_x64 github sourceforge

OS

  • Debian 11 (bullseye) amd64
  • Debian 12 (bookworm) amd64
  • Ubuntu 20.04 (focal) amd64
  • Ubuntu 22.04 (jammy) amd64

CPU

  • Intel x64 (x86_64, amd64)
  • AMD x64 (x86_64, amd64)

Build Info

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Debian GNU/Linux 11 (bullseye)

Linux version 5.10.0-18-cloud-amd64

GNU Make 4.3
Built for x86_64-pc-linux-gnu

gcc version 10.2.1 20210110 (Debian 10.2.1-6)
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/10/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 10.2.1-6' --with-bugurl=file:///usr/share/doc/gcc-10/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-10 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-10-Km9U7s/gcc-10-10.2.1/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-10-Km9U7s/gcc-10-10.2.1/debian/tmp-gcn/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-mutex
Thread model: posix
Supported LTO compression algorithms: zlib zstd
rasp4b_64

sha256full_rasp4b_64 github sourceforge

sha256fast_rasp4b_64 github sourceforge

sha256min_rasp4b_64 github sourceforge

OS

  • Raspbian 11 (i.e. Debian 11) aarch64
  • Ubuntu 20.04 (focal) aarch64
  • Ubuntu 22.04 (jammy) aarch64

Hardware

  • Raspberry Pi 4 Model B

Build Info

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Debian GNU/Linux 11 (bullseye)

Linux version 5.15.61-v8+

GNU Make 4.3
Built for aarch64-unknown-linux-gnu

gcc version 10.2.1 20210110 (Debian 10.2.1-6)
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/aarch64-linux-gnu/10/lto-wrapper
Target: aarch64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 10.2.1-6' --with-bugurl=file:///usr/share/doc/gcc-10/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-10 --program-prefix=aarch64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-checking=release --build=aarch64-linux-gnu --host=aarch64-linux-gnu --target=aarch64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-mutex
Thread model: posix
Supported LTO compression algorithms: zlib zstd

32-bit

rasp4b_32

sha256full_rasp4b_32 github sourceforge

sha256fast_rasp4b_32 github sourceforge

sha256min_rasp4b_32 github sourceforge

OS

  • Raspbian 11 armhf
  • Ubuntu 20.04 (focal) armhf
  • Ubuntu 22.04 (jammy) armhf

Hardware

  • Raspberry Pi 4 Model B

Build Info

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Raspbian GNU/Linux 11 (bullseye)

Linux version 5.15.61-v7l+

GNU Make 4.3
Built for arm-unknown-linux-gnueabihf

gcc version 10.2.1 20210110 (Raspbian 10.2.1-6+rpi1)
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/10/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Raspbian 10.2.1-6+rpi1' --with-bugurl=file:///usr/share/doc/gcc-10/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-10 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
Thread model: posix
Supported LTO compression algorithms: zlib zstd

Clone & Build

Download source_of_sha-256_v2.1_little-endian.zip or source_of_sha-256_v2.1_little-endian.tar.gz

or

1
git clone https://github.com/Robert1037/Crypto-in-C.git

Windows

Download the latest version of mingw: https://github.com/niXman/mingw-builds-binaries/releases4

Build one of them: (e.g. sha256full)

1
> mingw32-make full

Build all: (by default)

1
> mingw32-make

Linux

Prerequisites: gcc, make

Build one of them: (e.g. sha256full)

1
$ make full

Build all: (by default)

1
$ make

Usage

Windows

sha256full

  • cmd or powershell
  • double click .exe
1
2
3
4
5
6
7
8
> .\sha256full
*************** sha-256 ***************
Please input a file name.
If the file dose not exist,
the inputted string will be computed.
(string length < 960, file size < 2 GB)
(ENTER without input to quit)
:

sha256fast

  • cmd or powershell
  • double click .exe
1
2
> .\sha256fast
filename or string :

sha256min

  • cmd or powershell
  • double click .exe
1
> .\sha256min <filename>

Linux

sha256full

1
2
3
4
5
6
7
8
$ ./sha256full
*************** sha-256 ***************
Please input a file name.
If the file dose not exist,
the inputted string will be computed.
(string length < 960, file size < 2 GB)
(ENTER without input to quit)
:

sha256fast

1
2
$ ./sha256fast
filename or string :

sha256min

1
$ ./sha256min <filename>

Screenshots & Test Results

Windows10 x64

Verification tools:

https://coding.tools/sha256

and

1
> certutil -hashfile <filename> sha256

sha256full.exe

hello

null.txt

NIST.FIPS.180-4.pdf

..\..\test.mp4

..\..\movie.mp4

(Press ENTER key directly)

sha256fast.exe

(Press ENTER key directly)

hello

null.txt

NIST.FIPS.180-4.pdf

..\..\movie.mp4

sha256min.exe

(Press ENTER key directly)

null.txt

NIST.FIPS.180-4.pdf

..\..\movie.mp4

Ubuntu20.04 x64

Verification tool:

1
$ sha256sum <filename>

sha256full

hello

NIST.FIPS.180-4.pdf

sha256fast

(Press ENTER key directly)

hello

NIST.FIPS.180-4.pdf

sha256min

null.txt

NIST.FIPS.180-4.pdf

Verification:

References

[1] Wade Trappe, Lawrence C. Washington. Introduction to Cryptography with Coding Theory (3rd edition) [M]. Hoboken: Pearson Education, 2020: 499-521.

[2] FIPS PUB 180-4. Secure Hash Standard (SHS) [S]. http://dx.doi.org/10.6028/NIST.FIPS.180-4

[3] Datacruiser. 一文读懂SHA256算法原理及其实现. https://zhuanlan.zhihu.com/p/94619052

[4] 小Q谈移动安全. 【密码学】一文读懂SHA-2. https://zhuanlan.zhihu.com/p/404879837

Further Reading

[1] Henri Gilbert, Helena Handschuh. Security Analysis of SHA-256 and Sisters. https://link.springer.com/content/pdf/10.1007/978-3-540-24654-1_13.pdf

[2] in3rsha. sha256-animation. https://github.com/in3rsha/sha256-animation

[3] https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA256.pdf

This post is licensed under CC BY 4.0 by the author.
Trending Tags