Skip to content

Commit

Permalink
hashes/sha256: add sha256-chain computation and verification functions
Browse files Browse the repository at this point in the history
* also added unittetst for it

x[SQUASH ME] separated out all waypoints test and increased waypoints
  • Loading branch information
BytesGalore authored and BytesGalore committed Feb 24, 2016
1 parent dd15430 commit f0245bd
Show file tree
Hide file tree
Showing 6 changed files with 399 additions and 0 deletions.
140 changes: 140 additions & 0 deletions sys/hashes/sha256.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*-
* Copyright 2005 Colin Percival
* Copyright 2013 Christian Mehlis & René Kijewski
* Copyright 2016 Martin Landsmann <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -37,11 +38,13 @@
* @author Colin Percival
* @author Christian Mehlis
* @author Rene Kijewski
* @author Martin Landsmann
*
* @}
*/

#include <string.h>
#include <assert.h>

#include "hashes/sha256.h"
#include "board.h"
Expand Down Expand Up @@ -318,3 +321,140 @@ const unsigned char *hmac_sha256(const unsigned char *key,

return result;
}

/**
* @brief helper to compute sha256 inplace for the given buffer
*
* @param[in, out] element the buffer to compute a sha256 and store it back to it
*
*/
static inline void sha256_inplace(unsigned char element[SHA256_DIGEST_LENGTH])
{
sha256_context_t ctx;
sha256_init(&ctx);
sha256_update(&ctx, element, SHA256_DIGEST_LENGTH);
sha256_final(element, &ctx);
}

unsigned char *sha256_chain(const unsigned char *seed, size_t seed_length,
size_t elements, unsigned char *tail_element)
{
unsigned char tmp_element[SHA256_DIGEST_LENGTH];

/* assert if no sha256-chain can be created */
assert(elements >= 2);

/* 1st iteration */
sha256(seed, seed_length, tmp_element);

/* perform consecutive iterations minus the first one */
for (size_t i = 0; i < (elements - 1); ++i) {
sha256_inplace(tmp_element);
}

/* store the result */
memcpy(tail_element, tmp_element, SHA256_DIGEST_LENGTH);

return tail_element;
}

unsigned char *sha256_chain_with_waypoints(const unsigned char *seed,
size_t seed_length,
size_t elements,
unsigned char *tail_element,
sha256_chain_idx_elm_t *waypoints,
size_t *waypoints_length)
{
/* assert if no sha256-chain can be created */
assert(elements >= 2);

/* assert to prevent division by 0 */
assert(*waypoints_length > 0);

/* assert if no waypoints can be created */
assert(*waypoints_length > 1);

/* if we have enough space we store the whole chain */
if (*waypoints_length >= elements) {
/* 1st iteration */
sha256(seed, seed_length, waypoints[0].element);
waypoints[0].index = 0;

/* perform consecutive iterations starting at index 1*/
for (size_t i = 1; i < elements; ++i) {
sha256_context_t ctx;
sha256_init(&ctx);
sha256_update(&ctx, waypoints[(i - 1)].element, SHA256_DIGEST_LENGTH);
sha256_final(waypoints[i].element, &ctx);
waypoints[i].index = i;
}

/* store the result */
memcpy(tail_element, waypoints[(elements - 1)].element, SHA256_DIGEST_LENGTH);
*waypoints_length = (elements - 1);

return tail_element;
}
else {
unsigned char tmp_element[SHA256_DIGEST_LENGTH];
size_t waypoint_streak = (elements / *waypoints_length);

/* 1st waypoint iteration */
sha256(seed, seed_length, tmp_element);
for (size_t i = 1; i < waypoint_streak; ++i) {
sha256_inplace(tmp_element);
}
memcpy(waypoints[0].element, tmp_element, SHA256_DIGEST_LENGTH);
waypoints[0].index = (waypoint_streak - 1);

/* index of the current computed element in the chain */
size_t index = (waypoint_streak - 1);

/* consecutive waypoint iterations */
size_t j = 1;
for (; j < *waypoints_length; ++j) {
for (size_t i = 0; i < waypoint_streak; ++i) {
sha256_inplace(tmp_element);
index++;
}
memcpy(waypoints[j].element, tmp_element, SHA256_DIGEST_LENGTH);
waypoints[j].index = index;
}

/* store/pass the last used index in the waypoint array */
*waypoints_length = (j - 1);

/* remaining iterations down to elements */
for (size_t i = index; i < (elements - 1); ++i) {
sha256_inplace(tmp_element);
}

/* store the result */
memcpy(tail_element, tmp_element, SHA256_DIGEST_LENGTH);

return tail_element;
}
}

int sha256_chain_verify_element(unsigned char *element,
size_t element_index,
unsigned char *tail_element,
size_t chain_length)
{
unsigned char tmp_element[SHA256_DIGEST_LENGTH];

int delta_count = (chain_length - element_index);

/* assert if we have an index mismatch */
assert(delta_count >= 1);

memcpy((void*)tmp_element, (void*)element, SHA256_DIGEST_LENGTH);

/* perform all consecutive iterations down to tail_element */
for (int i = 0; i < (delta_count - 1); ++i) {
sha256_inplace(tmp_element);
}

/* return if the computed element equals the tail_element */
return (memcmp(tmp_element, tail_element, SHA256_DIGEST_LENGTH) != 0);
}
79 changes: 79 additions & 0 deletions sys/include/hashes/sha256.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*-
* Copyright 2005 Colin Percival
* Copyright 2013 Christian Mehlis & René Kijewski
* Copyright 2016 Martin Landsmann <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -68,6 +69,16 @@ typedef struct {
unsigned char buf[64];
} sha256_context_t;

/**
* @brief sha256-chain indexed element
*/
typedef struct {
/** the position of this element in its chain */
size_t index;
/** the element */
unsigned char element[SHA256_DIGEST_LENGTH];
} sha256_chain_idx_elm_t;

/**
* @brief SHA-256 initialization. Begins a SHA-256 operation.
*
Expand Down Expand Up @@ -124,6 +135,74 @@ const unsigned char *hmac_sha256(const unsigned char *key,
size_t message_length,
unsigned char *result);

/**
* @brief function to produce a hash chain statring with a given seed element.
* The chain is computed by taking the sha256 from the seed,
* hash the resulting sha256 and continuing taking sha256
* from each result consecutively.
*
* @param[in] seed the seed of the sha256-chain, i.e. the first element
* @param[in] seed_length the size of seed in bytes
* @param[in] elements the number of chained elements,
* i.e. the index of the last element is (elements-1)
* @param[out] tail_element the final element of the sha256-chain
*
* @returns pointer to tail_element
*/
unsigned char *sha256_chain(const unsigned char *seed, size_t seed_length,
size_t elements, unsigned char *tail_element);

/**
* @brief function to produce a hash chain statring with a given seed element.
* The chain is computed the same way as done with sha256_chain().
* Additionally intermediate elements are saved while computing the chain.
* This slows down computation, but provides the caller with indexed
* "waypoint"-elements.
* They are supposed to shortcut computing verification elements,
* this comes in handy when using long chains,
* e.g. a chain with 2<sup>32</sup> elements.
*
* @param[in] seed the seed of the sha256-chain, i.e. the first element
* @param[in] seed_length the size of seed in bytes
* @param[in] elements the number of chained elements,
* i.e. the index of the last element is (elements-1)
* @param[out] tail_element the final element of the sha256-chain
* @param[out] waypoints intermediate elements are stored there.
* @param[in, out] waypoints_length the size of the waypoints array.
* If the given size is equal or greater elements, the complete
* chain will be stored.
* Otherwise every n-th element is stored where:
* n = floor(elements / waypoints_length);
* floor is implicitly used since we perform unsigned integer division.
* The last used waypoint index is stored in the variable after call.
* That is (elements - 1) if the complete chain is stored,
* and (*waypoints_length - 1) if we only store some waypoints.
*
* @returns pointer to tail_element
*/
unsigned char *sha256_chain_with_waypoints(const unsigned char *seed,
size_t seed_length,
size_t elements,
unsigned char *tail_element,
sha256_chain_idx_elm_t *waypoints,
size_t *waypoints_length);

/**
* @brief function to verify if a given chain element is part of the chain.
*
* @param[in] element the chain element to be verified
* @param[in] element_index the position in the chain
* @param[in] tail_element the last element of the sha256-chain
* @param[in] chain_length the number of elements in the chain
*
* @returns 0 if element is verified to be part of the chain at element_index
* 1 if the element cannot be verified as part of the chain
*/
int sha256_chain_verify_element(unsigned char *element,
size_t element_index,
unsigned char *tail_element,
size_t chain_length);

#ifdef __cplusplus
}
#endif
Expand Down
Loading

0 comments on commit f0245bd

Please sign in to comment.