Merge branch 'upstream-librhash' into import-librhash

* upstream-librhash:
  librhash 2016-11-01 (d839a1a8)
This commit is contained in:
Brad King 2016-11-03 13:45:29 -04:00
commit 5cb1b345d9
21 changed files with 3238 additions and 0 deletions

1
Utilities/cmlibrhash/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* -whitespace

View File

@ -0,0 +1,15 @@
RHash License
Copyright (c) 2005-2014 Aleksey Kravchenko <rhash.admin@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so.
The Software is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Use this program at your own risk!

View File

@ -0,0 +1,61 @@
=== RHash program ===
RHash is a console utility for calculation and verification of magnet links
and a wide range of hash sums like CRC32, MD4, MD5, SHA1, SHA256, SHA512,
SHA3, AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94,
RIPEMD-160, HAS-160, EDON-R, Whirlpool and Snefru.
Hash sums are used to ensure and verify integrity of large volumes of data
for a long-term storing or transferring.
Features:
* Output in a predefined (SFV, BSD-like) or a user-defined format.
* Can calculate Magnet links.
* Updating hash files (adding hash sums of files missing in the hash file).
* Calculates several hash sums in one pass
* Ability to process directories recursively.
* Portability: the program works the same on Linux, *BSD or Windows.
=== The LibRHash library ===
LibRHash is a professional, portable, thread-safe C library for computing
a wide variety of hash sums, such as CRC32, MD4, MD5, SHA1, SHA256, SHA512,
SHA3, AICH, ED2K, Tiger, DC++ TTH, BitTorrent BTIH, GOST R 34.11-94,
RIPEMD-160, HAS-160, EDON-R, Whirlpool and Snefru.
Hash sums are used to ensure and verify integrity of large volumes of data
for a long-term storing or transferring.
Features:
* Small and easy to learn interface.
* Hi-level and Low-level API.
* Allows calculating of several hash functions simultaneously.
* Portability: the library works on Linux, *BSD and Windows.
=== Links ===
* Project Home Page: http://rhash.sourceforge.net/
* Official Releases: http://sf.net/projects/rhash/files/rhash/
* RHash hash functions descriptions http://rhash.anz.ru/hashes.php
* The table of the hash functions supported by RHash
http://sf.net/apps/mediawiki/rhash/index.php?title=Hash_sums
* ECRYPT: The Hash Function Zoo
http://ehash.iaik.tugraz.at/wiki/The_Hash_Function_Zoo
=== Getting latest source code ===
The latest source code can be obtained from Git repository by command:
git clone git://github.com/rhash/RHash.git
=== Notes on RHash License ===
The RHash program and LibRHash library are distributed under RHash License,
see the COPYING file for details. In particular, the program, the library
and source code can be used free of charge under the MIT, BSD, GPL,
commercial or freeware license without additional restrictions. In the case
the OSI-approved license is required the MIT license should be used.

View File

@ -0,0 +1,200 @@
/* algorithms.c - the algorithms supported by the rhash library
*
* Copyright: 2011-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
#include <stdio.h>
#include <assert.h>
#include "byte_order.h"
#include "rhash.h"
#include "algorithms.h"
/* header files of all supported hash sums */
#include "aich.h"
#include "crc32.h"
#include "ed2k.h"
#include "edonr.h"
#include "gost.h"
#include "has160.h"
#include "md4.h"
#include "md5.h"
#include "ripemd-160.h"
#include "snefru.h"
#include "sha1.h"
#include "sha256.h"
#include "sha512.h"
#include "sha3.h"
#include "tiger.h"
#include "torrent.h"
#include "tth.h"
#include "whirlpool.h"
#ifdef USE_OPENSSL
/* note: BTIH and AICH depends on the used SHA1 algorithm */
# define NEED_OPENSSL_INIT (RHASH_MD4 | RHASH_MD5 | \
RHASH_SHA1 | RHASH_SHA224 | RHASH_SHA256 | RHASH_SHA384 | RHASH_SHA512 | \
RHASH_BTIH | RHASH_AICH | RHASH_RIPEMD160 | RHASH_WHIRLPOOL)
#else
# define NEED_OPENSSL_INIT 0
#endif /* USE_OPENSSL */
#ifdef GENERATE_GOST_LOOKUP_TABLE
# define NEED_GOST_INIT (RHASH_GOST | RHASH_GOST_CRYPTOPRO)
#else
# define NEED_GOST_INIT 0
#endif /* GENERATE_GOST_LOOKUP_TABLE */
#ifdef GENERATE_CRC32_TABLE
# define NEED_CRC32_INIT RHASH_CRC32
#else
# define NEED_CRC32_INIT 0
#endif /* GENERATE_CRC32_TABLE */
#define RHASH_NEED_INIT_ALG (NEED_CRC32_INIT | NEED_GOST_INIT | NEED_OPENSSL_INIT)
unsigned rhash_uninitialized_algorithms = RHASH_NEED_INIT_ALG;
rhash_hash_info* rhash_info_table = rhash_hash_info_default;
int rhash_info_size = RHASH_HASH_COUNT;
static void rhash_crc32_init(uint32_t* crc32);
static void rhash_crc32_update(uint32_t* crc32, const unsigned char* msg, size_t size);
static void rhash_crc32_final(uint32_t* crc32, unsigned char* result);
rhash_info info_crc32 = { RHASH_CRC32, F_BE32, 4, "CRC32", "crc32" };
rhash_info info_md4 = { RHASH_MD4, F_LE32, 16, "MD4", "md4" };
rhash_info info_md5 = { RHASH_MD5, F_LE32, 16, "MD5", "md5" };
rhash_info info_sha1 = { RHASH_SHA1, F_BE32, 20, "SHA1", "sha1" };
rhash_info info_tiger = { RHASH_TIGER, F_LE64, 24, "TIGER", "tiger" };
rhash_info info_tth = { RHASH_TTH, F_BS32, 24, "TTH", "tree:tiger" };
rhash_info info_btih = { RHASH_BTIH, 0, 20, "BTIH", "btih" };
rhash_info info_ed2k = { RHASH_ED2K, F_LE32, 16, "ED2K", "ed2k" };
rhash_info info_aich = { RHASH_AICH, F_BS32, 20, "AICH", "aich" };
rhash_info info_whirlpool = { RHASH_WHIRLPOOL, F_BE64, 64, "WHIRLPOOL", "whirlpool" };
rhash_info info_rmd160 = { RHASH_RIPEMD160, F_LE32, 20, "RIPEMD-160", "ripemd160" };
rhash_info info_gost = { RHASH_GOST, F_LE32, 32, "GOST", "gost" };
rhash_info info_gostpro = { RHASH_GOST_CRYPTOPRO, F_LE32, 32, "GOST-CRYPTOPRO", "gost-cryptopro" };
rhash_info info_has160 = { RHASH_HAS160, F_LE32, 20, "HAS-160", "has160" };
rhash_info info_snf128 = { RHASH_SNEFRU128, F_BE32, 16, "SNEFRU-128", "snefru128" };
rhash_info info_snf256 = { RHASH_SNEFRU256, F_BE32, 32, "SNEFRU-256", "snefru256" };
rhash_info info_sha224 = { RHASH_SHA224, F_BE32, 28, "SHA-224", "sha224" };
rhash_info info_sha256 = { RHASH_SHA256, F_BE32, 32, "SHA-256", "sha256" };
rhash_info info_sha384 = { RHASH_SHA384, F_BE64, 48, "SHA-384", "sha384" };
rhash_info info_sha512 = { RHASH_SHA512, F_BE64, 64, "SHA-512", "sha512" };
rhash_info info_edr256 = { RHASH_EDONR256, F_LE32, 32, "EDON-R256", "edon-r256" };
rhash_info info_edr512 = { RHASH_EDONR512, F_LE64, 64, "EDON-R512", "edon-r512" };
rhash_info info_sha3_224 = { RHASH_SHA3_224, F_LE64, 28, "SHA3-224", "sha3-224" };
rhash_info info_sha3_256 = { RHASH_SHA3_256, F_LE64, 32, "SHA3-256", "sha3-256" };
rhash_info info_sha3_384 = { RHASH_SHA3_384, F_LE64, 48, "SHA3-384", "sha3-384" };
rhash_info info_sha3_512 = { RHASH_SHA3_512, F_LE64, 64, "SHA3-512", "sha3-512" };
/* some helper macros */
#define dgshft(name) (((char*)&((name##_ctx*)0)->hash) - (char*)0)
#define dgshft2(name, field) (((char*)&((name##_ctx*)0)->field) - (char*)0)
#define ini(name) ((pinit_t)(name##_init))
#define upd(name) ((pupdate_t)(name##_update))
#define fin(name) ((pfinal_t)(name##_final))
#define iuf(name) ini(name), upd(name), fin(name)
#define diuf(name) dgshft(name), ini(name), upd(name), fin(name)
/* information about all hashes */
rhash_hash_info rhash_hash_info_default[RHASH_HASH_COUNT] =
{
{ &info_crc32, sizeof(uint32_t), 0, iuf(rhash_crc32), 0 }, /* 32 bit */
{ &info_md4, sizeof(md4_ctx), dgshft(md4), iuf(rhash_md4), 0 }, /* 128 bit */
{ &info_md5, sizeof(md5_ctx), dgshft(md5), iuf(rhash_md5), 0 }, /* 128 bit */
{ &info_sha1, sizeof(sha1_ctx), dgshft(sha1), iuf(rhash_sha1), 0 }, /* 160 bit */
{ &info_tiger, sizeof(tiger_ctx), dgshft(tiger), iuf(rhash_tiger), 0 }, /* 192 bit */
{ &info_tth, sizeof(tth_ctx), dgshft2(tth, tiger.hash), iuf(rhash_tth), 0 }, /* 192 bit */
{ &info_btih, sizeof(torrent_ctx), dgshft2(torrent, btih), iuf(bt), (pcleanup_t)bt_cleanup }, /* 160 bit */
{ &info_ed2k, sizeof(ed2k_ctx), dgshft2(ed2k, md4_context_inner.hash), iuf(rhash_ed2k), 0 }, /* 128 bit */
{ &info_aich, sizeof(aich_ctx), dgshft2(aich, sha1_context.hash), iuf(rhash_aich), (pcleanup_t)rhash_aich_cleanup }, /* 160 bit */
{ &info_whirlpool, sizeof(whirlpool_ctx), dgshft(whirlpool), iuf(rhash_whirlpool), 0 }, /* 512 bit */
{ &info_rmd160, sizeof(ripemd160_ctx), dgshft(ripemd160), iuf(rhash_ripemd160), 0 }, /* 160 bit */
{ &info_gost, sizeof(gost_ctx), dgshft(gost), iuf(rhash_gost), 0 }, /* 256 bit */
{ &info_gostpro, sizeof(gost_ctx), dgshft(gost), ini(rhash_gost_cryptopro), upd(rhash_gost), fin(rhash_gost), 0 }, /* 256 bit */
{ &info_has160, sizeof(has160_ctx), dgshft(has160), iuf(rhash_has160), 0 }, /* 160 bit */
{ &info_snf128, sizeof(snefru_ctx), dgshft(snefru), ini(rhash_snefru128), upd(rhash_snefru), fin(rhash_snefru), 0 }, /* 128 bit */
{ &info_snf256, sizeof(snefru_ctx), dgshft(snefru), ini(rhash_snefru256), upd(rhash_snefru), fin(rhash_snefru), 0 }, /* 256 bit */
{ &info_sha224, sizeof(sha256_ctx), dgshft(sha256), ini(rhash_sha224), upd(rhash_sha256), fin(rhash_sha256), 0 }, /* 224 bit */
{ &info_sha256, sizeof(sha256_ctx), dgshft(sha256), iuf(rhash_sha256), 0 }, /* 256 bit */
{ &info_sha384, sizeof(sha512_ctx), dgshft(sha512), ini(rhash_sha384), upd(rhash_sha512), fin(rhash_sha512), 0 }, /* 384 bit */
{ &info_sha512, sizeof(sha512_ctx), dgshft(sha512), iuf(rhash_sha512), 0 }, /* 512 bit */
{ &info_edr256, sizeof(edonr_ctx), dgshft2(edonr, u.data256.hash) + 32, iuf(rhash_edonr256), 0 }, /* 256 bit */
{ &info_edr512, sizeof(edonr_ctx), dgshft2(edonr, u.data512.hash) + 64, iuf(rhash_edonr512), 0 }, /* 512 bit */
{ &info_sha3_224, sizeof(sha3_ctx), dgshft(sha3), ini(rhash_sha3_224), upd(rhash_sha3), fin(rhash_sha3), 0 }, /* 224 bit */
{ &info_sha3_256, sizeof(sha3_ctx), dgshft(sha3), ini(rhash_sha3_256), upd(rhash_sha3), fin(rhash_sha3), 0 }, /* 256 bit */
{ &info_sha3_384, sizeof(sha3_ctx), dgshft(sha3), ini(rhash_sha3_384), upd(rhash_sha3), fin(rhash_sha3), 0 }, /* 384 bit */
{ &info_sha3_512, sizeof(sha3_ctx), dgshft(sha3), ini(rhash_sha3_512), upd(rhash_sha3), fin(rhash_sha3), 0 }, /* 512 bit */
};
/**
* Initialize requested algorithms.
*/
void rhash_init_algorithms(unsigned mask)
{
(void)mask; /* unused now */
/* verify that RHASH_HASH_COUNT is the index of the major bit of RHASH_ALL_HASHES */
assert(1 == (RHASH_ALL_HASHES >> (RHASH_HASH_COUNT - 1)));
#ifdef GENERATE_CRC32_TABLE
rhash_crc32_init_table();
#endif
#ifdef GENERATE_GOST_LOOKUP_TABLE
rhash_gost_init_table();
#endif
rhash_uninitialized_algorithms = 0;
}
/* CRC32 helper functions */
/**
* Initialize crc32 hash.
*
* @param crc32 pointer to the hash to initialize
*/
static void rhash_crc32_init(uint32_t* crc32)
{
*crc32 = 0; /* note: context size is sizeof(uint32_t) */
}
/**
* Calculate message CRC32 hash.
* Can be called repeatedly with chunks of the message to be hashed.
*
* @param crc32 pointer to the hash
* @param msg message chunk
* @param size length of the message chunk
*/
static void rhash_crc32_update(uint32_t* crc32, const unsigned char* msg, size_t size)
{
*crc32 = rhash_get_crc32(*crc32, msg, size);
}
/**
* Store calculated hash into the given array.
*
* @param crc32 pointer to the current hash value
* @param result calculated hash in binary form
*/
static void rhash_crc32_final(uint32_t* crc32, unsigned char* result)
{
#if defined(CPU_IA32) || defined(CPU_X64)
/* intel CPUs support assigment with non 32-bit aligned pointers */
*(unsigned*)result = be2me_32(*crc32);
#else
/* correct saving BigEndian integer on all archs */
result[0] = (unsigned char)(*crc32 >> 24), result[1] = (unsigned char)(*crc32 >> 16);
result[2] = (unsigned char)(*crc32 >> 8), result[3] = (unsigned char)(*crc32);
#endif
}

