/* See LICENSE file for copyright and license details. */
#ifndef LIBHASHSUM_H
#define LIBHASHSUM_H
#include <stddef.h>
#include <stdint.h>
#include <libsha1.h>
#include <libsha2.h>
#if defined(__GNUC__)
# define LIBHASHSUM_USERET_ __attribute__((__warn_unused_result__))
# define LIBHASHSUM_1_NONNULL_ __attribute__((__nonnull__(1)))
#else
# define LIBHASHSUM_USERET_
# define LIBHASHSUM_1_NONNULL_
#endif
/**
* Hashing algorithm
*
* @since 1.0
*/
enum libhashsum_algorithm {
/* since 1.0 */
LIBHASHSUM_MD2, /**< MD2 */
LIBHASHSUM_MD4, /**< MD4 */
LIBHASHSUM_MD5, /**< MD5; this algorithm has been compromised */
LIBHASHSUM_RIPEMD_128, /**< RIPEMD-128 */
LIBHASHSUM_RIPEMD_160, /**< RIPEMD-160 */
LIBHASHSUM_RIPEMD_256, /**< RIPEMD-256 */
LIBHASHSUM_RIPEMD_320, /**< RIPEMD-320 */
LIBHASHSUM_SHA0, /**< SHA0; this algorithm has been compromised */
LIBHASHSUM_SHA1, /**< SHA1; this algorithm has been compromised */
LIBHASHSUM_SHA_224, /**< SHA-224 (SHA2) */
LIBHASHSUM_SHA_256, /**< SHA-256 (SHA2) */
LIBHASHSUM_SHA_384, /**< SHA-384 (SHA2) */
LIBHASHSUM_SHA_512, /**< SHA-512 (SHA2) */
LIBHASHSUM_SHA_512_224, /**< SHA-512/224 (SHA2) */
LIBHASHSUM_SHA_512_256 /**< SHA-512/256 (SHA2) */
};
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_MD2`
*
* @since 1.0
*/
#define LIBHASHSUM_MD2_HASH_SIZE 16
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_MD4`
*
* @since 1.0
*/
#define LIBHASHSUM_MD4_HASH_SIZE 16
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_MD5`
*
* @since 1.0
*/
#define LIBHASHSUM_MD5_HASH_SIZE 16
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_RIPEMD_128`
*
* @since 1.0
*/
#define LIBHASHSUM_RIPEMD_128_HASH_SIZE 16
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_RIPEMD_160`
*
* @since 1.0
*/
#define LIBHASHSUM_RIPEMD_160_HASH_SIZE 20
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_RIPEMD_256`
*
* @since 1.0
*/
#define LIBHASHSUM_RIPEMD_256_HASH_SIZE 32
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_RIPEMD_320`
*
* @since 1.0
*/
#define LIBHASHSUM_RIPEMD_320_HASH_SIZE 40
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_SHA0`
*
* @since 1.0
*/
#define LIBHASHSUM_SHA0_HASH_SIZE 20
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_SHA1`
*
* @since 1.0
*/
#define LIBHASHSUM_SHA1_HASH_SIZE 20
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_SHA_224`
*
* @since 1.0
*/
#define LIBHASHSUM_SHA_224_HASH_SIZE 28
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_SHA_256`
*
* @since 1.0
*/
#define LIBHASHSUM_SHA_256_HASH_SIZE 32
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_SHA_384`
*
* @since 1.0
*/
#define LIBHASHSUM_SHA_384_HASH_SIZE 48
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_SHA_512`
*
* @since 1.0
*/
#define LIBHASHSUM_SHA_512_HASH_SIZE 64
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_SHA_512_224`
*
* @since 1.0
*/
#define LIBHASHSUM_SHA_512_224_HASH_SIZE 28
/**
* The value of `struct libhashsum_hasher.hash_size` for `LIBHASHSUM_SHA_512_256`
*
* @since 1.0
*/
#define LIBHASHSUM_SHA_512_256_HASH_SIZE 32
/**
* Hash state
*
* For internal use
*/
union libhashsum_state {
struct {
unsigned char x[32];
unsigned char mp[16];
unsigned char mz[16];
unsigned char sum[16];
unsigned t;
} md2;
struct {
union {
uint32_t h32[4];
uint8_t sum[16];
} h;
union {
uint32_t m32[16];
uint8_t m8[64];
} m;
uint64_t count;
} md4;
struct {
union {
uint32_t h32[4];
uint8_t sum[16];
} h;
uint8_t m[64];
uint32_t w[16];
uint64_t count;
} md5;
struct {
union {
uint32_t h32[4];
uint8_t sum[16];
} h;
union {
uint32_t m32[16];
uint8_t m8[64];
} m;
uint64_t count;
} ripemd_128;
struct {
union {
uint32_t h32[5];
uint8_t sum[20];
} h;
union {
uint32_t m32[16];
uint8_t m8[64];
} m;
uint32_t w1[5];
uint32_t w2[5];
uint64_t count;
} ripemd_160;
struct {
union {
uint32_t h32[8];
uint8_t sum[32];
} h;
union {
uint32_t m32[16];
uint8_t m8[64];
} m;
uint64_t count;
} ripemd_256;
struct {
union {
uint32_t h32[10];
uint8_t sum[40];
} h;
union {
uint32_t m32[16];
uint8_t m8[64];
} m;
uint32_t w1[5];
uint32_t w2[5];
uint64_t count;
} ripemd_320;
struct {
struct libsha1_state s;
uint8_t sum[20];
} sha0, sha1;
struct {
struct libsha2_state s;
uint8_t sum[64];
} sha2;
};
/**
* Message hash functions and state
*
* @since 1.0
*/
struct libhashsum_hasher {
/**
* The used hash algorithm
*
* @since 1.0
*/
enum libhashsum_algorithm algorithm;
/**
* The number of bytes required for each
* call to `.process_block`
*
* @since 1.0
*/
size_t input_block_size;
/**
* The number of bytes in the resulting hash
*
* @since 1.0
*/
size_t hash_size;
/**
* The hash
*
* This will be set to `NULL` when the structure
* is initialised, but will be set to a pointer
* to a buffer inside `.state` once `.finalise_const`
* or `.finalise` has been called with successful
* completion
*
* @since 1.0
*/
unsigned char *hash_output;
/**
* Whether the algorithm supports non-whole octet input
*
* @since 1.0
*/
unsigned char supports_non_whole_bytes;
/**
* Update the hash state given additional
* input data
*
* @param this The object containing this function pointer
* @param data The new input data
* @param bytes The number of bytes available in `data`
* @return The number of bytes processed from `data`
*
* @since 1.0
*/
LIBHASHSUM_USERET_ LIBHASHSUM_1_NONNULL_
size_t (*process)(struct libhashsum_hasher *this, const void *data, size_t bytes);
/**
* Update the hash state given it's final
* input data
*
* Regardless of the algorithm's standard, the function
* will takes the lower bits from `data[bytes]`, if
* `extra_bits > 0` and use the for the additional bits;
* the least significant bit will be used as the first
* bit and the most significant bit will be used as the
* last bit
*
* @param this The object containing this function pointer
* @param data The new input data, the function may rewrite it's content
* @param bytes The number of bytes available in `data` for reading
* @param extra_bits Additional bits in `data` not covered by `bytes`
* @return 0 on success, -1 on failure
*
* @throws EINVAL `extra_bits` is greater than 7
* @throws EINVAL `extra_bits` is non-zero but `.supports_non_whole_bytes` is 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int (*finalise_const)(struct libhashsum_hasher *this, const void *data, size_t bytes, unsigned extra_bits);
/**
* Update the hash state given it's final
* input data
*
* Regardless of the algorithm's standard, the function
* will takes the lower bits from `data[bytes]`, if
* `extra_bits > 0` and use the for the additional bits;
* the least significant bit will be used as the first
* bit and the most significant bit will be used as the
* last bit
*
* @param this The object containing this function pointer
* @param data The new input data, the function may rewrite it's content
* @param bytes The number of bytes available in `data` for reading
* @param extra_bits Additional bits in `data` not covered by `bytes`
* @param size `bytes` plus any number of additional bytes available
* for the function to write additional data block padding
* @return 0 on success, -1 on failure
*
* @throws EINVAL `extra_bits` is greater than 7
* @throws EINVAL `extra_bits` is non-zero but `.supports_non_whole_bytes` is 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int (*finalise)(struct libhashsum_hasher *this, void *data, size_t bytes, unsigned extra_bits, size_t size);
/**
* The hash state
*
* For internal use
*
* @since 1.0
*/
union libhashsum_state state;
};
/**
* Create an initialised state for a hash algorithm
* and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @param algorithm The hashing algorithm
* @return 0 on success, -1 on failure
*
* @throws EINVAL `algorithm` is unsupported
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_hasher(struct libhashsum_hasher *this, enum libhashsum_algorithm algorithm);
/**
* Create an initialised state for MD2
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_md2_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for MD4
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_md4_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for MD5
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_md5_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for RIPEMD-128
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_ripemd_128_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for RIPEMD-160
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_ripemd_160_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for RIPEMD-256
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_ripemd_256_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for RIPEMD-320
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_ripemd_320_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for SHA0
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_sha0_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for SHA1
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_sha1_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for SHA-224 (SHA2)
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_sha_224_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for SHA-256 (SHA2)
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_sha_256_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for SHA-384 (SHA2)
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_sha_384_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for SHA-512 (SHA2)
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_sha_512_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for SHA-512/224 (SHA2)
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_sha_512_224_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for SHA-512/256 (SHA2)
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @return 0 on success, -1 on failure
*
* Failure isn't actually possible, so this function always return 0
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_sha_512_256_hasher(struct libhashsum_hasher *this);
/**
* Create an initialised state for SHA2
* hashing and return hash functions and details
*
* @param this The output parameter for the functions, details, and state
* @param algobits 32 for a 32-bit algorithm, 64 for a 64-bit algorithm
* @param hashbits Hash output size in bits
* @return 0 on success, -1 on failure
*
* @throws EINVAL `algobits` is invalid (neither 32 nor 64)
* @throws EINVAL `hashbits` is invalid (neither 224, 256, 384, nor 512)
* @throws EINVAL The combination of `algobits` and `hashbits` is invalid
* (`hashbits` is 384 or 512 but `algobits` is 32)
*
* @since 1.0
*/
LIBHASHSUM_1_NONNULL_
int libhashsum_init_sha2_hasher(struct libhashsum_hasher *this, unsigned algobits, size_t hashbits);
#endif