Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hmac sha1 #14

Open
wants to merge 7 commits into
base: sha1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 223 additions & 0 deletions sys/hashes/sha1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/*
* Copyright (C) 2016 Oliver Hahm <oliver.hahm@inria.fr>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/* This code is public-domain - it is based on libcrypt
* placed in the public domain by Wei Dai and other contributors.
*/

/**
* @defgroup sys_hashes_sha1 SHA-1
* @ingroup sys_hashes
* @brief Implementation of the SHA-1 hashing function

* @{
*
* @file
* @brief SHA-1 interface definition
*
* @author Wei Dai and others
* @author Oliver Hahm <oliver.hahm@inria.fr>
*/

#include <stdint.h>
#include <string.h>

#include "hashes/sha1.h"

#define SHA1_K0 0x5a827999
#define SHA1_K20 0x6ed9eba1
#define SHA1_K40 0x8f1bbcdc
#define SHA1_K60 0xca62c1d6

void sha1_init(sha1_context *s)
{
s->state[0] = 0x67452301;
s->state[1] = 0xefcdab89;
s->state[2] = 0x98badcfe;
s->state[3] = 0x10325476;
s->state[4] = 0xc3d2e1f0;
s->byte_count = 0;
s->buffer_offset = 0;
}

uint32_t sha1_rol32(uint32_t number, uint8_t bits)
{
return ((number << bits) | (number >> (32 - bits)));
}

void sha1_hash_block(sha1_context *s)
{
uint8_t i;
uint32_t a, b, c, d, e, t;

a = s->state[0];
b = s->state[1];
c = s->state[2];
d = s->state[3];
e = s->state[4];
for (i = 0; i < 80; i++) {
if (i >= 16) {
t = s->buffer[(i + 13) & 15] ^ s->buffer[(i + 8) & 15] ^
s->buffer[(i + 2) & 15] ^ s->buffer[i & 15];
s->buffer[i & 15] = sha1_rol32(t, 1);
}
if (i < 20) {
t = (d ^ (b & (c ^ d))) + SHA1_K0;
}
else if (i < 40) {
t = (b ^ c ^ d) + SHA1_K20;
}
else if (i < 60) {
t = ((b & c) | (d & (b | c))) + SHA1_K40;
}
else {
t = (b ^ c ^ d) + SHA1_K60;
}
t += sha1_rol32(a, 5) + e + s->buffer[i & 15];
e = d;
d = c;
c = sha1_rol32(b, 30);
b = a;
a = t;
}
s->state[0] += a;
s->state[1] += b;
s->state[2] += c;
s->state[3] += d;
s->state[4] += e;
}

void sha1_add_uncounted(sha1_context *s, uint8_t data)
{
uint8_t *const b = (uint8_t *) s->buffer;

#ifdef __BIG_ENDIAN__
b[s->buffer_offset] = data;
#else
b[s->buffer_offset ^ 3] = data;
#endif
s->buffer_offset++;
if (s->buffer_offset == SHA1_BLOCK_LENGTH) {
sha1_hash_block(s);
s->buffer_offset = 0;
}
}

void sha1_update(sha1_context *s, const unsigned char *data, size_t len)
{
while (len--) {
++s->byte_count;
sha1_add_uncounted(s, *data++);
}
}

void sha1_pad(sha1_context *s)
{
/* Implement SHA-1 padding (fips180-2 §5.1.1) */

/* Pad with 0x80 followed by 0x00 until the end of the block */
sha1_add_uncounted(s, 0x80);
while (s->buffer_offset != 56) {
sha1_add_uncounted(s, 0x00);
}

/* Append length in the last 8 bytes */
sha1_add_uncounted(s, 0); /* We're only using 32 bit lengths */
sha1_add_uncounted(s, 0); /* But SHA-1 supports 64 bit lengths */
sha1_add_uncounted(s, 0); /* So zero pad the top bits */
sha1_add_uncounted(s, s->byte_count >> 29); /* Shifting to multiply by 8 */
sha1_add_uncounted(s, s->byte_count >> 21); /* as SHA-1 supports bitstreams as well as */
sha1_add_uncounted(s, s->byte_count >> 13); /* byte. */
sha1_add_uncounted(s, s->byte_count >> 5);
sha1_add_uncounted(s, s->byte_count << 3);
}

uint8_t *sha1_final(sha1_context *s)
{
/* Pad to complete the last block */
sha1_pad(s);

/* Swap byte order back */
for (int i = 0; i < 5; i++) {
s->state[i] =
(((s->state[i]) << 24) & 0xff000000)
| (((s->state[i]) << 8) & 0x00ff0000)
| (((s->state[i]) >> 8) & 0x0000ff00)
| (((s->state[i]) >> 24) & 0x000000ff);
}

/* Return pointer to hash (20 characters) */
return (uint8_t *) s->state;
}

void sha1(uint8_t *dst, const uint8_t *src, size_t len)
{
sha1_context ctx;
sha1_init(&ctx);
sha1_update(&ctx, (unsigned char*) src, len);
memcpy(dst, sha1_final(&ctx), SHA1_DIGEST_LENGTH);
}

unsigned char * hmac_sha1(const unsigned char *key,
size_t key_length,
const unsigned *message,
size_t message_length,
unsigned char *result)
{
unsigned char k[64];
memset((void *)k, 0x00, 64);

if (key_length > 64) {
sha1((uint8_t*)k, key, key_length);
}
else {
memcpy((void *)k, key, key_length);
}

/*
* create the inner and outer keypads
* rising hamming distance enforcing i_* and o_* are distinct
* in at least one bit
*/
unsigned char o_key_pad[64];
unsigned char i_key_pad[64];

for (size_t i = 0; i < 64; ++i) {
o_key_pad[i] = 0x5c^k[i];
i_key_pad[i] = 0x36^k[i];
}

/*
* Create the inner hash
* tmp = hash(i_key_pad CONCAT message)
*/
sha1_context c;
unsigned char tmp[SHA1_DIGEST_LENGTH];

sha1_init(&c);
sha1_update(&c, i_key_pad, 64);
sha1_update(&c, (unsigned char *)message, message_length);
memcpy(tmp, sha1_final(&c), SHA1_DIGEST_LENGTH);

static unsigned char m[SHA1_DIGEST_LENGTH];

if (result == NULL) {
result = m;
}

/*
* Create the outer hash
* result = hash(o_key_pad CONCAT tmp)
*/
sha1_init(&c);
sha1_update(&c, o_key_pad, 64);
sha1_update(&c, tmp, SHA1_DIGEST_LENGTH);
memcpy(result, sha1_final(&c), SHA1_DIGEST_LENGTH);

return result;
}
111 changes: 111 additions & 0 deletions sys/include/hashes/sha1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright (C) 2016 Oliver Hahm <oliver.hahm@inria.fr>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @defgroup sys_hashes_sha1 SHA-1
* @ingroup sys_hashes
* @brief Implementation of the SHA-1 hashing function

* @{
*
* @file
* @brief SHA-1 interface definition
*
* @author Wei Dai and others
* @author Oliver Hahm <oliver.hahm@inria.fr>
*/

/* This code is public-domain - it is based on libcrypt
* placed in the public domain by Wei Dai and other contributors. */

#ifndef _SHA1_H
#define _SHA1_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Length of SHA-1 digests in byte
*/
#define SHA1_DIGEST_LENGTH (20)

/**
* @brief Length of SHA-1 block in byte
*/
#define SHA1_BLOCK_LENGTH (64)

/**
* @brief SHA-1 algorithm context
* */
typedef struct {
uint32_t buffer[SHA1_BLOCK_LENGTH / sizeof(uint32_t)]; /**< @internal */
uint32_t state[SHA1_DIGEST_LENGTH / sizeof(uint32_t)]; /**< @internal */
uint32_t byte_count; /**< @internal */
uint8_t buffer_offset; /**< @internal */
} sha1_context;


/**
* @brief Initialize SHA-1 message digest context
*
* @param[in] s Pointer to the SHA-1 context to initialize
*/
void sha1_init(sha1_context *s);

/**
* @brief Update the SHA-1 context with a portion of the message being hashed
*
* @param[in] s Pointer to the SHA-1 context to update
* @param[in] data Pointer to the buffer to be hashed
* @param[in] len Length of the buffer
*/
void sha1_update(sha1_context *s, const unsigned char *data, size_t len);
/**
* @brief Finalizes the SHA-1 message digest
*
* @param[in] s Pointer to the SHA-1 contex
*
* @return Caluclated digest
*/
uint8_t *sha1_final(sha1_context *s);

/**
* @brief Calculate a SHA1 hash from the given data
*
* @param[out] dst Result location, must be 20 byte
* @param[in] src Input data
* @param[in] len Length of @p buf
*/
void sha1(uint8_t *dst, const uint8_t *src, size_t len);

/**
* @brief function to compute a hmac-sha1 from a given message
*
* @param[in] key key used in the hmac-sha1 computation
* @param[in] key_length the size in bytes of the key
* @param[in] message poiter to the message to generate the hmac-sha1
* @param[in] message_length the length of the message in bytes
* @param[out] result the computed hmac-sha1,
* length MUST be SHA1_DIGEST_LENGTH
* if result == NULL, a static buffer is used
*/
unsigned char * hmac_sha1(const unsigned char *key,
size_t key_length,
const unsigned *message,
size_t message_length,
unsigned char *result);

#ifdef __cplusplus
}
#endif

#endif /* _SHA1_H */
/** @} */
Loading