View File

@ -0,0 +1,120 @@
/* algorithms.h - rhash library algorithms */
#ifndef RHASH_ALGORITHMS_H
#define RHASH_ALGORITHMS_H
#include <stddef.h> /* for ptrdiff_t */
#include "rhash.h"
#include "byte_order.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef RHASH_API
/* modifier for RHash library functions */
# define RHASH_API
#endif
typedef void (*pinit_t)(void*);
typedef void (*pupdate_t)(void *ctx, const void* msg, size_t size);
typedef void (*pfinal_t)(void*, unsigned char*);
typedef void (*pcleanup_t)(void*);
/**
* Information about a hash function
*/
typedef struct rhash_hash_info
{
rhash_info *info;
size_t context_size;
ptrdiff_t digest_diff;
pinit_t init;
pupdate_t update;
pfinal_t final;
pcleanup_t cleanup;
} rhash_hash_info;
/**
* Information on a hash function and its context
*/
typedef struct rhash_vector_item
{
struct rhash_hash_info* hash_info;
void *context;
} rhash_vector_item;
/**
* The rhash context containing contexts for several hash functions
*/
typedef struct rhash_context_ext
{
struct rhash_context rc;
unsigned hash_vector_size; /* number of contained hash sums */
unsigned flags;
unsigned state;
void *callback, *callback_data;
void *bt_ctx;
rhash_vector_item vector[1]; /* contexts of contained hash sums */
} rhash_context_ext;
extern rhash_hash_info rhash_hash_info_default[RHASH_HASH_COUNT];
extern rhash_hash_info* rhash_info_table;
extern int rhash_info_size;
extern unsigned rhash_uninitialized_algorithms;
extern rhash_info info_crc32;
extern rhash_info info_md4;
extern rhash_info info_md5;
extern rhash_info info_sha1;
extern rhash_info info_tiger;
extern rhash_info info_tth ;
extern rhash_info info_btih;
extern rhash_info info_ed2k;
extern rhash_info info_aich;
extern rhash_info info_whirlpool;
extern rhash_info info_rmd160;
extern rhash_info info_gost;
extern rhash_info info_gostpro;
extern rhash_info info_has160;
extern rhash_info info_snf128;
extern rhash_info info_snf256;
extern rhash_info info_sha224;
extern rhash_info info_sha256;
extern rhash_info info_sha384;
extern rhash_info info_sha512;
extern rhash_info info_sha3_224;
extern rhash_info info_sha3_256;
extern rhash_info info_sha3_384;
extern rhash_info info_sha3_512;
extern rhash_info info_edr256;
extern rhash_info info_edr512;
/* rhash_info flags */
#define F_BS32 1 /* default output in base32 */
#define F_SWAP32 2 /* Big endian flag */
#define F_SWAP64 4
/* define endianness flags */
#ifndef CPU_BIG_ENDIAN
#define F_LE32 0
#define F_LE64 0
#define F_BE32 F_SWAP32
#define F_BE64 F_SWAP64
#else
#define F_LE32 F_SWAP32
#define F_LE64 F_SWAP64
#define F_BE32 0
#define F_BE64 0
#endif
void rhash_init_algorithms(unsigned mask);
#if defined(OPENSSL_RUNTIME) && !defined(USE_OPENSSL)
# define USE_OPENSSL
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* RHASH_ALGORITHMS_H */

View File

@ -0,0 +1,150 @@
/* byte_order.c - byte order related platform dependent routines,
*
* Copyright: 2008-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
#include "byte_order.h"
#if !(__GNUC__ >= 4 || (__GNUC__ ==3 && __GNUC_MINOR__ >= 4)) /* if !GCC or GCC < 4.3 */
# if _MSC_VER >= 1300 && (_M_IX86 || _M_AMD64 || _M_IA64) /* if MSVC++ >= 2002 on x86/x64 */
# include <intrin.h>
# pragma intrinsic(_BitScanForward)
/**
* Returns index of the trailing bit of x.
*
* @param x the number to process
* @return zero-based index of the trailing bit
*/
unsigned rhash_ctz(unsigned x)
{
unsigned long index;
unsigned char isNonzero = _BitScanForward(&index, x); /* MSVC intrinsic */
return (isNonzero ? (unsigned)index : 0);
}
# else /* _MSC_VER >= 1300... */
/**
* Returns index of the trailing bit of a 32-bit number.
* This is a plain C equivalent for GCC __builtin_ctz() bit scan.
*
* @param x the number to process
* @return zero-based index of the trailing bit
*/
unsigned rhash_ctz(unsigned x)
{
/* array for conversion to bit position */
static unsigned char bit_pos[32] = {
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
/* The De Bruijn bit-scan was devised in 1997, according to Donald Knuth
* by Martin Lauter. The constant 0x077CB531UL is a De Bruijn sequence,
* which produces a unique pattern of bits into the high 5 bits for each
* possible bit position that it is multiplied against.
* See http://graphics.stanford.edu/~seander/bithacks.html
* and http://chessprogramming.wikispaces.com/BitScan */
return (unsigned)bit_pos[((uint32_t)((x & -x) * 0x077CB531U)) >> 27];
}
# endif /* _MSC_VER >= 1300... */
#endif /* !(GCC >= 4.3) */
/**
* Copy a memory block with simultaneous exchanging byte order.
* The byte order is changed from little-endian 32-bit integers
* to big-endian (or vice-versa).
*
* @param to the pointer where to copy memory block
* @param index the index to start writing from
* @param from the source block to copy
* @param length length of the memory block
*/
void rhash_swap_copy_str_to_u32(void* to, int index, const void* from, size_t length)
{
/* if all pointers and length are 32-bits aligned */
if ( 0 == (( (int)((char*)to - (char*)0) | ((char*)from - (char*)0) | index | length ) & 3) ) {
/* copy memory as 32-bit words */
const uint32_t* src = (const uint32_t*)from;
const uint32_t* end = (const uint32_t*)((const char*)src + length);
uint32_t* dst = (uint32_t*)((char*)to + index);
while (src < end) *(dst++) = bswap_32( *(src++) );
} else {
const char* src = (const char*)from;
for (length += index; (size_t)index < length; index++) ((char*)to)[index ^ 3] = *(src++);
}
}
/**
* Copy a memory block with changed byte order.
* The byte order is changed from little-endian 64-bit integers
* to big-endian (or vice-versa).
*
* @param to the pointer where to copy memory block
* @param index the index to start writing from
* @param from the source block to copy
* @param length length of the memory block
*/
void rhash_swap_copy_str_to_u64(void* to, int index, const void* from, size_t length)
{
/* if all pointers and length are 64-bits aligned */
if ( 0 == (( (int)((char*)to - (char*)0) | ((char*)from - (char*)0) | index | length ) & 7) ) {
/* copy aligned memory block as 64-bit integers */
const uint64_t* src = (const uint64_t*)from;
const uint64_t* end = (const uint64_t*)((const char*)src + length);
uint64_t* dst = (uint64_t*)((char*)to + index);
while (src < end) *(dst++) = bswap_64( *(src++) );
} else {
const char* src = (const char*)from;
for (length += index; (size_t)index < length; index++) ((char*)to)[index ^ 7] = *(src++);
}
}
/**
* Copy data from a sequence of 64-bit words to a binary string of given length,
* while changing byte order.
*
* @param to the binary string to receive data
* @param from the source sequence of 64-bit words
* @param length the size in bytes of the data being copied
*/
void rhash_swap_copy_u64_to_str(void* to, const void* from, size_t length)
{
/* if all pointers and length are 64-bits aligned */
if ( 0 == (( (int)((char*)to - (char*)0) | ((char*)from - (char*)0) | length ) & 7) ) {
/* copy aligned memory block as 64-bit integers */
const uint64_t* src = (const uint64_t*)from;
const uint64_t* end = (const uint64_t*)((const char*)src + length);
uint64_t* dst = (uint64_t*)to;
while (src < end) *(dst++) = bswap_64( *(src++) );
} else {
size_t index;
char* dst = (char*)to;
for (index = 0; index < length; index++) *(dst++) = ((char*)from)[index ^ 7];
}
}
/**
* Exchange byte order in the given array of 32-bit integers.
*
* @param arr the array to process
* @param length array length
*/
void rhash_u32_mem_swap(unsigned *arr, int length)
{
unsigned* end = arr + length;
for (; arr < end; arr++) {
*arr = bswap_32(*arr);
}
}

View File

@ -0,0 +1,171 @@
/* byte_order.h */
#ifndef BYTE_ORDER_H
#define BYTE_ORDER_H
#include "ustd.h"
#include <stdlib.h>
#ifdef IN_RHASH
#include "config.h"
#endif
#ifdef __GLIBC__
# include <endian.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* if x86 compatible cpu */
#if defined(i386) || defined(__i386__) || defined(__i486__) || \
defined(__i586__) || defined(__i686__) || defined(__pentium__) || \
defined(__pentiumpro__) || defined(__pentium4__) || \
defined(__nocona__) || defined(prescott) || defined(__core2__) || \
defined(__k6__) || defined(__k8__) || defined(__athlon__) || \
defined(__amd64) || defined(__amd64__) || \
defined(__x86_64) || defined(__x86_64__) || defined(_M_IX86) || \
defined(_M_AMD64) || defined(_M_IA64) || defined(_M_X64)
/* detect if x86-64 instruction set is supported */
# if defined(_LP64) || defined(__LP64__) || defined(__x86_64) || \
defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
# define CPU_X64
# else
# define CPU_IA32
# endif
#endif
/* detect CPU endianness */
#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
__BYTE_ORDER == __LITTLE_ENDIAN) || \
defined(CPU_IA32) || defined(CPU_X64) || \
defined(__ia64) || defined(__ia64__) || defined(__alpha__) || defined(_M_ALPHA) || \
defined(vax) || defined(MIPSEL) || defined(_ARM_) || defined(__arm__)
# define CPU_LITTLE_ENDIAN
# define IS_BIG_ENDIAN 0
# define IS_LITTLE_ENDIAN 1
#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
__BYTE_ORDER == __BIG_ENDIAN) || \
defined(__sparc) || defined(__sparc__) || defined(sparc) || \
defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(_POWER) || \
defined(__POWERPC__) || defined(POWERPC) || defined(__powerpc) || \
defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || \
defined(__hpux) || defined(_MIPSEB) || defined(mc68000) || \
defined(__s390__) || defined(__s390x__) || defined(sel)
# define CPU_BIG_ENDIAN
# define IS_BIG_ENDIAN 1
# define IS_LITTLE_ENDIAN 0
#else
# error "Can't detect CPU architechture"
#endif
#define IS_ALIGNED_32(p) (0 == (3 & ((const char*)(p) - (const char*)0)))
#define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0)))
#if defined(_MSC_VER)
#define ALIGN_ATTR(n) __declspec(align(n))
#elif defined(__GNUC__)
#define ALIGN_ATTR(n) __attribute__((aligned (n)))
#else
#define ALIGN_ATTR(n) /* nothing */
#endif
#if defined(_MSC_VER) || defined(__BORLANDC__)
#define I64(x) x##ui64
#else
#define I64(x) x##LL
#endif
/* convert a hash flag to index */
#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) /* GCC < 3.4 */
# define rhash_ctz(x) __builtin_ctz(x)
#else
unsigned rhash_ctz(unsigned); /* define as function */
#endif
void rhash_swap_copy_str_to_u32(void* to, int index, const void* from, size_t length);
void rhash_swap_copy_str_to_u64(void* to, int index, const void* from, size_t length);
void rhash_swap_copy_u64_to_str(void* to, const void* from, size_t length);
void rhash_u32_mem_swap(unsigned *p, int length_in_u32);
/* define bswap_32 */
#if defined(__GNUC__) && defined(CPU_IA32) && !defined(__i386__)
/* for intel x86 CPU */
static inline uint32_t bswap_32(uint32_t x) {
__asm("bswap\t%0" : "=r" (x) : "0" (x));
return x;
}
#elif defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC__ > 4 || __GNUC_MINOR__ >= 3)
/* for GCC >= 4.3 */
# define bswap_32(x) __builtin_bswap32(x)
#elif (_MSC_VER > 1300) && (defined(CPU_IA32) || defined(CPU_X64)) /* MS VC */
# define bswap_32(x) _byteswap_ulong((unsigned long)x)
#elif !defined(__STRICT_ANSI__)
/* general bswap_32 definition */
static inline uint32_t bswap_32(uint32_t x) {
x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF);
return (x >> 16) | (x << 16);
}
#else
#define bswap_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
#endif /* bswap_32 */
#if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC__ > 4 || __GNUC_MINOR__ >= 3)
# define bswap_64(x) __builtin_bswap64(x)
#elif (_MSC_VER > 1300) && (defined(CPU_IA32) || defined(CPU_X64)) /* MS VC */
# define bswap_64(x) _byteswap_uint64((__int64)x)
#elif !defined(__STRICT_ANSI__)
static inline uint64_t bswap_64(uint64_t x) {
union {
uint64_t ll;
uint32_t l[2];
} w, r;
w.ll = x;
r.l[0] = bswap_32(w.l[1]);
r.l[1] = bswap_32(w.l[0]);
return r.ll;
}
#else
#error "bswap_64 unsupported"
#endif
#ifdef CPU_BIG_ENDIAN
# define be2me_32(x) (x)
# define be2me_64(x) (x)
# define le2me_32(x) bswap_32(x)
# define le2me_64(x) bswap_64(x)
# define be32_copy(to, index, from, length) memcpy((to) + (index), (from), (length))
# define le32_copy(to, index, from, length) rhash_swap_copy_str_to_u32((to), (index), (from), (length))
# define be64_copy(to, index, from, length) memcpy((to) + (index), (from), (length))
# define le64_copy(to, index, from, length) rhash_swap_copy_str_to_u64((to), (index), (from), (length))
# define me64_to_be_str(to, from, length) memcpy((to), (from), (length))
# define me64_to_le_str(to, from, length) rhash_swap_copy_u64_to_str((to), (from), (length))
#else /* CPU_BIG_ENDIAN */
# define be2me_32(x) bswap_32(x)
# define be2me_64(x) bswap_64(x)
# define le2me_32(x) (x)
# define le2me_64(x) (x)
# define be32_copy(to, index, from, length) rhash_swap_copy_str_to_u32((to), (index), (from), (length))
# define le32_copy(to, index, from, length) memcpy((to) + (index), (from), (length))
# define be64_copy(to, index, from, length) rhash_swap_copy_str_to_u64((to), (index), (from), (length))
# define le64_copy(to, index, from, length) memcpy((to) + (index), (from), (length))
# define me64_to_be_str(to, from, length) rhash_swap_copy_u64_to_str((to), (from), (length))
# define me64_to_le_str(to, from, length) memcpy((to), (from), (length))
#endif /* CPU_BIG_ENDIAN */
/* ROTL/ROTR macros rotate a 32/64-bit word left/right by n bits */
#define ROTL32(dword, n) ((dword) << (n) ^ ((dword) >> (32 - (n))))
#define ROTR32(dword, n) ((dword) >> (n) ^ ((dword) << (32 - (n))))
#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n))))
#define ROTR64(qword, n) ((qword) >> (n) ^ ((qword) << (64 - (n))))
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* BYTE_ORDER_H */

