Completed the implementation, including testing, and fixed bugs
This commit is contained in:
parent
d676207600
commit
489f5e66b6
|
@ -1 +1,3 @@
|
||||||
*~
|
*~
|
||||||
|
*.o
|
||||||
|
test
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -1,3 +1,5 @@
|
||||||
|
CFLAGS = -Wall -Wextra -Wpedantic
|
||||||
|
|
||||||
test: test.o sha-256.o
|
test: test.o sha-256.o
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
27
README.md
27
README.md
|
@ -1,2 +1,27 @@
|
||||||
# sha-2
|
# sha-2
|
||||||
SHA-2 algorithm implementations
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
SHA-2 algorithm implementations.
|
||||||
|
|
||||||
|
At the moment, only a SHA-256 is implemented.
|
||||||
|
|
||||||
|
## Design criteria
|
||||||
|
|
||||||
|
- Easy to test, include in any project, compile and link.
|
||||||
|
|
||||||
|
- ANSI C with as little specific C99 as possible (e.g. extended
|
||||||
|
integer types are used, but not bool).
|
||||||
|
|
||||||
|
- Portable. Makes no assumptions on the target system's endianess or
|
||||||
|
word size.
|
||||||
|
|
||||||
|
- The SHA-256 implementation is a straightforward implementation of
|
||||||
|
the algorithm specified on
|
||||||
|
[Wikipedia](https://en.wikipedia.org/wiki/SHA-2). At the moment,
|
||||||
|
no effort at all has been put in optimization.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This repository is made available in the public domain. See [LICENSE
|
||||||
|
FILE](LICENSE).
|
||||||
|
|
39
sha-256.c
39
sha-256.c
|
@ -71,6 +71,8 @@ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state)
|
||||||
memcpy(chunk, state->p, state->len);
|
memcpy(chunk, state->p, state->len);
|
||||||
chunk += state->len;
|
chunk += state->len;
|
||||||
space_in_chunk = CHUNK_SIZE - state->len;
|
space_in_chunk = CHUNK_SIZE - state->len;
|
||||||
|
state->p += state->len;
|
||||||
|
state->len = 0;
|
||||||
|
|
||||||
/* If we are here, space_in_chunk is one at minimum. */
|
/* If we are here, space_in_chunk is one at minimum. */
|
||||||
if (!state->single_one_delivered) {
|
if (!state->single_one_delivered) {
|
||||||
|
@ -83,21 +85,39 @@ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state)
|
||||||
* Now:
|
* Now:
|
||||||
* - either there is enough space left for the total length, and we can conclude,
|
* - either there is enough space left for the total length, and we can conclude,
|
||||||
* - or there is too little space left, and we have to pad the rest of this chunk with zeroes.
|
* - or there is too little space left, and we have to pad the rest of this chunk with zeroes.
|
||||||
* In the latter case, we will conclude at the next pass.
|
* In the latter case, we will conclude at the next invokation of this function.
|
||||||
*/
|
*/
|
||||||
if (space_in_chunk >= TOTAL_LEN_LEN) {
|
if (space_in_chunk >= TOTAL_LEN_LEN) {
|
||||||
const size_t left = space_in_chunk - TOTAL_LEN_LEN;
|
const size_t left = space_in_chunk - TOTAL_LEN_LEN;
|
||||||
const size_t len = state->total_len;
|
const size_t len = state->total_len * 8;
|
||||||
memset(chunk, 0x00, left);
|
memset(chunk, 0x00, left);
|
||||||
chunk += left;
|
chunk += left;
|
||||||
|
|
||||||
|
if (sizeof len > 4) {
|
||||||
chunk[0] = (uint8_t) (len >> 56);
|
chunk[0] = (uint8_t) (len >> 56);
|
||||||
chunk[1] = (uint8_t) (len >> 48);
|
chunk[1] = (uint8_t) (len >> 48);
|
||||||
chunk[2] = (uint8_t) (len >> 40);
|
chunk[2] = (uint8_t) (len >> 40);
|
||||||
chunk[3] = (uint8_t) (len >> 32);
|
chunk[3] = (uint8_t) (len >> 32);
|
||||||
|
} else {
|
||||||
|
chunk[0] = 0;
|
||||||
|
chunk[1] = 0;
|
||||||
|
chunk[2] = 0;
|
||||||
|
chunk[3] = 0;
|
||||||
|
}
|
||||||
|
if (sizeof len > 2) {
|
||||||
chunk[4] = (uint8_t) (len >> 24);
|
chunk[4] = (uint8_t) (len >> 24);
|
||||||
chunk[5] = (uint8_t) (len >> 16);
|
chunk[5] = (uint8_t) (len >> 16);
|
||||||
|
} else {
|
||||||
|
chunk[4] = 0;
|
||||||
|
chunk[5] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sizeof len > 1) {
|
||||||
chunk[6] = (uint8_t) (len >> 8);
|
chunk[6] = (uint8_t) (len >> 8);
|
||||||
|
} else {
|
||||||
|
chunk[6] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
chunk[7] = (uint8_t) len;
|
chunk[7] = (uint8_t) len;
|
||||||
|
|
||||||
state->total_len_delivered = 1;
|
state->total_len_delivered = 1;
|
||||||
|
@ -108,6 +128,13 @@ static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limitations:
|
||||||
|
* - len must be small enough for (8 * len) to fit in len. Otherwise, the results are unpredictable.
|
||||||
|
* - sizeof size_t is assumed to be either 8, 16, 32 or 64. Otherwise, the results are unpredictable.
|
||||||
|
* - Since input is a pointer in RAM, the data to hash should be in RAM, which could be a problem
|
||||||
|
* for large data sizes.
|
||||||
|
*/
|
||||||
void calc_sha_256(uint8_t hash[32], const void * input, size_t len)
|
void calc_sha_256(uint8_t hash[32], const void * input, size_t len)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -161,8 +188,8 @@ void calc_sha_256(uint8_t hash[32], const void * input, size_t len)
|
||||||
|
|
||||||
/* Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array: */
|
/* Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array: */
|
||||||
for (int i = 16; i < 64; i++) {
|
for (int i = 16; i < 64; i++) {
|
||||||
const uint32_t s0 = right_rot(w[i - 15], 7) ^ right_rot(w[i - 15], 18) ^ w[i - 15] >> 3;
|
const uint32_t s0 = right_rot(w[i - 15], 7) ^ right_rot(w[i - 15], 18) ^ (w[i - 15] >> 3);
|
||||||
const uint32_t s1 = right_rot(w[i - 2], 17) ^ right_rot(w[i - 2], 19) ^ w[i - 2] >> 10;
|
const uint32_t s1 = right_rot(w[i - 2], 17) ^ right_rot(w[i - 2], 19) ^ (w[i - 2] >> 10);
|
||||||
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
|
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,10 +206,10 @@ void calc_sha_256(uint8_t hash[32], const void * input, size_t len)
|
||||||
/* Compression function main loop: */
|
/* Compression function main loop: */
|
||||||
for (int i = 0; i < 64; i++) {
|
for (int i = 0; i < 64; i++) {
|
||||||
const uint32_t s1 = right_rot(e, 6) ^ right_rot(e, 11) ^ right_rot(e, 25);
|
const uint32_t s1 = right_rot(e, 6) ^ right_rot(e, 11) ^ right_rot(e, 25);
|
||||||
const uint32_t ch = e & f ^ ~e & g;
|
const uint32_t ch = (e & f) ^ (~e & g);
|
||||||
const uint32_t temp1 = h + s1 + ch + k[i] + w[i];
|
const uint32_t temp1 = h + s1 + ch + k[i] + w[i];
|
||||||
const uint32_t s0 = right_rot(a, 2) ^ right_rot(a, 13) ^ right_rot(a, 22);
|
const uint32_t s0 = right_rot(a, 2) ^ right_rot(a, 13) ^ right_rot(a, 22);
|
||||||
const uint32_t maj = a & b ^ a & c ^ b & c;
|
const uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
|
||||||
const uint32_t temp2 = s0 + maj;
|
const uint32_t temp2 = s0 + maj;
|
||||||
|
|
||||||
h = g;
|
h = g;
|
||||||
|
|
71
test.c
71
test.c
|
@ -1,14 +1,75 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "sha-256.h"
|
#include "sha-256.h"
|
||||||
|
|
||||||
int main()
|
struct vector {
|
||||||
|
const char *input;
|
||||||
|
const char *output;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct vector VECTORS[] = {
|
||||||
|
{
|
||||||
|
"",
|
||||||
|
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"abc",
|
||||||
|
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||||
|
"a8ae6e6ee929abea3afcfc5258c8ccd6f85273e0d4626d26c7279f3250f77c8e"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde",
|
||||||
|
"057ee79ece0b9a849552ab8d3c335fe9a5f1c46ef5f1d9b190c295728628299c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0",
|
||||||
|
"2a6ad82f3620d3ebe9d678c812ae12312699d673240d5be8fac0910a70000d93"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||||
|
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoi"
|
||||||
|
"jklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
|
||||||
|
"cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void hash_to_string(char string[65], const uint8_t hash[32])
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 32; i++) {
|
||||||
|
string += sprintf(string, "%02x", hash[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test(const char input[], const char output[])
|
||||||
{
|
{
|
||||||
uint8_t hash[32];
|
uint8_t hash[32];
|
||||||
calc_sha_256(hash, "hello\n", 6);
|
char hash_string[65];
|
||||||
for (size_t i = 0; i < sizeof hash; i++) {
|
calc_sha_256(hash, input, strlen(input));
|
||||||
printf("%02x", hash[i]);
|
hash_to_string(hash_string, hash);
|
||||||
|
printf("input: %s\n", input);
|
||||||
|
printf("hash : %s\n", hash_string);
|
||||||
|
if (strcmp(output, hash_string)) {
|
||||||
|
printf("FAILURE!\n\n");
|
||||||
|
} else {
|
||||||
|
printf("SUCCESS!\n\n");
|
||||||
}
|
}
|
||||||
printf("\n");
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printf("%zu\n", sizeof (size_t));
|
||||||
|
for (size_t i = 0; i < (sizeof VECTORS / sizeof (struct vector)); i++) {
|
||||||
|
const struct vector *vector = &VECTORS[i];
|
||||||
|
test(vector->input, vector->output);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue