Name: Anonymous 2009-04-24 11:40
Hey /prog/, here's something I started a few months ago, and just found and improved upon some more recently. It's a hash function based an the XTEA block cipher. It's faster than MD5, though I can't attest to its security. I'm particularly concerned that short messages may be insecure, since it only uses four rounds (two cycles) of XTEA.
xtash.c
xtash.c
/*******************************************************************************
* xtash.c -- a hash function based on XTEA. *
* Copyright (c) 2009, Samuel Fredrickson <kinghajj@gmail.com>; *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions are met: *
* * Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* * Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS *
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY *
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
* DAMAGE. *
******************************************************************************/
/*******************************************************************************
* XTASH is a Merkle-Damgard construction hash function that uses XTEA as a *
* one-way compression function using the Davies-Meyer method. To speed things *
* up, only two XTEA cycles are performed per compression, which probably *
* doesn't help with its security. *
* *
* Simple tests appear to show a good avalanche effect, but I don't reccommend *
* anyone use this for anything serious, as I'm an amateur cryptographer. *
* *
* I've tested this on both big- and little-endian machines, and both provide *
* the same results. This code may run faster on a big-endian machine, because *
* there's less swapping. However, since I'm using ntohl and htonl, swapping *
* should be faster on processors with a byteswap instruction. *
* *
* Because XTEA operates on 64-bit blocks with a 128-bit key, the compression *
* function enciphers both halves of the previous state with the input message *
* block. *
******************************************************************************/
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include "xtash.h"
/* Converts an array of 4 bytes into a 32-bit integer. */
static inline uint32_t UInt8s_To_UInt32(uint8_t in[4])
{
return ntohl(*(uint32_t*)in);
}
/* Converts a 32-bit integer into an array of 4 bytes. */
static inline void UInt32_To_UInt8s(uint32_t in, uint8_t out[4])
{
*(uint32_t*)out = htonl(in);
}
/* The XTEA encryption function. */
static inline void encipher(uint32_t v[2], uint32_t k[4])
{
const static uint32_t XTEA_CYCLES = 2;
uint32_t v0=v[0], v1=v[1], i;
uint32_t sum = 0, delta = 0x9e3779b9;
for(i = 0; i < XTEA_CYCLES; ++i) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]);
}
v[0] = v0, v[1] = v1;
}
/* The XTASH compression function. */
static inline void compress(uint32_t a[4], uint32_t b[4])
{
// just a simple compression function, but it seems to work decently.
encipher(a, b);
encipher(&a[2], b);
}
/* Converts the data to uint32_t, then calls compress(). */
static inline void compress_data(XTASH_State *state, uint8_t *data)
{
uint32_t b[4];
// construct a uint32_t block from the data.
b[0] = UInt8s_To_UInt32(data);
b[1] = UInt8s_To_UInt32(data + 4);
b[2] = UInt8s_To_UInt32(data + 8);
b[3] = UInt8s_To_UInt32(data + 12);
// compress it.
compress(state->state, b);
}
/* Initializes a hash state with the IV. */
void XTASH_Init (XTASH_State *state)
{
// this is the md5 sum of "XTASH\n". probably not the best IV.
const static uint32_t iv[4] =
{ 0x6a39cda1, 0x62a1c9dd, 0xf41a42cc, 0x28a638f4 };
memcpy(state->state, iv, XTASH_DIGEST_SIZE);
state->length = 0;
state->leftover = 0;
}
/* Updates the hash state with new data. */
void XTASH_Update(XTASH_State *state, uint8_t *data, uint64_t len)
{
if(!len) return;
state->length += len;
// if there are leftovers,
if(state->leftover) {
// fill the rest of the leftover block as much as possible.
while(len && state->leftover < XTASH_DIGEST_SIZE)
state->data[state->leftover++] = *data++, len--;
// if we're full of leftovers, use them and move on.
if(state->leftover == XTASH_DIGEST_SIZE)
compress_data(state, state->data), state->leftover = 0;
}
// while we have enough for one block,
while(len >= XTASH_DIGEST_SIZE) {
compress_data(state, data);
len -= XTASH_DIGEST_SIZE;
data += XTASH_DIGEST_SIZE;
}
// if there are leftovers, save them.
if(len) memcpy(state->data, data, (state->leftover = (uint8_t)len));
}
/* Finalizes a hash state into a digest. */
void XTASH_Final(XTASH_State *state, uint8_t *sum)
{
uint32_t block[4];
uint8_t fluff[XTASH_DIGEST_SIZE];
// flush any leftovers.
if(state->leftover) {
memset(fluff, 0, XTASH_DIGEST_SIZE);
XTASH_Update(state, fluff, XTASH_DIGEST_SIZE - state->leftover);
}
// create a block with the message length and compress it.
block[0] = state->length & (~UINT32_MAX);
block[1] = state->length & UINT32_MAX;
block[2] = block[3] = 0;
compress(state->state, block);
// put state into the sum array.
UInt32_To_UInt8s(state->state[0], sum);
UInt32_To_UInt8s(state->state[1], sum + 4);
UInt32_To_UInt8s(state->state[2], sum + 8);
UInt32_To_UInt8s(state->state[3], sum + 12);
}
/* Streams data from a file and calculates the digest. */
void XTASH_Stream(FILE *f, uint8_t *digest)
{
const size_t buffer_size = 4096;
uint8_t buffer[buffer_size];
XTASH_State state;
size_t read;
XTASH_Init(&state);
while((read = fread(buffer, 1, buffer_size, f)))
XTASH_Update(&state, buffer, read);
XTASH_Final(&state, digest);
}
#ifdef XTASH_MAIN
int main()
{
uint8_t digest[XTASH_DIGEST_SIZE];
int i;
XTASH_Stream(stdin, digest);
for(i = 0; i < XTASH_DIGEST_SIZE; i++)
printf("%02x", digest[i]);
fputc('\n', stdout);
return 0;
}
#endif