Last active
August 29, 2015 14:24
-
-
Save tell/70fcf481b3130be16d3c to your computer and use it in GitHub Desktop.
An exercise for C99
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*.d | |
# Object files | |
*.o | |
*.ko | |
*.obj | |
*.elf | |
# Precompiled Headers | |
*.gch | |
*.pch | |
# Libraries | |
*.lib | |
*.a | |
*.la | |
*.lo | |
# Shared objects (inc. Windows DLLs) | |
*.dll | |
*.so | |
*.so.* | |
*.dylib | |
# Executables | |
*.exe | |
*.out | |
*.app | |
*.i*86 | |
*.x86_64 | |
*.hex | |
# Debug files | |
*.dSYM/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <openssl/sha.h> | |
#include "genhash.h" | |
const named_hash_func_t predefined_hash_funcs[] = { | |
{"SHA1", {SHA1, SHA_DIGEST_LENGTH}}, | |
{"SHA224", {SHA224, SHA224_DIGEST_LENGTH}}, | |
{"SHA256", {SHA256, SHA256_DIGEST_LENGTH}}, | |
{"SHA384", {SHA384, SHA384_DIGEST_LENGTH}}, | |
{"SHA512", {SHA512, SHA512_DIGEST_LENGTH}}, | |
}; | |
const size_t nhash = sizeof(predefined_hash_funcs)/sizeof(predefined_hash_funcs[0]); | |
hash_func_t select_hash_func(const char *name) | |
{ | |
const size_t N = 128; | |
for (size_t i = 0; i < nhash; i++) { | |
if (strncmp(name, predefined_hash_funcs[i].name, N) == 0) { | |
return predefined_hash_funcs[i].hash; | |
} | |
} | |
errno = EINVAL; | |
return (hash_func_t){NULL, 0}; | |
} | |
typedef union { | |
SHA_CTX SHA1; | |
SHA256_CTX SHA224; | |
SHA256_CTX SHA256; | |
SHA512_CTX SHA384; | |
SHA512_CTX SHA512; | |
} ctx_sha_family_t; | |
typedef struct { | |
ctx_sha_family_t base; | |
int status; | |
} ctx_sha_t; | |
#define DECLARE_HASH_INIT(name) \ | |
static int name##_init_(ctx_hash_func_t * ctx_) { \ | |
ctx_sha_t *ctx = (ctx_sha_t *)ctx_->ctx; \ | |
if ((ctx->status = name##_Init(&(ctx->base.name))) == 1) { \ | |
return E_OK; \ | |
} else { \ | |
return E_INTERNAL; \ | |
} \ | |
} | |
#define DECLARE_HASH_UPDATE(name) \ | |
static int name##_update_(ctx_hash_func_t * ctx_, const void *data, size_t len) { \ | |
ctx_sha_t *ctx = (ctx_sha_t *)ctx_->ctx; \ | |
if ((ctx->status = name##_Update(&(ctx->base.name), data, len)) == 1) { \ | |
return E_OK; \ | |
} else { \ | |
return E_INTERNAL; \ | |
} \ | |
} | |
#define DECLARE_HASH_FINAL(name) \ | |
static int name##_final_(ctx_hash_func_t * ctx_, unsigned char *md) { \ | |
ctx_sha_t *ctx = (ctx_sha_t *)ctx_->ctx; \ | |
if ((ctx->status = name##_Final(md, &(ctx->base.name))) == 1) { \ | |
return E_OK; \ | |
} else { \ | |
return E_INTERNAL; \ | |
} \ | |
} | |
#define DECLARE_HASH(name) \ | |
DECLARE_HASH_INIT(name) \ | |
DECLARE_HASH_UPDATE(name) \ | |
DECLARE_HASH_FINAL(name) | |
#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH | |
#define RECORD_HASH(name) { \ | |
{name##_DIGEST_LENGTH, name##_init_, name##_update_, name##_final_}, #name, \ | |
} | |
DECLARE_HASH(SHA1) | |
DECLARE_HASH(SHA224) | |
DECLARE_HASH(SHA256) | |
DECLARE_HASH(SHA384) | |
DECLARE_HASH(SHA512) | |
typedef struct { | |
const ctx_hash_funcs_vtbl_t vtbl; | |
const char *name; | |
} named_ctx_hash_funcs_vtbl_t; | |
static const named_ctx_hash_funcs_vtbl_t predefined_ctx_hash_funcs[] = { | |
RECORD_HASH(SHA1), | |
RECORD_HASH(SHA224), | |
RECORD_HASH(SHA256), | |
RECORD_HASH(SHA384), | |
RECORD_HASH(SHA512), | |
}; | |
static const ctx_hash_funcs_vtbl_t null_vtbl = {0, NULL, NULL, NULL}; | |
const ctx_hash_funcs_vtbl_t *select_ctx_hash_func(const char *name) | |
{ | |
const size_t N = 128; | |
for (size_t i = 0; i < nhash; i++) { | |
if (strncmp(name, predefined_ctx_hash_funcs[i].name, N) == 0) { | |
return &predefined_ctx_hash_funcs[i].vtbl; | |
} | |
} | |
errno = EINVAL; | |
return &null_vtbl; | |
} | |
errno_t hash_init(ctx_hash_func_t *ctx, const char *name) | |
{ | |
assert(ctx != NULL); | |
assert(ctx->ctx == NULL); | |
if ((ctx->vtbl = select_ctx_hash_func(name))->init == NULL) { | |
return E_INVAL; | |
} | |
if ((ctx->ctx = malloc(sizeof(ctx_sha_t))) == NULL) { | |
return E_NOMEM; | |
} | |
if (ctx->vtbl->init(ctx) != E_OK) { | |
free(ctx->ctx); | |
return E_FAIL; | |
} | |
return E_OK; | |
} | |
errno_t hash_update(ctx_hash_func_t *ctx, const void *data, size_t len) | |
{ | |
assert(ctx != NULL); | |
assert(data != NULL); | |
assert(ctx->vtbl->update != NULL); | |
if (ctx->vtbl->update(ctx, data, len) != E_OK) { | |
return E_FAIL; | |
} | |
return E_OK; | |
} | |
errno_t hash_final(ctx_hash_func_t *ctx, unsigned char *md) | |
{ | |
assert(ctx != NULL); | |
assert(ctx->vtbl->final != NULL); | |
int status = E_OK; | |
if (md != NULL) { | |
status = ctx->vtbl->final(ctx, md); | |
} | |
free(ctx->ctx); | |
if (status != E_OK) { | |
return E_FAIL; | |
} else { | |
return E_OK; | |
} | |
} | |
errno_t hash_apply(const char *name, const char *in, size_t bytes, unsigned char *out) | |
{ | |
ctx_hash_func_t h = make_ctx_hash(); | |
int status; | |
if ((status = hash_init(&h, name)) != E_OK) { | |
return status; | |
} | |
if ((status = hash_update(&h, in, bytes)) != E_OK) { | |
return status; | |
} | |
return hash_final(&h, out); | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <assert.h> | |
#include <stddef.h> | |
#include <stdbool.h> | |
#include <errno.h> | |
/** | |
* To detect that the C11 Annex K is used or not. | |
* */ | |
#if !defined(__STDC_WANT_LIB_EXT1__) || (__STDC_WANT_LIB_EXT1__ < 1) | |
#pragma message "The C11 Annex K is not used." | |
typedef int errno_t; | |
#endif | |
typedef struct { | |
unsigned char *(*func)(const unsigned char *in, size_t butes, unsigned char *out); | |
size_t digest_bytes; | |
} hash_func_t; | |
hash_func_t select_hash_func(const char *name); | |
typedef struct { | |
const char *name; | |
const hash_func_t hash; | |
} named_hash_func_t; | |
extern const named_hash_func_t predefined_hash_funcs[]; | |
extern const size_t nhash; | |
/* ==== */ | |
struct ctx_hash_func_t; | |
typedef struct { | |
const size_t digest_bytes; | |
int (*init)(struct ctx_hash_func_t *); | |
int (*update)(struct ctx_hash_func_t *, const void *data, size_t len); | |
int (*final)(struct ctx_hash_func_t *, unsigned char *md); | |
} ctx_hash_funcs_vtbl_t; | |
typedef struct ctx_hash_func_t { | |
const ctx_hash_funcs_vtbl_t *vtbl; | |
void *ctx; | |
errno_t status; | |
} ctx_hash_func_t; | |
enum { | |
E_OK = 0, | |
E_FAIL, | |
E_INVAL, | |
E_NOMEM, | |
E_INTERNAL, | |
}; | |
const ctx_hash_funcs_vtbl_t *select_ctx_hash_func(const char *name); | |
#define make_ctx_hash() {.ctx = NULL} | |
/** | |
* hash_init | |
* This function tries to allocate a memory. | |
* This allocation is succeeded if E_OK is returned. | |
* */ | |
errno_t hash_init(ctx_hash_func_t *ctx, const char *name); | |
errno_t hash_update(ctx_hash_func_t *ctx, const void *data, size_t len); | |
errno_t hash_final(ctx_hash_func_t *ctx, unsigned char *md); | |
errno_t hash_apply(const char *name, const char *in, size_t bytes, unsigned char *out); | |
static inline size_t hash_digest_bytes(const ctx_hash_func_t *ctx) | |
{ | |
assert(ctx != NULL); | |
assert(ctx->vtbl != NULL); | |
return ctx->vtbl->digest_bytes; | |
} | |
static inline bool hash_is_valid_ctx(const ctx_hash_func_t *ctx) | |
{ | |
assert(ctx != NULL); | |
assert(ctx->ctx != NULL); | |
return ctx->ctx != NULL; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stddef.h> | |
#include <string.h> | |
#include <errno.h> | |
#include "genhash.h" | |
#include "siphash.h" | |
static void print_chars(const unsigned char *cary, size_t n) | |
{ | |
for (size_t i = 0; i < n; i++) { | |
printf("%02x ", cary[i]); | |
} | |
printf("\n"); | |
} | |
static const size_t MAXLEN = 100; | |
static int test0(const char *name, const char *in) | |
{ | |
puts(__func__); | |
const hash_func_t h = select_hash_func(name); | |
if (h.func) { | |
unsigned char md[h.digest_bytes]; | |
h.func((const unsigned char *)in, strnlen(in, MAXLEN), md); | |
print_chars(md, h.digest_bytes); | |
} else { | |
perror("Not found hash function"); | |
printf("Available hash functions:\n"); | |
for (size_t i = 0; i < nhash; i++) { | |
printf("\t%s\n", predefined_hash_funcs[i].name); | |
} | |
return 1; | |
} | |
return 0; | |
} | |
static int test1(const char *name, const char *in) | |
{ | |
puts(__func__); | |
ctx_hash_func_t h = make_ctx_hash(); | |
hash_init(&h, name); | |
if (hash_is_valid_ctx(&h)) { | |
const char *cur = in; | |
size_t l; | |
while ((l = strnlen(cur, MAXLEN)) != 0) { | |
hash_update(&h, cur, l); | |
cur += l; | |
} | |
unsigned char md[hash_digest_bytes(&h)]; | |
hash_final(&h, md); | |
print_chars(md, hash_digest_bytes(&h)); | |
} else { | |
return 1; | |
} | |
return 0; | |
} | |
static int test2(void) | |
{ | |
puts(__func__); | |
ctx_siphash_t h = make_ctx_siphash(0, 1); | |
ctx_siphash_t h2 = make_ctx_siphash_by_chs(((unsigned char[]){[15] = 0, 1})); | |
return 0; | |
} | |
int main(int argc, char **argv) | |
{ | |
int retcode = 0; | |
if (argc > 2) { | |
retcode |= test0(argv[1], argv[2]); | |
retcode |= test1(argv[1], argv[2]); | |
retcode |= test2(); | |
} | |
return retcode; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CPPFLAGS = -std=c11 -g -pedantic | |
CFLAGS = -Wall -Wextra -O4 -MMD -MP -D__STDC_WANT_LIB_EXT1__=1 | |
LOADLIBES = -lcrypto | |
LDLIBS = libs.a | |
SRCS = $(shell ls -1 *.c) | |
TARGETS = libs.a hash.exe | |
ARCMEMS = $(filter-out $(addsuffix .o,$(basename $(filter %.exe,$(TARGETS)))),$(SRCS:%.c=%.o)) | |
.PHONY: all clean check | |
.PRECIOUS: %.o | |
all: $(TARGETS) | |
check: | |
for name in SHA1 SHA224 SHA256 SHA384 SHA512; do \ | |
valgrind -q --error-exitcode=1 ./hash.exe $$name "$(shell date)"; \ | |
done | |
clean: | |
$(RM) -r $(TARGETS) *~ .*~ *.o *.d *.dSYM | |
%.exe: %.o | |
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ | |
libs.a: $(ARCMEMS) | |
$(RM) $@ | |
$(AR) $(ARFLAGS) $@ $^ | |
-include $(SRCS:%.c=%.d) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "siphash.h" | |
errno_t siphash_init(ctx_hash_func_t *pCtx_) | |
{ | |
ctx_siphash_t *pCtx = (ctx_hash_func_t *)pCtx_; | |
pCtx->base.ctx = (void *)pCtx->v; | |
return E_OK; | |
} | |
typedef union { | |
unsigned char md[sizeof(uint64_t)]; | |
uint64_t v; | |
} siphash_output_t; | |
errno_t siphash_final(ctx_hash_func_t *pCtx_, unsigned char *md) | |
{ | |
ctx_siphash_t *pCtx = (ctx_hash_func_t *)pCtx_; | |
pCtx->v[2] ^= 0xff; | |
// TODO: not implemented yet. | |
siphash_output_t r; | |
r.v = pCtx->v[0] ^ pCtx->v[1] ^ pCtx->v[2] ^ pCtx->v[3]; | |
// TODO: endian. | |
for (size_t i = 0; i < sizeof(uint64_t); i++) { | |
md[i] = r.md[i]; | |
} | |
return E_OK; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <stdint.h> | |
#include "genhash.h" | |
extern const ctx_hash_funcs_vtbl_t siphash_vtbl; | |
typedef struct { | |
ctx_hash_func_t base; | |
uint64_t v[4]; | |
} ctx_siphash_t; | |
inline uint64_t uc8_to_ui64(const unsigned char cs[]) | |
{ | |
return *(uint64_t *)cs; | |
} | |
#define SIPHASH_INIT_V0 (0x736f6d6570736575ULL) | |
#define SIPHASH_INIT_V1 (0x646f72616e646f6dULL) | |
#define SIPHASH_INIT_V2 (0x6c7967656e657261ULL) | |
#define SIPHASH_INIT_V3 (0x7465646279746573ULL) | |
#define make_ctx_siphash(k0, k1) { \ | |
{&siphash_vtbl, NULL, E_OK}, \ | |
{ \ | |
k0 ^ SIPHASH_INIT_V0, \ | |
k1 ^ SIPHASH_INIT_V1, \ | |
k0 ^ SIPHASH_INIT_V2, \ | |
k1 ^ SIPHASH_INIT_V3, \ | |
}, \ | |
} | |
#define make_ctx_siphash_by_chs(chs) { \ | |
{&siphash_vtbl, NULL, E_OK}, \ | |
{ \ | |
uc8_to_ui64((chs)) ^ SIPHASH_INIT_V0, \ | |
uc8_to_ui64((chs + 8)) ^ SIPHASH_INIT_V1, \ | |
uc8_to_ui64((chs)) ^ SIPHASH_INIT_V2, \ | |
uc8_to_ui64((chs + 8)) ^ SIPHASH_INIT_V3, \ | |
}, \ | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment