Index: include/libroar/hash.h
===================================================================
--- include/libroar/hash.h	(revision 4453)
+++ include/libroar/hash.h	(revision 4670)
@@ -76,4 +76,15 @@
 #define ROAR_HT_ISBN13      ROAR_HT_GTIN13
 
+struct roar_hash_cmds {
+ int algo;
+ ssize_t statelen;
+ ssize_t blocksize;
+ int (*init)(void * state);
+ int (*uninit)(void * state);
+ int (*digest)(void * state, void * digest, size_t * len);
+ int (*proc_block)(void * state, const void * block);
+ int (*proc)(void * state, const void * data, size_t len);
+};
+
 const char * roar_ht2str (const int    ht);
 int          roar_str2ht (const char * ht);
@@ -85,4 +96,9 @@
 struct roar_hash_state;
 
+struct roar_hash_state * roar_hash_new(int algo);
+int roar_hash_free(struct roar_hash_state * state);
+int roar_hash_digest(struct roar_hash_state * state, void * digest, size_t * len);
+int roar_hash_proc(struct roar_hash_state * state, const void * data, size_t len);
+
 int roar_hash_buffer(void * digest, const void * data, size_t datalen, int algo);
 int roar_hash_salted_buffer(void * digest, const void * data, size_t datalen, int algo, const void * salt, size_t saltlen);
Index: libroar/hash.c
===================================================================
--- libroar/hash.c	(revision 4549)
+++ libroar/hash.c	(revision 4670)
@@ -39,4 +39,9 @@
 #include <gcrypt.h>
 #endif
+
+struct roar_hash_state {
+ struct roar_hash_cmds * cmds;
+ void * state;
+};
 
 static const struct hashes {
@@ -86,4 +91,24 @@
 };
 
+static struct roar_hash_cmds _libroar_hash_cmds[] = {
+ {ROAR_HT_TIGER, sizeof(struct roar_hash_tiger), 512,
+  (int (*)(void *))roar_hash_tiger_init, (int (*)(void *))roar_hash_tiger_uninit,
+  (int (*)(void *, void *, size_t *))roar_hash_tiger_get_digest,
+  (int (*)(void *, const void *))roar_hash_tiger_proc_block,
+  (int (*)(void *, const void *, size_t))roar_hash_tiger_proc
+ },
+ {-1, -1, -1, NULL, NULL, NULL, NULL, NULL}
+};
+
+static struct roar_hash_cmds * roar_ht2cmds(const int ht) {
+ size_t i;
+
+ for(i = 0; _libroar_hash_cmds[i].algo != -1; i++)
+  if ( _libroar_hash_cmds[i].algo == ht )
+   return &(_libroar_hash_cmds[i]);
+
+ return NULL;
+}
+
 static inline int roar_ht2gcrypt_tested (const int ht) {
 #ifdef ROAR_HAVE_LIBGCRYPT
@@ -141,4 +166,7 @@
  roar_crypto_init();
 
+ if ( roar_ht2cmds(ht) != NULL )
+  return 1;
+
 #ifdef ROAR_HAVE_LIBGCRYPT
  if ( roar_ht2gcrypt_tested(ht) == -1 )
@@ -149,4 +177,75 @@
  return 0;
 #endif
+}
+
+struct roar_hash_state * roar_hash_new(int algo) {
+ struct roar_hash_cmds  * cmds = roar_ht2cmds(algo);
+ struct roar_hash_state * self;
+
+ if ( cmds == NULL )
+  return NULL;
+
+ self = roar_mm_malloc(sizeof(struct roar_hash_state));
+
+ if ( self == NULL )
+  return NULL;
+
+ memset(self, 0, sizeof(struct roar_hash_state));
+
+ self->cmds = cmds;
+
+ self->state = roar_mm_malloc(cmds->statelen);
+
+ if ( self->state == NULL ) {
+  roar_mm_free(self);
+  return NULL;
+ }
+
+ memset(self->state, 0, cmds->statelen);
+
+ if ( cmds->init != NULL ) {
+  if ( cmds->init(self->state) == -1 ) {
+   roar_mm_free(self->state);
+   roar_mm_free(self);
+   return NULL;
+  }
+ }
+
+ return self;
+}
+
+int roar_hash_free(struct roar_hash_state * state) {
+ int ret = 0;
+
+ if ( state == NULL )
+  return -1;
+
+ if ( state->cmds->uninit != NULL )
+  ret = state->cmds->uninit(state->state);
+
+ roar_mm_free(state->state);
+ roar_mm_free(state);
+
+ return ret;
+}
+
+int roar_hash_digest(struct roar_hash_state * state, void * digest, size_t * len) {
+ if ( state == NULL )
+  return -1;
+
+ if ( state->cmds->digest == NULL )
+  return -1;
+
+ return state->cmds->digest(state->state, digest, len);
+}
+
+int roar_hash_proc(struct roar_hash_state * state, const void * data, size_t len) {
+ if ( state == NULL )
+  return -1;
+
+ if ( state->cmds->proc == NULL )
+  return -1;
+
+ return state->cmds->proc(state->state, data, len);
 }
 
@@ -189,6 +288,31 @@
 
 int roar_hash_salted_buffer(void * digest, const void * data, size_t datalen, int algo, const void * salt, size_t saltlen) {
+ struct roar_hash_state * state;
+ size_t len;
+ int ret;
+
  if ( digest == NULL || data == NULL )
   return -1;
+
+ len = roar_ht_digestlen(algo);
+ if ( len == -1 )
+  return -1;
+
+ if ( (state = roar_hash_new(algo)) != NULL ) {
+  if ( roar_hash_proc(state, data, datalen) == -1 )
+   ret = -1;
+
+  if ( saltlen != 0 )
+   if ( roar_hash_proc(state, salt, saltlen) == -1 )
+    ret = -1;
+
+  if ( roar_hash_digest(state, digest, &len) == -1 )
+   ret = -1;
+
+  if ( roar_hash_free(state) == -1 )
+   ret = -1;
+
+  return ret;
+ }
 
 #ifdef ROAR_HAVE_LIBGCRYPT