View File

@ -0,0 +1,188 @@
/* hex.c - conversion for hexadecimal and base32 strings.
*
* Copyright: 2008-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
#include <string.h>
#include <ctype.h>
#include "hex.h"
/**
* Convert a byte to a hexadecimal number. The result, consisting of two
* hexadecimal digits is stored into a buffer.
*
* @param dest the buffer to receive two symbols of hex representation
* @param byte the byte to decode
* @param upper_case flag to print string in uppercase
* @return pointer to the chararcter just after the written number (dest + 2)
*/
char* rhash_print_hex_byte(char *dest, const unsigned char byte, int upper_case)
{
const char add = (upper_case ? 'A' - 10 : 'a' - 10);
unsigned char c = (byte >> 4) & 15;
*dest++ = (c > 9 ? c + add : c + '0');
c = byte & 15;
*dest++ = (c > 9 ? c + add : c + '0');
return dest;
}
/**
* Store hexadecimal representation of a binary string to given buffer.
*
* @param dest the buffer to receive hexadecimal representation
* @param src binary string
* @param len string length
* @param upper_case flag to print string in uppercase
*/
void rhash_byte_to_hex(char *dest, const unsigned char *src, unsigned len, int upper_case)
{
while (len-- > 0) {
dest = rhash_print_hex_byte(dest, *src++, upper_case);
}
*dest = '\0';
}
/**
* Encode a binary string to base32.
*
* @param dest the buffer to store result
* @param src binary string
* @param len string length
* @param upper_case flag to print string in uppercase
*/
void rhash_byte_to_base32(char* dest, const unsigned char* src, unsigned len, int upper_case)
{
const char a = (upper_case ? 'A' : 'a');
unsigned shift = 0;
unsigned char word;
const unsigned char* e = src + len;
while (src < e) {
if (shift > 3) {
word = (*src & (0xFF >> shift));
shift = (shift + 5) % 8;
word <<= shift;
if (src + 1 < e)
word |= *(src + 1) >> (8 - shift);
++src;
} else {
shift = (shift + 5) % 8;
word = ( *src >> ( (8 - shift) & 7 ) ) & 0x1F;
if (shift == 0) src++;
}
*dest++ = ( word < 26 ? word + a : word + '2' - 26 );
}
*dest = '\0';
}
/**
* Encode a binary string to base64.
* Encoded output length is always a multiple of 4 bytes.
*
* @param dest the buffer to store result
* @param src binary string
* @param len string length
*/
void rhash_byte_to_base64(char* dest, const unsigned char* src, unsigned len)
{
static const char* tail = "0123456789+/";
unsigned shift = 0;
unsigned char word;
const unsigned char* e = src + len;
while (src < e) {
if (shift > 2) {
word = (*src & (0xFF >> shift));
shift = (shift + 6) % 8;
word <<= shift;
if (src + 1 < e)
word |= *(src + 1) >> (8 - shift);
++src;
} else {
shift = (shift + 6) % 8;
word = ( *src >> ( (8 - shift) & 7 ) ) & 0x3F;
if (shift == 0) src++;
}
*dest++ = ( word < 52 ? (word < 26 ? word + 'A' : word - 26 + 'a') : tail[word - 52]);
}
if (shift > 0) {
*dest++ = '=';
if (shift == 4) *dest++ = '=';
}
*dest = '\0';
}
/* unsafe characters are "<>{}[]%#/|\^~`@:;?=&+ */
#define IS_GOOD_URL_CHAR(c) (isalnum((unsigned char)c) || strchr("$-_.!'(),", c))
/**
* URL-encode a string.
*
* @param dst buffer to receive result or NULL to calculate
* the lengths of encoded string
* @param filename the file name
* @return the length of the result string
*/
int rhash_urlencode(char *dst, const char *name)
{
const char *start;
if (!dst) {
int len;
for (len = 0; *name; name++) len += (IS_GOOD_URL_CHAR(*name) ? 1 : 3);
return len;
}
/* encode URL as specified by RFC 1738 */
for (start = dst; *name; name++) {
if ( IS_GOOD_URL_CHAR(*name) ) {
*dst++ = *name;
} else {
*dst++ = '%';
dst = rhash_print_hex_byte(dst, *name, 'A');
}
}
*dst = 0;
return (int)(dst - start);
}
/**
* Print 64-bit number with trailing '\0' to a string buffer.
* if dst is NULL, then just return the length of the number.
*
* @param dst output buffer
* @param number the number to print
* @return length of the printed number (without trailing '\0')
*/
int rhash_sprintI64(char *dst, uint64_t number)
{
/* The biggest number has 20 digits: 2^64 = 18 446 744 073 709 551 616 */
char buf[24], *p;
size_t length;
if (dst == NULL) {
/* just calculate the length of the number */
if (number == 0) return 1;
for (length = 0; number != 0; number /= 10) length++;
return (int)length;
}
p = buf + 23;
*p = '\0'; /* last symbol should be '\0' */
if (number == 0) {
*(--p) = '0';
} else {
for (; p >= buf && number != 0; number /= 10) {
*(--p) = '0' + (char)(number % 10);
}
}
length = buf + 23 - p;
memcpy(dst, p, length + 1);
return (int)length;
}

View File

@ -0,0 +1,25 @@
/* hex.h - conversion for hexadecimal and base32 strings. */
#ifndef HEX_H
#define HEX_H
#include "ustd.h"
#ifdef __cplusplus
extern "C" {
#endif
void rhash_byte_to_hex(char *dest, const unsigned char *src, unsigned len, int upper_case);
void rhash_byte_to_base32(char* dest, const unsigned char* src, unsigned len, int upper_case);
void rhash_byte_to_base64(char* dest, const unsigned char* src, unsigned len);
char* rhash_print_hex_byte(char *dest, const unsigned char byte, int upper_case);
int rhash_urlencode(char *dst, const char *name);
int rhash_sprintI64(char *dst, uint64_t number);
#define BASE32_LENGTH(bytes) (((bytes) * 8 + 4) / 5)
#define BASE64_LENGTH(bytes) ((((bytes) + 2) / 3) * 4)
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* HEX_H */

View File

@ -0,0 +1,236 @@
/* md5.c - an implementation of the MD5 algorithm, based on RFC 1321.
*
* Copyright: 2007-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
#include <string.h>
#include "byte_order.h"
#include "md5.h"
/**
* Initialize context before calculaing hash.
*
* @param ctx context to initialize
*/
void rhash_md5_init(md5_ctx *ctx)
{
ctx->length = 0;
/* initialize state */
ctx->hash[0] = 0x67452301;
ctx->hash[1] = 0xefcdab89;
ctx->hash[2] = 0x98badcfe;
ctx->hash[3] = 0x10325476;
}
/* First, define four auxiliary functions that each take as input
* three 32-bit words and returns a 32-bit word.*/
/* F(x,y,z) = ((y XOR z) AND x) XOR z - is faster then original version */
#define MD5_F(x, y, z) ((((y) ^ (z)) & (x)) ^ (z))
#define MD5_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define MD5_H(x, y, z) ((x) ^ (y) ^ (z))
#define MD5_I(x, y, z) ((y) ^ ((x) | (~z)))
/* transformations for rounds 1, 2, 3, and 4. */
#define MD5_ROUND1(a, b, c, d, x, s, ac) { \
(a) += MD5_F((b), (c), (d)) + (x) + (ac); \
(a) = ROTL32((a), (s)); \
(a) += (b); \
}
#define MD5_ROUND2(a, b, c, d, x, s, ac) { \
(a) += MD5_G((b), (c), (d)) + (x) + (ac); \
(a) = ROTL32((a), (s)); \
(a) += (b); \
}
#define MD5_ROUND3(a, b, c, d, x, s, ac) { \
(a) += MD5_H((b), (c), (d)) + (x) + (ac); \
(a) = ROTL32((a), (s)); \
(a) += (b); \
}
#define MD5_ROUND4(a, b, c, d, x, s, ac) { \
(a) += MD5_I((b), (c), (d)) + (x) + (ac); \
(a) = ROTL32((a), (s)); \
(a) += (b); \
}
/**
* The core transformation. Process a 512-bit block.
* The function has been taken from RFC 1321 with little changes.
*
* @param state algorithm state
* @param x the message block to process
*/
static void rhash_md5_process_block(unsigned state[4], const unsigned* x)
{
register unsigned a, b, c, d;
a = state[0];
b = state[1];
c = state[2];
d = state[3];
MD5_ROUND1(a, b, c, d, x[ 0], 7, 0xd76aa478);
MD5_ROUND1(d, a, b, c, x[ 1], 12, 0xe8c7b756);
MD5_ROUND1(c, d, a, b, x[ 2], 17, 0x242070db);
MD5_ROUND1(b, c, d, a, x[ 3], 22, 0xc1bdceee);
MD5_ROUND1(a, b, c, d, x[ 4], 7, 0xf57c0faf);
MD5_ROUND1(d, a, b, c, x[ 5], 12, 0x4787c62a);
MD5_ROUND1(c, d, a, b, x[ 6], 17, 0xa8304613);
MD5_ROUND1(b, c, d, a, x[ 7], 22, 0xfd469501);
MD5_ROUND1(a, b, c, d, x[ 8], 7, 0x698098d8);
MD5_ROUND1(d, a, b, c, x[ 9], 12, 0x8b44f7af);
MD5_ROUND1(c, d, a, b, x[10], 17, 0xffff5bb1);
MD5_ROUND1(b, c, d, a, x[11], 22, 0x895cd7be);
MD5_ROUND1(a, b, c, d, x[12], 7, 0x6b901122);
MD5_ROUND1(d, a, b, c, x[13], 12, 0xfd987193);
MD5_ROUND1(c, d, a, b, x[14], 17, 0xa679438e);
MD5_ROUND1(b, c, d, a, x[15], 22, 0x49b40821);
MD5_ROUND2(a, b, c, d, x[ 1], 5, 0xf61e2562);
MD5_ROUND2(d, a, b, c, x[ 6], 9, 0xc040b340);
MD5_ROUND2(c, d, a, b, x[11], 14, 0x265e5a51);
MD5_ROUND2(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
MD5_ROUND2(a, b, c, d, x[ 5], 5, 0xd62f105d);
MD5_ROUND2(d, a, b, c, x[10], 9, 0x2441453);
MD5_ROUND2(c, d, a, b, x[15], 14, 0xd8a1e681);
MD5_ROUND2(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
MD5_ROUND2(a, b, c, d, x[ 9], 5, 0x21e1cde6);
MD5_ROUND2(d, a, b, c, x[14], 9, 0xc33707d6);
MD5_ROUND2(c, d, a, b, x[ 3], 14, 0xf4d50d87);
MD5_ROUND2(b, c, d, a, x[ 8], 20, 0x455a14ed);
MD5_ROUND2(a, b, c, d, x[13], 5, 0xa9e3e905);
MD5_ROUND2(d, a, b, c, x[ 2], 9, 0xfcefa3f8);
MD5_ROUND2(c, d, a, b, x[ 7], 14, 0x676f02d9);
MD5_ROUND2(b, c, d, a, x[12], 20, 0x8d2a4c8a);
MD5_ROUND3(a, b, c, d, x[ 5], 4, 0xfffa3942);
MD5_ROUND3(d, a, b, c, x[ 8], 11, 0x8771f681);
MD5_ROUND3(c, d, a, b, x[11], 16, 0x6d9d6122);
MD5_ROUND3(b, c, d, a, x[14], 23, 0xfde5380c);
MD5_ROUND3(a, b, c, d, x[ 1], 4, 0xa4beea44);
MD5_ROUND3(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
MD5_ROUND3(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
MD5_ROUND3(b, c, d, a, x[10], 23, 0xbebfbc70);
MD5_ROUND3(a, b, c, d, x[13], 4, 0x289b7ec6);
MD5_ROUND3(d, a, b, c, x[ 0], 11, 0xeaa127fa);
MD5_ROUND3(c, d, a, b, x[ 3], 16, 0xd4ef3085);
MD5_ROUND3(b, c, d, a, x[ 6], 23, 0x4881d05);
MD5_ROUND3(a, b, c, d, x[ 9], 4, 0xd9d4d039);
MD5_ROUND3(d, a, b, c, x[12], 11, 0xe6db99e5);
MD5_ROUND3(c, d, a, b, x[15], 16, 0x1fa27cf8);
MD5_ROUND3(b, c, d, a, x[ 2], 23, 0xc4ac5665);
MD5_ROUND4(a, b, c, d, x[ 0], 6, 0xf4292244);
MD5_ROUND4(d, a, b, c, x[ 7], 10, 0x432aff97);
MD5_ROUND4(c, d, a, b, x[14], 15, 0xab9423a7);
MD5_ROUND4(b, c, d, a, x[ 5], 21, 0xfc93a039);
MD5_ROUND4(a, b, c, d, x[12], 6, 0x655b59c3);
MD5_ROUND4(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
MD5_ROUND4(c, d, a, b, x[10], 15, 0xffeff47d);
MD5_ROUND4(b, c, d, a, x[ 1], 21, 0x85845dd1);
MD5_ROUND4(a, b, c, d, x[ 8], 6, 0x6fa87e4f);
MD5_ROUND4(d, a, b, c, x[15], 10, 0xfe2ce6e0);
MD5_ROUND4(c, d, a, b, x[ 6], 15, 0xa3014314);
MD5_ROUND4(b, c, d, a, x[13], 21, 0x4e0811a1);
MD5_ROUND4(a, b, c, d, x[ 4], 6, 0xf7537e82);
MD5_ROUND4(d, a, b, c, x[11], 10, 0xbd3af235);
MD5_ROUND4(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
MD5_ROUND4(b, c, d, a, x[ 9], 21, 0xeb86d391);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
/**
* Calculate message hash.
* Can be called repeatedly with chunks of the message to be hashed.
*
* @param ctx the algorithm context containing current hashing state
* @param msg message chunk
* @param size length of the message chunk
*/
void rhash_md5_update(md5_ctx *ctx, const unsigned char* msg, size_t size)
{
unsigned index = (unsigned)ctx->length & 63;
ctx->length += size;
/* fill partial block */
if (index) {
unsigned left = md5_block_size - index;
le32_copy((char*)ctx->message, index, msg, (size < left ? size : left));
if (size < left) return;
/* process partial block */
rhash_md5_process_block(ctx->hash, ctx->message);
msg += left;
size -= left;
}
while (size >= md5_block_size) {
unsigned* aligned_message_block;
if (IS_LITTLE_ENDIAN && IS_ALIGNED_32(msg)) {
/* the most common case is processing a 32-bit aligned message
on a little-endian CPU without copying it */
aligned_message_block = (unsigned*)msg;
} else {
le32_copy(ctx->message, 0, msg, md5_block_size);
aligned_message_block = ctx->message;
}
rhash_md5_process_block(ctx->hash, aligned_message_block);
msg += md5_block_size;
size -= md5_block_size;
}
if (size) {
/* save leftovers */
le32_copy(ctx->message, 0, msg, size);
}
}
/**
* Store calculated hash into the given array.
*
* @param ctx the algorithm context containing current hashing state
* @param result calculated hash in binary form
*/
void rhash_md5_final(md5_ctx *ctx, unsigned char* result)
{
unsigned index = ((unsigned)ctx->length & 63) >> 2;
unsigned shift = ((unsigned)ctx->length & 3) * 8;
/* pad message and run for last block */
/* append the byte 0x80 to the message */
ctx->message[index] &= ~(0xFFFFFFFF << shift);
ctx->message[index++] ^= 0x80 << shift;
/* if no room left in the message to store 64-bit message length */
if (index > 14) {
/* then fill the rest with zeros and process it */
while (index < 16) {
ctx->message[index++] = 0;
}
rhash_md5_process_block(ctx->hash, ctx->message);
index = 0;
}
while (index < 14) {
ctx->message[index++] = 0;
}
ctx->message[14] = (unsigned)(ctx->length << 3);
ctx->message[15] = (unsigned)(ctx->length >> 29);
rhash_md5_process_block(ctx->hash, ctx->message);
if (result) le32_copy(result, 0, &ctx->hash, 16);
}

View File

@ -0,0 +1,31 @@
/* md5.h */
#ifndef MD5_HIDER
#define MD5_HIDER
#include "ustd.h"
#ifdef __cplusplus
extern "C" {
#endif
#define md5_block_size 64
#define md5_hash_size 16
/* algorithm context */
typedef struct md5_ctx
{
unsigned message[md5_block_size / 4]; /* 512-bit buffer for leftovers */
uint64_t length; /* number of processed bytes */
unsigned hash[4]; /* 128-bit algorithm internal hashing state */
} md5_ctx;
/* hash functions */
void rhash_md5_init(md5_ctx *ctx);
void rhash_md5_update(md5_ctx *ctx, const unsigned char* msg, size_t size);
void rhash_md5_final(md5_ctx *ctx, unsigned char result[16]);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* MD5_HIDER */

View File

@ -0,0 +1,919 @@
/* rhash.c - implementation of LibRHash library calls
*
* Copyright: 2008-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
/* macros for large file support, must be defined before any include file */
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#include <string.h> /* memset() */
#include <stdlib.h> /* free() */
#include <stddef.h> /* ptrdiff_t */
#include <stdio.h>
#include <assert.h>
#include <errno.h>
/* modifier for Windows DLL */
#if defined(_WIN32) && defined(RHASH_EXPORTS)
# define RHASH_API __declspec(dllexport)
#endif
#include "byte_order.h"
#include "algorithms.h"
#include "torrent.h"
#include "plug_openssl.h"
#include "util.h"
#include "hex.h"
#include "rhash.h" /* RHash library interface */
#define STATE_ACTIVE 0xb01dbabe
#define STATE_STOPED 0xdeadbeef
#define STATE_DELETED 0xdecea5ed
#define RCTX_AUTO_FINAL 0x1
#define RCTX_FINALIZED 0x2
#define RCTX_FINALIZED_MASK (RCTX_AUTO_FINAL | RCTX_FINALIZED)
#define RHPR_FORMAT (RHPR_RAW | RHPR_HEX | RHPR_BASE32 | RHPR_BASE64)
#define RHPR_MODIFIER (RHPR_UPPERCASE | RHPR_REVERSE)
/**
* Initialize static data of rhash algorithms
*/
void rhash_library_init(void)
{
rhash_init_algorithms(RHASH_ALL_HASHES);
#ifdef USE_OPENSSL
rhash_plug_openssl();
#endif
}
/**
* Returns the number of supported hash algorithms.
*
* @return the number of supported hash functions
*/
int RHASH_API rhash_count(void)
{
return rhash_info_size;
}
/* Lo-level rhash library functions */
/**
* Allocate and initialize RHash context for calculating hash(es).
* After initializing rhash_update()/rhash_final() functions should be used.
* Then the context must be freed by calling rhash_free().
*
* @param hash_id union of bit flags, containing ids of hashes to calculate.
* @return initialized rhash context, NULL on error and errno is set
*/
RHASH_API rhash rhash_init(unsigned hash_id)
{
unsigned tail_bit_index; /* index of hash_id trailing bit */
unsigned num = 0; /* number of hashes to compute */
rhash_context_ext *rctx = NULL; /* allocated rhash context */
size_t hash_size_sum = 0; /* size of hash contexts to store in rctx */
unsigned i, bit_index, id;
struct rhash_hash_info* info;
size_t aligned_size;
char* phash_ctx;
hash_id &= RHASH_ALL_HASHES;
if (hash_id == 0) {
errno = EINVAL;
return NULL;
}
tail_bit_index = rhash_ctz(hash_id); /* get trailing bit index */
assert(tail_bit_index < RHASH_HASH_COUNT);
id = 1 << tail_bit_index;
if (hash_id == id) {
/* handle the most common case of only one hash */
num = 1;
info = &rhash_info_table[tail_bit_index];
hash_size_sum = info->context_size;
} else {
/* another case: hash_id contains several hashes */
for (bit_index = tail_bit_index; id <= hash_id; bit_index++, id = id << 1) {
assert(id != 0);
assert(bit_index < RHASH_HASH_COUNT);
info = &rhash_info_table[bit_index];
if (hash_id & id) {
/* align sizes by 8 bytes */
aligned_size = (info->context_size + 7) & ~7;
hash_size_sum += aligned_size;
num++;
}
}
assert(num > 1);
}
/* align the size of the rhash context common part */
aligned_size = (offsetof(rhash_context_ext, vector[num]) + 7) & ~7;
assert(aligned_size >= sizeof(rhash_context_ext));
/* allocate rhash context with enough memory to store contexts of all used hashes */
rctx = (rhash_context_ext*)malloc(aligned_size + hash_size_sum);
if (rctx == NULL) return NULL;
/* initialize common fields of the rhash context */
memset(rctx, 0, sizeof(rhash_context_ext));
rctx->rc.hash_id = hash_id;
rctx->flags = RCTX_AUTO_FINAL; /* turn on auto-final by default */
rctx->state = STATE_ACTIVE;
rctx->hash_vector_size = num;
/* aligned hash contexts follows rctx->vector[num] in the same memory block */
phash_ctx = (char*)rctx + aligned_size;
assert(phash_ctx >= (char*)&rctx->vector[num]);
/* initialize context for every hash in a loop */
for (bit_index = tail_bit_index, id = 1 << tail_bit_index, i = 0;
id <= hash_id; bit_index++, id = id << 1)
{
/* check if a hash function with given id shall be included into rctx */
if ((hash_id & id) != 0) {
info = &rhash_info_table[bit_index];
assert(info->context_size > 0);
assert(((phash_ctx - (char*)0) & 7) == 0); /* hash context is aligned */
assert(info->init != NULL);
rctx->vector[i].hash_info = info;
rctx->vector[i].context = phash_ctx;
/* BTIH initialization is complex, save pointer for later */
if ((id & RHASH_BTIH) != 0) rctx->bt_ctx = phash_ctx;
phash_ctx += (info->context_size + 7) & ~7;
/* initialize the i-th hash context */
info->init(rctx->vector[i].context);
i++;
}
}
return &rctx->rc; /* return allocated and initialized rhash context */
}
/**
* Free RHash context memory.
*
* @param ctx the context to free.
*/
void rhash_free(rhash ctx)
{
rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
unsigned i;
if (ctx == 0) return;
assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
ectx->state = STATE_DELETED; /* mark memory block as being removed */
/* clean the hash functions, which require additional clean up */
for (i = 0; i < ectx->hash_vector_size; i++) {
struct rhash_hash_info* info = ectx->vector[i].hash_info;
if (info->cleanup != 0) {
info->cleanup(ectx->vector[i].context);
}
}
free(ectx);
}
/**
* Re-initialize RHash context to reuse it.
* Useful to speed up processing of many small messages.
*
* @param ctx context to reinitialize
*/
RHASH_API void rhash_reset(rhash ctx)
{
rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
unsigned i;
assert(ectx->hash_vector_size > 0);
assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
ectx->state = STATE_ACTIVE; /* re-activate the structure */
/* re-initialize every hash in a loop */
for (i = 0; i < ectx->hash_vector_size; i++) {
struct rhash_hash_info* info = ectx->vector[i].hash_info;
if (info->cleanup != 0) {
info->cleanup(ectx->vector[i].context);
}
assert(info->init != NULL);
info->init(ectx->vector[i].context);
}
ectx->flags &= ~RCTX_FINALIZED; /* clear finalized state */
}
/**
* Calculate hashes of message.
* Can be called repeatedly with chunks of the message to be hashed.
*
* @param ctx the rhash context
* @param message message chunk
* @param length length of the message chunk
* @return 0 on success; On fail return -1 and set errno
*/
RHASH_API int rhash_update(rhash ctx, const void* message, size_t length)
{
rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
unsigned i;
assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
if (ectx->state != STATE_ACTIVE) return 0; /* do nothing if canceled */
ctx->msg_size += length;
/* call update method for every algorithm */
for (i = 0; i < ectx->hash_vector_size; i++) {
struct rhash_hash_info* info = ectx->vector[i].hash_info;
assert(info->update != 0);
info->update(ectx->vector[i].context, message, length);
}
return 0; /* no error processing at the moment */
}
/**
* Finalize hash calculation and optionally store the first hash.
*
* @param ctx the rhash context
* @param first_result optional buffer to store a calculated hash with the lowest available id
* @return 0 on success; On fail return -1 and set errno
*/
RHASH_API int rhash_final(rhash ctx, unsigned char* first_result)
{
unsigned i = 0;
unsigned char buffer[130];
unsigned char* out = (first_result ? first_result : buffer);
rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
/* skip final call if already finalized and auto-final is on */
if ((ectx->flags & RCTX_FINALIZED_MASK) ==
(RCTX_AUTO_FINAL | RCTX_FINALIZED)) return 0;
/* call final method for every algorithm */
for (i = 0; i < ectx->hash_vector_size; i++) {
struct rhash_hash_info* info = ectx->vector[i].hash_info;
assert(info->final != 0);
assert(info->info->digest_size < sizeof(buffer));
info->final(ectx->vector[i].context, out);
out = buffer;
}
ectx->flags |= RCTX_FINALIZED;
return 0; /* no error processing at the moment */
}
/**
* Store digest for given hash_id.
* If hash_id is zero, function stores digest for a hash with the lowest id found in the context.
* For nonzero hash_id the context must contain it, otherwise function silently does nothing.
*
* @param ctx rhash context
* @param hash_id id of hash to retrieve or zero for hash with the lowest available id
* @param result buffer to put the hash into
*/
static void rhash_put_digest(rhash ctx, unsigned hash_id, unsigned char* result)
{
rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
unsigned i;
rhash_vector_item *item;
struct rhash_hash_info* info;
unsigned char* digest;
assert(ectx);
assert(ectx->hash_vector_size > 0 && ectx->hash_vector_size <= RHASH_HASH_COUNT);
/* finalize context if not yet finalized and auto-final is on */
if ((ectx->flags & RCTX_FINALIZED_MASK) == RCTX_AUTO_FINAL) {
rhash_final(ctx, NULL);
}
if (hash_id == 0) {
item = &ectx->vector[0]; /* get the first hash */
info = item->hash_info;
} else {
for (i = 0;; i++) {
if (i >= ectx->hash_vector_size) {
return; /* hash_id not found, do nothing */
}
item = &ectx->vector[i];
info = item->hash_info;
if (info->info->hash_id == hash_id) break;
}
}
digest = ((unsigned char*)item->context + info->digest_diff);
if (info->info->flags & F_SWAP32) {
assert((info->info->digest_size & 3) == 0);
/* NB: the next call is correct only for multiple of 4 byte size */
rhash_swap_copy_str_to_u32(result, 0, digest, info->info->digest_size);
} else if (info->info->flags & F_SWAP64) {
rhash_swap_copy_u64_to_str(result, digest, info->info->digest_size);
} else {
memcpy(result, digest, info->info->digest_size);
}
}
/**
* Set the callback function to be called from the
* rhash_file() and rhash_file_update() functions
* on processing every file block. The file block
* size is set internally by rhash and now is 8 KiB.
*
* @param ctx rhash context
* @param callback pointer to the callback function
* @param callback_data pointer to data passed to the callback
*/
RHASH_API void rhash_set_callback(rhash ctx, rhash_callback_t callback, void* callback_data)
{
((rhash_context_ext*)ctx)->callback = callback;
((rhash_context_ext*)ctx)->callback_data = callback_data;
}
/* hi-level message hashing interface */
/**
* Compute a hash of the given message.
*
* @param hash_id id of hash sum to compute
* @param message the message to process
* @param length message length
* @param result buffer to receive binary hash string
* @return 0 on success, -1 on error
*/
RHASH_API int rhash_msg(unsigned hash_id, const void* message, size_t length, unsigned char* result)
{
rhash ctx;
hash_id &= RHASH_ALL_HASHES;
ctx = rhash_init(hash_id);
if (ctx == NULL) return -1;
rhash_update(ctx, message, length);
rhash_final(ctx, result);
rhash_free(ctx);
return 0;
}
/**
* Hash a file or stream. Multiple hashes can be computed.
* First, inintialize ctx parameter with rhash_init() before calling
* rhash_file_update(). Then use rhash_final() and rhash_print()
* to retrive hash values. Finaly call rhash_free() on ctx
* to free allocated memory or call rhash_reset() to reuse ctx.
*
* @param ctx rhash context
* @param fd descriptor of the file to hash
* @return 0 on success, -1 on error and errno is set
*/
RHASH_API int rhash_file_update(rhash ctx, FILE* fd)
{
rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
const size_t block_size = 8192;
unsigned char *buffer, *pmem;
size_t length = 0, align8;
int res = 0;
if (ectx->state != STATE_ACTIVE) return 0; /* do nothing if canceled */
if (ctx == NULL) {
errno = EINVAL;
return -1;
}
pmem = (unsigned char*)malloc(block_size + 8);
if (!pmem) return -1; /* errno is set to ENOMEM according to UNIX 98 */
align8 = ((unsigned char*)0 - pmem) & 7;
buffer = pmem + align8;
while (!feof(fd)) {
/* stop if canceled */
if (ectx->state != STATE_ACTIVE) break;
length = fread(buffer, 1, block_size, fd);
if (ferror(fd)) {
res = -1; /* note: errno contains error code */
break;
} else if (length) {
rhash_update(ctx, buffer, length);
if (ectx->callback) {
((rhash_callback_t)ectx->callback)(ectx->callback_data, ectx->rc.msg_size);
}
}
}
free(buffer);
return res;
}
/**
* Compute a single hash for given file.
*
* @param hash_id id of hash sum to compute
* @param filepath path to the file to hash
* @param result buffer to receive hash value with the lowest requested id
* @return 0 on success, -1 on error and errno is set
*/
RHASH_API int rhash_file(unsigned hash_id, const char* filepath, unsigned char* result)
{
FILE* fd;
rhash ctx;
int res;
hash_id &= RHASH_ALL_HASHES;
if (hash_id == 0) {
errno = EINVAL;
return -1;
}
if ((fd = fopen(filepath, "rb")) == NULL) return -1;
if ((ctx = rhash_init(hash_id)) == NULL) return -1;
res = rhash_file_update(ctx, fd); /* hash the file */
fclose(fd);
rhash_final(ctx, result);
rhash_free(ctx);
return res;
}
#ifdef _WIN32 /* windows only function */
#include <share.h>
/**
* Compute a single hash for given file.
*
* @param hash_id id of hash sum to compute
* @param filepath path to the file to hash
* @param result buffer to receive hash value with the lowest requested id
* @return 0 on success, -1 on error, -1 on error and errno is set
*/
RHASH_API int rhash_wfile(unsigned hash_id, const wchar_t* filepath, unsigned char* result)
{
FILE* fd;
rhash ctx;
int res;
hash_id &= RHASH_ALL_HASHES;
if (hash_id == 0) {
errno = EINVAL;
return -1;
}
if ((fd = _wfsopen(filepath, L"rb", _SH_DENYWR)) == NULL) return -1;
if ((ctx = rhash_init(hash_id)) == NULL) return -1;
res = rhash_file_update(ctx, fd); /* hash the file */
fclose(fd);
rhash_final(ctx, result);
rhash_free(ctx);
return res;
}
#endif
/* RHash information functions */
/**
* Returns information about a hash function by its hash_id.
*
* @param hash_id the id of hash algorithm
* @return pointer to the rhash_info structure containing the information
*/
const rhash_info* rhash_info_by_id(unsigned hash_id)
{
hash_id &= RHASH_ALL_HASHES;
/* check that only one bit is set */
if (hash_id != (hash_id & -(int)hash_id)) return NULL;
/* note: alternative condition is (hash_id == 0 || (hash_id & (hash_id - 1)) != 0) */
return rhash_info_table[rhash_ctz(hash_id)].info;
}
/**
* Detect default digest output format for given hash algorithm.
*
* @param hash_id the id of hash algorithm
* @return 1 for base32 format, 0 for hexadecimal
*/
RHASH_API int rhash_is_base32(unsigned hash_id)
{
/* fast method is just to test a bit-mask */
return ((hash_id & (RHASH_TTH | RHASH_AICH)) != 0);
}
/**
* Returns size of binary digest for given hash algorithm.
*
* @param hash_id the id of hash algorithm
* @return digest size in bytes
*/
RHASH_API int rhash_get_digest_size(unsigned hash_id)
{
hash_id &= RHASH_ALL_HASHES;
if (hash_id == 0 || (hash_id & (hash_id - 1)) != 0) return -1;
return (int)rhash_info_table[rhash_ctz(hash_id)].info->digest_size;
}
/**
* Returns length of digest hash string in default output format.
*
* @param hash_id the id of hash algorithm
* @return the length of hash string
*/
RHASH_API int rhash_get_hash_length(unsigned hash_id)
{
const rhash_info* info = rhash_info_by_id(hash_id);
return (int)(info ? (info->flags & F_BS32 ?
BASE32_LENGTH(info->digest_size) : info->digest_size * 2) : 0);
}
/**
* Returns a name of given hash algorithm.
*
* @param hash_id the id of hash algorithm
* @return algorithm name
*/
RHASH_API const char* rhash_get_name(unsigned hash_id)
{
const rhash_info* info = rhash_info_by_id(hash_id);
return (info ? info->name : 0);
}
/**
* Returns a name part of magnet urn of the given hash algorithm.
* Such magnet_name is used to generate a magnet link of the form
* urn:&lt;magnet_name&gt;=&lt;hash_value&gt;.
*
* @param hash_id the id of hash algorithm
* @return name
*/
RHASH_API const char* rhash_get_magnet_name(unsigned hash_id)
{
const rhash_info* info = rhash_info_by_id(hash_id);
return (info ? info->magnet_name : 0);
}
static size_t rhash_get_magnet_url_size(const char* filepath,
rhash context, unsigned hash_mask, int flags)
{
size_t size = 0; /* count terminating '\0' */
unsigned bit, hash = context->hash_id & hash_mask;
/* RHPR_NO_MAGNET, RHPR_FILESIZE */
if ((flags & RHPR_NO_MAGNET) == 0) {
size += 8;
}
if ((flags & RHPR_FILESIZE) != 0) {
uint64_t num = context->msg_size;
size += 4;
if (num == 0) size++;
else {
for (; num; num /= 10, size++);
}
}
if (filepath) {
size += 4 + rhash_urlencode(NULL, filepath);
}
/* loop through hash values */
for (bit = hash & -(int)hash; bit <= hash; bit <<= 1) {
const char* name;
if ((bit & hash) == 0) continue;
if ((name = rhash_get_magnet_name(bit)) == 0) continue;
size += (7 + 2) + strlen(name);
size += rhash_print(NULL, context, bit,
(bit & (RHASH_SHA1 | RHASH_BTIH) ? RHPR_BASE32 : 0));
}
return size;
}
/**
* Print magnet link with given filepath and calculated hash sums into the
* output buffer. The hash_mask can limit which hash values will be printed.
* The function returns the size of the required buffer.
* If output is NULL the .
*
* @param output a string buffer to receive the magnet link or NULL
* @param filepath the file path to be printed or NULL
* @param context algorithms state
* @param hash_mask bit mask of the hash sums to add to the link
* @param flags can be combination of bits RHPR_UPPERCASE, RHPR_NO_MAGNET,
* RHPR_FILESIZE
* @return number of written characters, including terminating '\0' on success, 0 on fail
*/
RHASH_API size_t rhash_print_magnet(char* output, const char* filepath,
rhash context, unsigned hash_mask, int flags)
{
int i;
const char* begin = output;
if (output == NULL) return rhash_get_magnet_url_size(
filepath, context, hash_mask, flags);
/* RHPR_NO_MAGNET, RHPR_FILESIZE */
if ((flags & RHPR_NO_MAGNET) == 0) {
strcpy(output, "magnet:?");
output += 8;
}
if ((flags & RHPR_FILESIZE) != 0) {
strcpy(output, "xl=");
output += 3;
output += rhash_sprintI64(output, context->msg_size);
*(output++) = '&';
}
if (filepath) {
strcpy(output, "dn=");
output += 3;
output += rhash_urlencode(output, filepath);
*(output++) = '&';
}
flags &= RHPR_UPPERCASE;
for (i = 0; i < 2; i++) {
unsigned bit;
unsigned hash = context->hash_id & hash_mask;
hash = (i == 0 ? hash & (RHASH_ED2K | RHASH_AICH)
: hash & ~(RHASH_ED2K | RHASH_AICH));
if (!hash) continue;
/* loop through hash values */
for (bit = hash & -(int)hash; bit <= hash; bit <<= 1) {
const char* name;
if ((bit & hash) == 0) continue;
if (!(name = rhash_get_magnet_name(bit))) continue;
strcpy(output, "xt=urn:");
output += 7;
strcpy(output, name);
output += strlen(name);
*(output++) = ':';
output += rhash_print(output, context, bit,
(bit & (RHASH_SHA1 | RHASH_BTIH) ? flags | RHPR_BASE32 : flags));
*(output++) = '&';
}
}
output[-1] = '\0'; /* terminate the line */
return (output - begin);
}
/* hash sum output */
/**
* Print a text presentation of a given hash sum to the specified buffer,
*
* @param output a buffer to print the hash to
* @param bytes a hash sum to print
* @param size a size of hash sum in bytes
* @param flags a bit-mask controlling how to format the hash sum,
* can be a mix of the flags: RHPR_RAW, RHPR_HEX, RHPR_BASE32,
* RHPR_BASE64, RHPR_UPPERCASE, RHPR_REVERSE
* @return the number of written characters
*/
size_t rhash_print_bytes(char* output, const unsigned char* bytes,
size_t size, int flags)
{
size_t str_len;
int upper_case = (flags & RHPR_UPPERCASE);
int format = (flags & ~RHPR_MODIFIER);
switch (format) {
case RHPR_HEX:
str_len = size * 2;
rhash_byte_to_hex(output, bytes, (unsigned)size, upper_case);
break;
case RHPR_BASE32:
str_len = BASE32_LENGTH(size);
rhash_byte_to_base32(output, bytes, (unsigned)size, upper_case);
break;
case RHPR_BASE64:
str_len = BASE64_LENGTH(size);
rhash_byte_to_base64(output, bytes, (unsigned)size);
break;
default:
str_len = size;
memcpy(output, bytes, size);
break;
}
return str_len;
}
/**
* Print text presentation of a hash sum with given hash_id to the specified
* output buffer. If the hash_id is zero, then print the hash sum with
* the lowest id stored in the hash context.
* The function call fails if the context doesn't include a hash with the
* given hash_id.
*
* @param output a buffer to print the hash to
* @param context algorithms state
* @param hash_id id of the hash sum to print or 0 to print the first hash
* saved in the context.
* @param flags a bitmask controlling how to print the hash. Can contain flags
* RHPR_UPPERCASE, RHPR_HEX, RHPR_BASE32, RHPR_BASE64, etc.
* @return the number of written characters on success or 0 on fail
*/
size_t RHASH_API rhash_print(char* output, rhash context, unsigned hash_id, int flags)
{
const rhash_info* info;
unsigned char digest[80];
size_t digest_size;
info = (hash_id != 0 ? rhash_info_by_id(hash_id) :
((rhash_context_ext*)context)->vector[0].hash_info->info);
if (info == NULL) return 0;
digest_size = info->digest_size;
assert(digest_size <= 64);
flags &= (RHPR_FORMAT | RHPR_MODIFIER);
if ((flags & RHPR_FORMAT) == 0) {
/* use default format if not specified by flags */
flags |= (info->flags & RHASH_INFO_BASE32 ? RHPR_BASE32 : RHPR_HEX);
}
if (output == NULL) {
switch (flags & RHPR_FORMAT) {
case RHPR_HEX:
return (digest_size * 2);
case RHPR_BASE32:
return BASE32_LENGTH(digest_size);
case RHPR_BASE64:
return BASE64_LENGTH(digest_size);
default:
return digest_size;
}
}
/* note: use info->hash_id, cause hash_id can be 0 */
rhash_put_digest(context, info->hash_id, digest);
if ((flags & ~RHPR_UPPERCASE) == (RHPR_REVERSE | RHPR_HEX)) {
/* reverse the digest */
unsigned char *p = digest, *r = digest + digest_size - 1;
char tmp;
for (; p < r; p++, r--) {
tmp = *p;
*p = *r;
*r = tmp;
}
}
return rhash_print_bytes(output, digest, digest_size, flags);
}
#if defined(_WIN32) && defined(RHASH_EXPORTS)
#include <windows.h>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved);
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved)
{
(void)hModule;
(void)reserved;
switch (reason) {
case DLL_PROCESS_ATTACH:
rhash_library_init();
break;
case DLL_PROCESS_DETACH:
/*rhash_library_free();*/
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
#endif
/**
* Process a BitTorrent-related rhash message.
*
* @param msg_id message identifier
* @param bt BitTorrent context
* @param ldata data depending on message
* @param rdata data depending on message
* @return message-specific data
*/
static rhash_uptr_t process_bt_msg(unsigned msg_id, torrent_ctx* bt, rhash_uptr_t ldata, rhash_uptr_t rdata)
{
if (bt == NULL) return RHASH_ERROR;
switch (msg_id) {
case RMSG_BT_ADD_FILE:
bt_add_file(bt, (const char*)ldata, *(unsigned long long*)rdata);
break;
case RMSG_BT_SET_OPTIONS:
bt_set_options(bt, (unsigned)ldata);
break;
case RMSG_BT_SET_ANNOUNCE:
bt_add_announce(bt, (const char*)ldata);
break;
case RMSG_BT_SET_PIECE_LENGTH:
bt_set_piece_length(bt, (size_t)ldata);
break;
case RMSG_BT_SET_BATCH_SIZE:
bt_set_piece_length(bt,
bt_default_piece_length(*(unsigned long long*)ldata));
break;
case RMSG_BT_SET_PROGRAM_NAME:
bt_set_program_name(bt, (const char*)ldata);
break;
case RMSG_BT_GET_TEXT:
return (rhash_uptr_t)bt_get_text(bt, (char**)ldata);
default:
return RHASH_ERROR; /* unknown message */
}
return 0;
}
#define PVOID2UPTR(p) ((rhash_uptr_t)((char*)p - 0))
/**
* Process a rhash message.
*
* @param msg_id message identifier
* @param dst message destination (can be NULL for generic messages)
* @param ldata data depending on message
* @param rdata data depending on message
* @return message-specific data
*/
RHASH_API rhash_uptr_t rhash_transmit(unsigned msg_id, void* dst, rhash_uptr_t ldata, rhash_uptr_t rdata)
{
/* for messages working with rhash context */
rhash_context_ext* const ctx = (rhash_context_ext*)dst;
switch (msg_id) {
case RMSG_GET_CONTEXT:
{
unsigned i;
for (i = 0; i < ctx->hash_vector_size; i++) {
struct rhash_hash_info* info = ctx->vector[i].hash_info;
if (info->info->hash_id == (unsigned)ldata)
return PVOID2UPTR(ctx->vector[i].context);
}
return (rhash_uptr_t)0;
}
case RMSG_CANCEL:
/* mark rhash context as canceled, in a multithreaded program */
atomic_compare_and_swap(&ctx->state, STATE_ACTIVE, STATE_STOPED);
return 0;
case RMSG_IS_CANCELED:
return (ctx->state == STATE_STOPED);
case RMSG_GET_FINALIZED:
return ((ctx->flags & RCTX_FINALIZED) != 0);
case RMSG_SET_AUTOFINAL:
ctx->flags &= ~RCTX_AUTO_FINAL;
if (ldata) ctx->flags |= RCTX_AUTO_FINAL;
break;
/* OpenSSL related messages */
#ifdef USE_OPENSSL
case RMSG_SET_OPENSSL_MASK:
rhash_openssl_hash_mask = (unsigned)ldata;
break;
case RMSG_GET_OPENSSL_MASK:
return rhash_openssl_hash_mask;
#endif
/* BitTorrent related messages */
case RMSG_BT_ADD_FILE:
case RMSG_BT_SET_OPTIONS:
case RMSG_BT_SET_ANNOUNCE:
case RMSG_BT_SET_PIECE_LENGTH:
case RMSG_BT_SET_PROGRAM_NAME:
case RMSG_BT_GET_TEXT:
case RMSG_BT_SET_BATCH_SIZE:
return process_bt_msg(msg_id, (torrent_ctx*)(((rhash_context_ext*)dst)->bt_ctx), ldata, rdata);
default:
return RHASH_ERROR; /* unknown message */
}
return 0;
}

View File

@ -0,0 +1,273 @@
/** @file rhash.h LibRHash interface */
#ifndef RHASH_H
#define RHASH_H
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef RHASH_API
/* modifier for LibRHash functions */
# define RHASH_API
#endif
/**
* Identifiers of supported hash functions.
* The rhash_init() function allows mixing several ids using
* binary OR, to calculate several hash functions for one message.
*/
enum rhash_ids
{
RHASH_CRC32 = 0x01,
RHASH_MD4 = 0x02,
RHASH_MD5 = 0x04,
RHASH_SHA1 = 0x08,
RHASH_TIGER = 0x10,
RHASH_TTH = 0x20,
RHASH_BTIH = 0x40,
RHASH_ED2K = 0x80,
RHASH_AICH = 0x100,
RHASH_WHIRLPOOL = 0x200,
RHASH_RIPEMD160 = 0x400,
RHASH_GOST = 0x800,
RHASH_GOST_CRYPTOPRO = 0x1000,
RHASH_HAS160 = 0x2000,
RHASH_SNEFRU128 = 0x4000,
RHASH_SNEFRU256 = 0x8000,
RHASH_SHA224 = 0x10000,
RHASH_SHA256 = 0x20000,
RHASH_SHA384 = 0x40000,
RHASH_SHA512 = 0x80000,
RHASH_EDONR256 = 0x0100000,
RHASH_EDONR512 = 0x0200000,
RHASH_SHA3_224 = 0x0400000,
RHASH_SHA3_256 = 0x0800000,
RHASH_SHA3_384 = 0x1000000,
RHASH_SHA3_512 = 0x2000000,
/** The bit-mask containing all supported hashe functions */
RHASH_ALL_HASHES = RHASH_CRC32 | RHASH_MD4 | RHASH_MD5 | RHASH_ED2K | RHASH_SHA1 |
RHASH_TIGER | RHASH_TTH | RHASH_GOST | RHASH_GOST_CRYPTOPRO |
RHASH_BTIH | RHASH_AICH | RHASH_WHIRLPOOL | RHASH_RIPEMD160 |
RHASH_HAS160 | RHASH_SNEFRU128 | RHASH_SNEFRU256 |
RHASH_SHA224 | RHASH_SHA256 | RHASH_SHA384 | RHASH_SHA512 |
RHASH_SHA3_224 | RHASH_SHA3_256 | RHASH_SHA3_384 | RHASH_SHA3_512 |
RHASH_EDONR256 | RHASH_EDONR512,
/** The number of supported hash functions */
RHASH_HASH_COUNT = 26
};
/**
* The rhash context structure contains contexts for several hash functions
*/
typedef struct rhash_context
{
/** The size of the hashed message */
unsigned long long msg_size;
/**
* The bit-mask containing identifiers of the hashes being calculated
*/
unsigned hash_id;
} rhash_context;
#ifndef LIBRHASH_RHASH_CTX_DEFINED
#define LIBRHASH_RHASH_CTX_DEFINED
/**
* Hashing context.
*/
typedef struct rhash_context* rhash;
#endif /* LIBRHASH_RHASH_CTX_DEFINED */
/** type of a callback to be called periodically while hashing a file */
typedef void (*rhash_callback_t)(void* data, unsigned long long offset);
RHASH_API void rhash_library_init(void); /* initialize static data */
/* hi-level hashing functions */
RHASH_API int rhash_msg(unsigned hash_id, const void* message, size_t length, unsigned char* result);
RHASH_API int rhash_file(unsigned hash_id, const char* filepath, unsigned char* result);
RHASH_API int rhash_file_update(rhash ctx, FILE* fd);
#ifdef _WIN32 /* windows only function */
RHASH_API int rhash_wfile(unsigned hash_id, const wchar_t* filepath, unsigned char* result);
#endif
/* lo-level interface */
RHASH_API rhash rhash_init(unsigned hash_id);
/*RHASH_API rhash rhash_init_by_ids(unsigned hash_ids[], unsigned count);*/
RHASH_API int rhash_update(rhash ctx, const void* message, size_t length);
RHASH_API int rhash_final(rhash ctx, unsigned char* first_result);
RHASH_API void rhash_reset(rhash ctx); /* reinitialize the context */
RHASH_API void rhash_free(rhash ctx);
/* additional lo-level functions */
RHASH_API void rhash_set_callback(rhash ctx, rhash_callback_t callback, void* callback_data);
/** bit-flag: default hash output format is base32 */
#define RHASH_INFO_BASE32 1
/**
* Information about a hash function.
*/
typedef struct rhash_info
{
/** hash function indentifier */
unsigned hash_id;
/** flags bit-mask, including RHASH_INFO_BASE32 bit */
unsigned flags;
/** size of binary message digest in bytes */
size_t digest_size;
const char* name;
const char* magnet_name;
} rhash_info;
/* information functions */
RHASH_API int rhash_count(void); /* number of supported hashes */
RHASH_API int rhash_get_digest_size(unsigned hash_id); /* size of binary message digest */
RHASH_API int rhash_get_hash_length(unsigned hash_id); /* length of formated hash string */
RHASH_API int rhash_is_base32(unsigned hash_id); /* default digest output format */
RHASH_API const char* rhash_get_name(unsigned hash_id); /* get hash function name */
RHASH_API const char* rhash_get_magnet_name(unsigned hash_id); /* get name part of magnet urn */
/* note, that rhash_info_by_id() is not exported to a shared library or DLL */
const rhash_info* rhash_info_by_id(unsigned hash_id); /* get hash sum info by hash id */
/**
* Flags for printing a hash sum
*/
enum rhash_print_sum_flags
{
/** print in a default format */
RHPR_DEFAULT = 0x0,
/** output as binary message digest */
RHPR_RAW = 0x1,
/** print as a hexadecimal string */
RHPR_HEX = 0x2,
/** print as a base32-encoded string */
RHPR_BASE32 = 0x3,
/** print as a base64-encoded string */
RHPR_BASE64 = 0x4,
/**
* Print as an uppercase string. Can be used
* for base32 or hexadecimal format only.
*/
RHPR_UPPERCASE = 0x8,
/**
* Reverse hash bytes. Can be used for GOST hash.
*/
RHPR_REVERSE = 0x10,
/** don't print 'magnet:?' prefix in rhash_print_magnet */
RHPR_NO_MAGNET = 0x20,
/** print file size in rhash_print_magnet */
RHPR_FILESIZE = 0x40,
};
/* output hash into the given buffer */
RHASH_API size_t rhash_print_bytes(char* output,
const unsigned char* bytes, size_t size, int flags);
RHASH_API size_t rhash_print(char* output, rhash ctx, unsigned hash_id,
int flags);
/* output magnet URL into the given buffer */
RHASH_API size_t rhash_print_magnet(char* output, const char* filepath,
rhash context, unsigned hash_mask, int flags);
/* macros for message API */
/** The type of an unsigned integer large enough to hold a pointer */
#if defined(UINTPTR_MAX)
typedef uintptr_t rhash_uptr_t;
#elif defined(_LP64) || defined(__LP64__) || defined(__x86_64) || \
defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
typedef unsigned long long rhash_uptr_t;
#else
typedef unsigned long rhash_uptr_t;
#endif
/** The value returned by rhash_transmit on error */
#define RHASH_ERROR ((rhash_uptr_t)-1)
/** Convert a pointer to rhash_uptr_t */
#define RHASH_STR2UPTR(str) ((rhash_uptr_t)(char*)(str))
/** Convert a rhash_uptr_t to a void* pointer */
#define RHASH_UPTR2PVOID(u) ((void*)((char*)0 + (u)))
/* rhash API to set/get data via messages */
RHASH_API rhash_uptr_t rhash_transmit(
unsigned msg_id, void* dst, rhash_uptr_t ldata, rhash_uptr_t rdata);
/* rhash message constants */
#define RMSG_GET_CONTEXT 1
#define RMSG_CANCEL 2
#define RMSG_IS_CANCELED 3
#define RMSG_GET_FINALIZED 4
#define RMSG_SET_AUTOFINAL 5
#define RMSG_SET_OPENSSL_MASK 10
#define RMSG_GET_OPENSSL_MASK 11
#define RMSG_BT_ADD_FILE 32
#define RMSG_BT_SET_OPTIONS 33
#define RMSG_BT_SET_ANNOUNCE 34
#define RMSG_BT_SET_PIECE_LENGTH 35
#define RMSG_BT_SET_PROGRAM_NAME 36
#define RMSG_BT_GET_TEXT 37
#define RMSG_BT_SET_BATCH_SIZE 38
/* possible BitTorrent options for the RMSG_BT_SET_OPTIONS message */
#define RHASH_BT_OPT_PRIVATE 1
#define RHASH_BT_OPT_INFOHASH_ONLY 2
/* helper macros */
/** Get a pointer to context of the specified hash function */
#define rhash_get_context_ptr(ctx, hash_id) RHASH_UPTR2PVOID(rhash_transmit(RMSG_GET_CONTEXT, ctx, hash_id, 0))
/** Cancel hash calculation of a file */
#define rhash_cancel(ctx) rhash_transmit(RMSG_CANCEL, ctx, 0, 0)
/** Return non-zero if hash calculation was canceled, zero otherwise */
#define rhash_is_canceled(ctx) rhash_transmit(RMSG_IS_CANCELED, ctx, 0, 0)
/** Return non-zero if rhash_final was called for rhash_context */
#define rhash_get_finalized(ctx) rhash_transmit(RMSG_GET_FINALIZED, ctx, 0, 0)
/**
* Turn on/off the auto-final flag for the given rhash_context. By default
* auto-final is on, which means rhash_final is called automatically, if
* needed when a hash value is retrived by rhash_print call.
*/
#define rhash_set_autofinal(ctx, on) rhash_transmit(RMSG_SET_AUTOFINAL, ctx, on, 0)
/**
* Set the bit-mask of hash algorithms to be calculated by OpenSSL library.
* The call rhash_set_openssl_mask(0) made before rhash_library_init(),
* turns off loading of the OpenSSL dynamic library.
* This call works if the LibRHash was compiled with OpenSSL support.
*/
#define rhash_set_openssl_mask(mask) rhash_transmit(RMSG_SET_OPENSSL_MASK, NULL, mask, 0)
/**
* Return current bit-mask of hash algorithms selected to be calculated
* by OpenSSL library.
*/
#define rhash_get_openssl_mask() rhash_transmit(RMSG_GET_OPENSSL_MASK, NULL, 0, 0)
/** The bit mask of hash algorithms implemented by OpenSSL */
#if defined(USE_OPENSSL) || defined(OPENSSL_RUNTIME)
# define RHASH_OPENSSL_SUPPORTED_HASHES (RHASH_MD4 | RHASH_MD5 | \
RHASH_SHA1 | RHASH_SHA224 | RHASH_SHA256 | RHASH_SHA384 | \
RHASH_SHA512 | RHASH_RIPEMD160 | RHASH_WHIRLPOOL)
#else
# define RHASH_OPENSSL_SUPPORTED_HASHES 0
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* RHASH_H */

View File

@ -0,0 +1,196 @@
/* sha1.c - an implementation of Secure Hash Algorithm 1 (SHA1)
* based on RFC 3174.
*
* Copyright: 2008-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
#include <string.h>
#include "byte_order.h"
#include "sha1.h"
/**
* Initialize context before calculaing hash.
*
* @param ctx context to initialize
*/
void rhash_sha1_init(sha1_ctx *ctx)
{
ctx->length = 0;
/* initialize algorithm state */
ctx->hash[0] = 0x67452301;
ctx->hash[1] = 0xefcdab89;
ctx->hash[2] = 0x98badcfe;
ctx->hash[3] = 0x10325476;
ctx->hash[4] = 0xc3d2e1f0;
}
/**
* The core transformation. Process a 512-bit block.
* The function has been taken from RFC 3174 with little changes.
*
* @param hash algorithm state
* @param block the message block to process
*/
static void rhash_sha1_process_block(unsigned* hash, const unsigned* block)
{
int t; /* Loop counter */
uint32_t temp; /* Temporary word value */
uint32_t W[80]; /* Word sequence */
uint32_t A, B, C, D, E; /* Word buffers */
/* initialize the first 16 words in the array W */
for (t = 0; t < 16; t++) {
/* note: it is much faster to apply be2me here, then using be32_copy */
W[t] = be2me_32(block[t]);
}
/* initialize the rest */
for (t = 16; t < 80; t++) {
W[t] = ROTL32(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
}
A = hash[0];
B = hash[1];
C = hash[2];
D = hash[3];
E = hash[4];
for (t = 0; t < 20; t++) {
/* the following is faster than ((B & C) | ((~B) & D)) */
temp = ROTL32(A, 5) + (((C ^ D) & B) ^ D)
+ E + W[t] + 0x5A827999;
E = D;
D = C;
C = ROTL32(B, 30);
B = A;
A = temp;
}
for (t = 20; t < 40; t++) {
temp = ROTL32(A, 5) + (B ^ C ^ D) + E + W[t] + 0x6ED9EBA1;
E = D;
D = C;
C = ROTL32(B, 30);
B = A;
A = temp;
}
for (t = 40; t < 60; t++) {
temp = ROTL32(A, 5) + ((B & C) | (B & D) | (C & D))
+ E + W[t] + 0x8F1BBCDC;
E = D;
D = C;
C = ROTL32(B, 30);
B = A;
A = temp;
}
for (t = 60; t < 80; t++) {
temp = ROTL32(A, 5) + (B ^ C ^ D) + E + W[t] + 0xCA62C1D6;
E = D;
D = C;
C = ROTL32(B, 30);
B = A;
A = temp;
}
hash[0] += A;
hash[1] += B;
hash[2] += C;
hash[3] += D;
hash[4] += E;
}
/**
* Calculate message hash.
* Can be called repeatedly with chunks of the message to be hashed.
*
* @param ctx the algorithm context containing current hashing state
* @param msg message chunk
* @param size length of the message chunk
*/
void rhash_sha1_update(sha1_ctx *ctx, const unsigned char* msg, size_t size)
{
unsigned index = (unsigned)ctx->length & 63;
ctx->length += size;
/* fill partial block */
if (index) {
unsigned left = sha1_block_size - index;
memcpy(ctx->message + index, msg, (size < left ? size : left));
if (size < left) return;
/* process partial block */
rhash_sha1_process_block(ctx->hash, (unsigned*)ctx->message);
msg += left;
size -= left;
}
while (size >= sha1_block_size) {
unsigned* aligned_message_block;
if (IS_ALIGNED_32(msg)) {
/* the most common case is processing of an already aligned message
without copying it */
aligned_message_block = (unsigned*)msg;
} else {
memcpy(ctx->message, msg, sha1_block_size);
aligned_message_block = (unsigned*)ctx->message;
}
rhash_sha1_process_block(ctx->hash, aligned_message_block);
msg += sha1_block_size;
size -= sha1_block_size;
}
if (size) {
/* save leftovers */
memcpy(ctx->message, msg, size);
}
}
/**
* Store calculated hash into the given array.
*
* @param ctx the algorithm context containing current hashing state
* @param result calculated hash in binary form
*/
void rhash_sha1_final(sha1_ctx *ctx, unsigned char* result)
{
unsigned index = (unsigned)ctx->length & 63;
unsigned* msg32 = (unsigned*)ctx->message;
/* pad message and run for last block */
ctx->message[index++] = 0x80;
while ((index & 3) != 0) {
ctx->message[index++] = 0;
}
index >>= 2;
/* if no room left in the message to store 64-bit message length */
if (index > 14) {
/* then fill the rest with zeros and process it */
while (index < 16) {
msg32[index++] = 0;
}
rhash_sha1_process_block(ctx->hash, msg32);
index = 0;
}
while (index < 14) {
msg32[index++] = 0;
}
msg32[14] = be2me_32( (unsigned)(ctx->length >> 29) );
msg32[15] = be2me_32( (unsigned)(ctx->length << 3) );
rhash_sha1_process_block(ctx->hash, msg32);
if (result) be32_copy(result, 0, &ctx->hash, sha1_hash_size);
}

View File

@ -0,0 +1,31 @@
/* sha1.h */
#ifndef SHA1_H
#define SHA1_H
#include "ustd.h"
#ifdef __cplusplus
extern "C" {
#endif
#define sha1_block_size 64
#define sha1_hash_size 20
/* algorithm context */
typedef struct sha1_ctx
{
unsigned char message[sha1_block_size]; /* 512-bit buffer for leftovers */
uint64_t length; /* number of processed bytes */
unsigned hash[5]; /* 160-bit algorithm internal hashing state */
} sha1_ctx;
/* hash functions */
void rhash_sha1_init(sha1_ctx *ctx);
void rhash_sha1_update(sha1_ctx *ctx, const unsigned char* msg, size_t size);
void rhash_sha1_final(sha1_ctx *ctx, unsigned char* result);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* SHA1_H */

View File

@ -0,0 +1,241 @@
/* sha256.c - an implementation of SHA-256/224 hash functions
* based on FIPS 180-3 (Federal Information Processing Standart).
*
* Copyright: 2010-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
#include <string.h>
#include "byte_order.h"
#include "sha256.h"
/* SHA-224 and SHA-256 constants for 64 rounds. These words represent
* the first 32 bits of the fractional parts of the cube
* roots of the first 64 prime numbers. */
static const unsigned rhash_k256[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
/* The SHA256/224 functions defined by FIPS 180-3, 4.1.2 */
/* Optimized version of Ch(x,y,z)=((x & y) | (~x & z)) */
#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
/* Optimized version of Maj(x,y,z)=((x & y) ^ (x & z) ^ (y & z)) */
#define Maj(x,y,z) (((x) & (y)) ^ ((z) & ((x) ^ (y))))
#define Sigma0(x) (ROTR32((x), 2) ^ ROTR32((x), 13) ^ ROTR32((x), 22))
#define Sigma1(x) (ROTR32((x), 6) ^ ROTR32((x), 11) ^ ROTR32((x), 25))
#define sigma0(x) (ROTR32((x), 7) ^ ROTR32((x), 18) ^ ((x) >> 3))
#define sigma1(x) (ROTR32((x),17) ^ ROTR32((x), 19) ^ ((x) >> 10))
/* Recalculate element n-th of circular buffer W using formula
* W[n] = sigma1(W[n - 2]) + W[n - 7] + sigma0(W[n - 15]) + W[n - 16]; */
#define RECALCULATE_W(W,n) (W[n] += \
(sigma1(W[(n - 2) & 15]) + W[(n - 7) & 15] + sigma0(W[(n - 15) & 15])))
#define ROUND(a,b,c,d,e,f,g,h,k,data) { \
unsigned T1 = h + Sigma1(e) + Ch(e,f,g) + k + (data); \
d += T1, h = T1 + Sigma0(a) + Maj(a,b,c); }
#define ROUND_1_16(a,b,c,d,e,f,g,h,n) \
ROUND(a,b,c,d,e,f,g,h, rhash_k256[n], W[n] = be2me_32(block[n]))
#define ROUND_17_64(a,b,c,d,e,f,g,h,n) \
ROUND(a,b,c,d,e,f,g,h, k[n], RECALCULATE_W(W, n))
/**
* Initialize context before calculaing hash.
*
* @param ctx context to initialize
*/
void rhash_sha256_init(sha256_ctx *ctx)
{
/* Initial values. These words were obtained by taking the first 32
* bits of the fractional parts of the square roots of the first
* eight prime numbers. */
static const unsigned SHA256_H0[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
ctx->length = 0;
ctx->digest_length = sha256_hash_size;
/* initialize algorithm state */
memcpy(ctx->hash, SHA256_H0, sizeof(ctx->hash));
}
/**
* Initialize context before calculaing hash.
*
* @param ctx context to initialize
*/
void rhash_sha224_init(struct sha256_ctx *ctx)
{
/* Initial values from FIPS 180-3. These words were obtained by taking
* bits from 33th to 64th of the fractional parts of the square
* roots of ninth through sixteenth prime numbers. */
static const unsigned SHA224_H0[8] = {
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
};
ctx->length = 0;
ctx->digest_length = sha224_hash_size;
memcpy(ctx->hash, SHA224_H0, sizeof(ctx->hash));
}
/**
* The core transformation. Process a 512-bit block.
*
* @param hash algorithm state
* @param block the message block to process
*/
static void rhash_sha256_process_block(unsigned hash[8], unsigned block[16])
{
unsigned A, B, C, D, E, F, G, H;
unsigned W[16];
const unsigned *k;
int i;
A = hash[0], B = hash[1], C = hash[2], D = hash[3];
E = hash[4], F = hash[5], G = hash[6], H = hash[7];
/* Compute SHA using alternate Method: FIPS 180-3 6.1.3 */
ROUND_1_16(A, B, C, D, E, F, G, H, 0);
ROUND_1_16(H, A, B, C, D, E, F, G, 1);
ROUND_1_16(G, H, A, B, C, D, E, F, 2);
ROUND_1_16(F, G, H, A, B, C, D, E, 3);
ROUND_1_16(E, F, G, H, A, B, C, D, 4);
ROUND_1_16(D, E, F, G, H, A, B, C, 5);
ROUND_1_16(C, D, E, F, G, H, A, B, 6);
ROUND_1_16(B, C, D, E, F, G, H, A, 7);
ROUND_1_16(A, B, C, D, E, F, G, H, 8);
ROUND_1_16(H, A, B, C, D, E, F, G, 9);
ROUND_1_16(G, H, A, B, C, D, E, F, 10);
ROUND_1_16(F, G, H, A, B, C, D, E, 11);
ROUND_1_16(E, F, G, H, A, B, C, D, 12);
ROUND_1_16(D, E, F, G, H, A, B, C, 13);
ROUND_1_16(C, D, E, F, G, H, A, B, 14);
ROUND_1_16(B, C, D, E, F, G, H, A, 15);
for (i = 16, k = &rhash_k256[16]; i < 64; i += 16, k += 16) {
ROUND_17_64(A, B, C, D, E, F, G, H, 0);
ROUND_17_64(H, A, B, C, D, E, F, G, 1);
ROUND_17_64(G, H, A, B, C, D, E, F, 2);
ROUND_17_64(F, G, H, A, B, C, D, E, 3);
ROUND_17_64(E, F, G, H, A, B, C, D, 4);
ROUND_17_64(D, E, F, G, H, A, B, C, 5);
ROUND_17_64(C, D, E, F, G, H, A, B, 6);
ROUND_17_64(B, C, D, E, F, G, H, A, 7);
ROUND_17_64(A, B, C, D, E, F, G, H, 8);
ROUND_17_64(H, A, B, C, D, E, F, G, 9);
ROUND_17_64(G, H, A, B, C, D, E, F, 10);
ROUND_17_64(F, G, H, A, B, C, D, E, 11);
ROUND_17_64(E, F, G, H, A, B, C, D, 12);
ROUND_17_64(D, E, F, G, H, A, B, C, 13);
ROUND_17_64(C, D, E, F, G, H, A, B, 14);
ROUND_17_64(B, C, D, E, F, G, H, A, 15);
}
hash[0] += A, hash[1] += B, hash[2] += C, hash[3] += D;
hash[4] += E, hash[5] += F, hash[6] += G, hash[7] += H;
}
/**
* Calculate message hash.
* Can be called repeatedly with chunks of the message to be hashed.
*
* @param ctx the algorithm context containing current hashing state
* @param msg message chunk
* @param size length of the message chunk
*/
void rhash_sha256_update(sha256_ctx *ctx, const unsigned char *msg, size_t size)
{
size_t index = (size_t)ctx->length & 63;
ctx->length += size;
/* fill partial block */
if (index) {
size_t left = sha256_block_size - index;
memcpy((char*)ctx->message + index, msg, (size < left ? size : left));
if (size < left) return;
/* process partial block */
rhash_sha256_process_block(ctx->hash, (unsigned*)ctx->message);
msg += left;
size -= left;
}
while (size >= sha256_block_size) {
unsigned* aligned_message_block;
if (IS_ALIGNED_32(msg)) {
/* the most common case is processing of an already aligned message
without copying it */
aligned_message_block = (unsigned*)msg;
} else {
memcpy(ctx->message, msg, sha256_block_size);
aligned_message_block = (unsigned*)ctx->message;
}
rhash_sha256_process_block(ctx->hash, aligned_message_block);
msg += sha256_block_size;
size -= sha256_block_size;
}
if (size) {
memcpy(ctx->message, msg, size); /* save leftovers */
}
}
/**
* Store calculated hash into the given array.
*
* @param ctx the algorithm context containing current hashing state
* @param result calculated hash in binary form
*/
void rhash_sha256_final(sha256_ctx *ctx, unsigned char* result)
{
size_t index = ((unsigned)ctx->length & 63) >> 2;
unsigned shift = ((unsigned)ctx->length & 3) * 8;
/* pad message and run for last block */
/* append the byte 0x80 to the message */
ctx->message[index] &= le2me_32(~(0xFFFFFFFF << shift));
ctx->message[index++] ^= le2me_32(0x80 << shift);
/* if no room left in the message to store 64-bit message length */
if (index > 14) {
/* then fill the rest with zeros and process it */
while (index < 16) {
ctx->message[index++] = 0;
}
rhash_sha256_process_block(ctx->hash, ctx->message);
index = 0;
}
while (index < 14) {
ctx->message[index++] = 0;
}
ctx->message[14] = be2me_32( (unsigned)(ctx->length >> 29) );
ctx->message[15] = be2me_32( (unsigned)(ctx->length << 3) );
rhash_sha256_process_block(ctx->hash, ctx->message);
if (result) be32_copy(result, 0, ctx->hash, ctx->digest_length);
}

View File

@ -0,0 +1,32 @@
/* sha.h sha256 and sha224 hash functions */
#ifndef SHA256_H
#define SHA256_H
#include "ustd.h"
#ifdef __cplusplus
extern "C" {
#endif
#define sha256_block_size 64
#define sha256_hash_size 32
#define sha224_hash_size 28
/* algorithm context */
typedef struct sha256_ctx
{
unsigned message[16]; /* 512-bit buffer for leftovers */
uint64_t length; /* number of processed bytes */
unsigned hash[8]; /* 256-bit algorithm internal hashing state */
unsigned digest_length; /* length of the algorithm digest in bytes */
} sha256_ctx;
void rhash_sha224_init(sha256_ctx *ctx);
void rhash_sha256_init(sha256_ctx *ctx);
void rhash_sha256_update(sha256_ctx *ctx, const unsigned char* data, size_t length);
void rhash_sha256_final(sha256_ctx *ctx, unsigned char result[32]);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* SHA256_H */

View File

@ -0,0 +1,255 @@
/* sha512.c - an implementation of SHA-384/512 hash functions
* based on FIPS 180-3 (Federal Information Processing Standart).
*
* Copyright: 2010-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
#include <string.h>
#include "byte_order.h"
#include "sha512.h"
/* SHA-384 and SHA-512 constants for 80 rounds. These qwords represent
* the first 64 bits of the fractional parts of the cube
* roots of the first 80 prime numbers. */
static const uint64_t rhash_k512[80] = {
I64(0x428a2f98d728ae22), I64(0x7137449123ef65cd), I64(0xb5c0fbcfec4d3b2f),
I64(0xe9b5dba58189dbbc), I64(0x3956c25bf348b538), I64(0x59f111f1b605d019),
I64(0x923f82a4af194f9b), I64(0xab1c5ed5da6d8118), I64(0xd807aa98a3030242),
I64(0x12835b0145706fbe), I64(0x243185be4ee4b28c), I64(0x550c7dc3d5ffb4e2),
I64(0x72be5d74f27b896f), I64(0x80deb1fe3b1696b1), I64(0x9bdc06a725c71235),
I64(0xc19bf174cf692694), I64(0xe49b69c19ef14ad2), I64(0xefbe4786384f25e3),
I64(0x0fc19dc68b8cd5b5), I64(0x240ca1cc77ac9c65), I64(0x2de92c6f592b0275),
I64(0x4a7484aa6ea6e483), I64(0x5cb0a9dcbd41fbd4), I64(0x76f988da831153b5),
I64(0x983e5152ee66dfab), I64(0xa831c66d2db43210), I64(0xb00327c898fb213f),
I64(0xbf597fc7beef0ee4), I64(0xc6e00bf33da88fc2), I64(0xd5a79147930aa725),
I64(0x06ca6351e003826f), I64(0x142929670a0e6e70), I64(0x27b70a8546d22ffc),
I64(0x2e1b21385c26c926), I64(0x4d2c6dfc5ac42aed), I64(0x53380d139d95b3df),
I64(0x650a73548baf63de), I64(0x766a0abb3c77b2a8), I64(0x81c2c92e47edaee6),
I64(0x92722c851482353b), I64(0xa2bfe8a14cf10364), I64(0xa81a664bbc423001),
I64(0xc24b8b70d0f89791), I64(0xc76c51a30654be30), I64(0xd192e819d6ef5218),
I64(0xd69906245565a910), I64(0xf40e35855771202a), I64(0x106aa07032bbd1b8),
I64(0x19a4c116b8d2d0c8), I64(0x1e376c085141ab53), I64(0x2748774cdf8eeb99),
I64(0x34b0bcb5e19b48a8), I64(0x391c0cb3c5c95a63), I64(0x4ed8aa4ae3418acb),
I64(0x5b9cca4f7763e373), I64(0x682e6ff3d6b2b8a3), I64(0x748f82ee5defb2fc),
I64(0x78a5636f43172f60), I64(0x84c87814a1f0ab72), I64(0x8cc702081a6439ec),
I64(0x90befffa23631e28), I64(0xa4506cebde82bde9), I64(0xbef9a3f7b2c67915),
I64(0xc67178f2e372532b), I64(0xca273eceea26619c), I64(0xd186b8c721c0c207),
I64(0xeada7dd6cde0eb1e), I64(0xf57d4f7fee6ed178), I64(0x06f067aa72176fba),
I64(0x0a637dc5a2c898a6), I64(0x113f9804bef90dae), I64(0x1b710b35131c471b),
I64(0x28db77f523047d84), I64(0x32caab7b40c72493), I64(0x3c9ebe0a15c9bebc),
I64(0x431d67c49c100d4c), I64(0x4cc5d4becb3e42b6), I64(0x597f299cfc657e2a),
I64(0x5fcb6fab3ad6faec), I64(0x6c44198c4a475817)
};
/* The SHA512/384 functions defined by FIPS 180-3, 4.1.3 */
/* Optimized version of Ch(x,y,z)=((x & y) | (~x & z)) */
#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
/* Optimized version of Maj(x,y,z)=((x & y) ^ (x & z) ^ (y & z)) */
#define Maj(x,y,z) (((x) & (y)) ^ ((z) & ((x) ^ (y))))
#define Sigma0(x) (ROTR64((x), 28) ^ ROTR64((x), 34) ^ ROTR64((x), 39))
#define Sigma1(x) (ROTR64((x), 14) ^ ROTR64((x), 18) ^ ROTR64((x), 41))
#define sigma0(x) (ROTR64((x), 1) ^ ROTR64((x), 8) ^ ((x) >> 7))
#define sigma1(x) (ROTR64((x), 19) ^ ROTR64((x), 61) ^ ((x) >> 6))
/* Recalculate element n-th of circular buffer W using formula
* W[n] = sigma1(W[n - 2]) + W[n - 7] + sigma0(W[n - 15]) + W[n - 16]; */
#define RECALCULATE_W(W,n) (W[n] += \
(sigma1(W[(n - 2) & 15]) + W[(n - 7) & 15] + sigma0(W[(n - 15) & 15])))
#define ROUND(a,b,c,d,e,f,g,h,k,data) { \
uint64_t T1 = h + Sigma1(e) + Ch(e,f,g) + k + (data); \
d += T1, h = T1 + Sigma0(a) + Maj(a,b,c); }
#define ROUND_1_16(a,b,c,d,e,f,g,h,n) \
ROUND(a,b,c,d,e,f,g,h, rhash_k512[n], W[n] = be2me_64(block[n]))
#define ROUND_17_80(a,b,c,d,e,f,g,h,n) \
ROUND(a,b,c,d,e,f,g,h, k[n], RECALCULATE_W(W, n))
/**
* Initialize context before calculating hash.
*
* @param ctx context to initialize
*/
void rhash_sha512_init(sha512_ctx *ctx)
{
/* Initial values. These words were obtained by taking the first 32
* bits of the fractional parts of the square roots of the first
* eight prime numbers. */
static const uint64_t SHA512_H0[8] = {
I64(0x6a09e667f3bcc908), I64(0xbb67ae8584caa73b), I64(0x3c6ef372fe94f82b),
I64(0xa54ff53a5f1d36f1), I64(0x510e527fade682d1), I64(0x9b05688c2b3e6c1f),
I64(0x1f83d9abfb41bd6b), I64(0x5be0cd19137e2179)
};
ctx->length = 0;
ctx->digest_length = sha512_hash_size;
/* initialize algorithm state */
memcpy(ctx->hash, SHA512_H0, sizeof(ctx->hash));
}
/**
* Initialize context before calculaing hash.
*
* @param ctx context to initialize
*/
void rhash_sha384_init(struct sha512_ctx *ctx)
{
/* Initial values from FIPS 180-3. These words were obtained by taking
* the first sixty-four bits of the fractional parts of the square
* roots of ninth through sixteenth prime numbers. */
static const uint64_t SHA384_H0[8] = {
I64(0xcbbb9d5dc1059ed8), I64(0x629a292a367cd507), I64(0x9159015a3070dd17),
I64(0x152fecd8f70e5939), I64(0x67332667ffc00b31), I64(0x8eb44a8768581511),
I64(0xdb0c2e0d64f98fa7), I64(0x47b5481dbefa4fa4)
};
ctx->length = 0;
ctx->digest_length = sha384_hash_size;
memcpy(ctx->hash, SHA384_H0, sizeof(ctx->hash));
}
/**
* The core transformation. Process a 512-bit block.
*
* @param hash algorithm state
* @param block the message block to process
*/
static void rhash_sha512_process_block(uint64_t hash[8], uint64_t block[16])
{
uint64_t A, B, C, D, E, F, G, H;
uint64_t W[16];
const uint64_t *k;
int i;
A = hash[0], B = hash[1], C = hash[2], D = hash[3];
E = hash[4], F = hash[5], G = hash[6], H = hash[7];
/* Compute SHA using alternate Method: FIPS 180-3 6.1.3 */
ROUND_1_16(A, B, C, D, E, F, G, H, 0);
ROUND_1_16(H, A, B, C, D, E, F, G, 1);
ROUND_1_16(G, H, A, B, C, D, E, F, 2);
ROUND_1_16(F, G, H, A, B, C, D, E, 3);
ROUND_1_16(E, F, G, H, A, B, C, D, 4);
ROUND_1_16(D, E, F, G, H, A, B, C, 5);
ROUND_1_16(C, D, E, F, G, H, A, B, 6);
ROUND_1_16(B, C, D, E, F, G, H, A, 7);
ROUND_1_16(A, B, C, D, E, F, G, H, 8);
ROUND_1_16(H, A, B, C, D, E, F, G, 9);
ROUND_1_16(G, H, A, B, C, D, E, F, 10);
ROUND_1_16(F, G, H, A, B, C, D, E, 11);
ROUND_1_16(E, F, G, H, A, B, C, D, 12);
ROUND_1_16(D, E, F, G, H, A, B, C, 13);
ROUND_1_16(C, D, E, F, G, H, A, B, 14);
ROUND_1_16(B, C, D, E, F, G, H, A, 15);
for (i = 16, k = &rhash_k512[16]; i < 80; i += 16, k += 16) {
ROUND_17_80(A, B, C, D, E, F, G, H, 0);
ROUND_17_80(H, A, B, C, D, E, F, G, 1);
ROUND_17_80(G, H, A, B, C, D, E, F, 2);
ROUND_17_80(F, G, H, A, B, C, D, E, 3);
ROUND_17_80(E, F, G, H, A, B, C, D, 4);
ROUND_17_80(D, E, F, G, H, A, B, C, 5);
ROUND_17_80(C, D, E, F, G, H, A, B, 6);
ROUND_17_80(B, C, D, E, F, G, H, A, 7);
ROUND_17_80(A, B, C, D, E, F, G, H, 8);
ROUND_17_80(H, A, B, C, D, E, F, G, 9);
ROUND_17_80(G, H, A, B, C, D, E, F, 10);
ROUND_17_80(F, G, H, A, B, C, D, E, 11);
ROUND_17_80(E, F, G, H, A, B, C, D, 12);
ROUND_17_80(D, E, F, G, H, A, B, C, 13);
ROUND_17_80(C, D, E, F, G, H, A, B, 14);
ROUND_17_80(B, C, D, E, F, G, H, A, 15);
}
hash[0] += A, hash[1] += B, hash[2] += C, hash[3] += D;
hash[4] += E, hash[5] += F, hash[6] += G, hash[7] += H;
}
/**
* Calculate message hash.
* Can be called repeatedly with chunks of the message to be hashed.
*
* @param ctx the algorithm context containing current hashing state
* @param msg message chunk
* @param size length of the message chunk
*/
void rhash_sha512_update(sha512_ctx *ctx, const unsigned char *msg, size_t size)
{
size_t index = (size_t)ctx->length & 127;
ctx->length += size;
/* fill partial block */
if (index) {
size_t left = sha512_block_size - index;
memcpy((char*)ctx->message + index, msg, (size < left ? size : left));
if (size < left) return;
/* process partial block */
rhash_sha512_process_block(ctx->hash, ctx->message);
msg += left;
size -= left;
}
while (size >= sha512_block_size) {
uint64_t* aligned_message_block;
if (IS_ALIGNED_64(msg)) {
/* the most common case is processing of an already aligned message
without copying it */
aligned_message_block = (uint64_t*)msg;
} else {
memcpy(ctx->message, msg, sha512_block_size);
aligned_message_block = ctx->message;
}
rhash_sha512_process_block(ctx->hash, aligned_message_block);
msg += sha512_block_size;
size -= sha512_block_size;
}
if (size) {
memcpy(ctx->message, msg, size); /* save leftovers */
}
}
/**
* Store calculated hash into the given array.
*
* @param ctx the algorithm context containing current hashing state
* @param result calculated hash in binary form
*/
void rhash_sha512_final(sha512_ctx *ctx, unsigned char* result)
{
size_t index = ((unsigned)ctx->length & 127) >> 3;
unsigned shift = ((unsigned)ctx->length & 7) * 8;
/* pad message and process the last block */
/* append the byte 0x80 to the message */
ctx->message[index] &= le2me_64( ~(I64(0xFFFFFFFFFFFFFFFF) << shift) );
ctx->message[index++] ^= le2me_64( I64(0x80) << shift );
/* if no room left in the message to store 128-bit message length */
if (index >= 15) {
if (index == 15) ctx->message[index] = 0;
rhash_sha512_process_block(ctx->hash, ctx->message);
index = 0;
}
while (index < 15) {
ctx->message[index++] = 0;
}
ctx->message[15] = be2me_64(ctx->length << 3);
rhash_sha512_process_block(ctx->hash, ctx->message);
if (result) be64_copy(result, 0, ctx->hash, ctx->digest_length);
}

View File

@ -0,0 +1,32 @@
/* sha.h sha512 and sha384 hash functions */
#ifndef SHA512_H
#define SHA512_H
#include "ustd.h"
#ifdef __cplusplus
extern "C" {
#endif
#define sha512_block_size 128
#define sha512_hash_size 64
#define sha384_hash_size 48
/* algorithm context */
typedef struct sha512_ctx
{
uint64_t message[16]; /* 1024-bit buffer for leftovers */
uint64_t length; /* number of processed bytes */
uint64_t hash[8]; /* 512-bit algorithm internal hashing state */
unsigned digest_length; /* length of the algorithm digest in bytes */
} sha512_ctx;
void rhash_sha384_init(sha512_ctx *ctx);
void rhash_sha512_init(sha512_ctx *ctx);
void rhash_sha512_update(sha512_ctx *ctx, const unsigned char* data, size_t length);
void rhash_sha512_final(sha512_ctx *ctx, unsigned char* result);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* SHA512_H */

View File

@ -0,0 +1,30 @@
/* ustd.h common macros and includes */
#ifndef LIBRHASH_USTD_H
#define LIBRHASH_USTD_H
#if _MSC_VER >= 1300
# define int64_t __int64
# define int32_t __int32
# define int16_t __int16
# define int8_t __int8
# define uint64_t unsigned __int64
# define uint32_t unsigned __int32
# define uint16_t unsigned __int16
# define uint8_t unsigned __int8
/* disable warnings: The POSIX name for this item is deprecated. Use the ISO C++ conformant name. */
#pragma warning(disable : 4996)
#else /* _MSC_VER >= 1300 */
# include <stdint.h>
# include <unistd.h>
#endif /* _MSC_VER >= 1300 */
#if _MSC_VER <= 1300
# include <stdlib.h> /* size_t for vc6.0 */
#endif /* _MSC_VER <= 1300 */
#endif /* LIBRHASH_USTD_H */

View File

@ -0,0 +1,31 @@
/* util.h */
#ifndef UTIL_H
#define UTIL_H
#ifdef __cplusplus
extern "C" {
#endif
#if (defined(__GNUC__) && __GNUC__ >= 4 && (__GNUC__ > 4 || __GNUC_MINOR__ >= 1) \
&& defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) \
|| (defined(__INTEL_COMPILER) && !defined(_WIN32))
/* atomic operations are defined by ICC and GCC >= 4.1, but by the later one supposedly not for ARM */
/* note: ICC on ia64 platform possibly require ia64intrin.h, need testing */
# define atomic_compare_and_swap(ptr, oldval, newval) __sync_val_compare_and_swap(ptr, oldval, newval)
#elif defined(_MSC_VER)
# include <windows.h>
# define atomic_compare_and_swap(ptr, oldval, newval) InterlockedCompareExchange(ptr, newval, oldval)
#elif defined(__sun)
# include <atomic.h>
# define atomic_compare_and_swap(ptr, oldval, newval) atomic_cas_32(ptr, oldval, newval)
#else
/* pray that it will work */
# define atomic_compare_and_swap(ptr, oldval, newval) { if(*(ptr) == (oldval)) *(ptr) = (newval); }
# define NO_ATOMIC_BUILTINS
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* UTIL_H */