-
Notifications
You must be signed in to change notification settings - Fork 2
/
hash.c
126 lines (115 loc) · 5.03 KB
/
hash.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* C to sqlite DB interface (for logins)
* with hashing mechanisms using gcrypt
* written by oMeN23 in 2011-2012
* If you think this is useful, use it!
* copyleft, open and free!
* file: hash.c (hashing)
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <stdbool.h>
#include <gcrypt.h>
#include <errno.h>
#include "login.h"
/* this function calculates a hex-string which represents
* the hash of the user's password or any value
* arg1 = the value
* arg2 = the destination (caller has to allocate dynamic or automatic memory and free it eventually after) - min. (gcry_md_get_algo_dlen(algo)*4) for hex notation
* arg3 = the algorithm (see libgcrypt docs)
* arg4 = some flags (see below)
* 0 = none,
* GCRY_MGCRY_MD_FLAG_SECURE = 1, Allocate all buffers in "secure" memory.
* GCRY_MD_FLAG_HMAC = 2, Make an HMAC out of this algorithm.
*/
void hash_func(const char* value, char* dest, int algo, unsigned int flags) {
gcrypt_init();
gcry_md_hd_t Crypto_handle; /* crypto context handle */
gcry_error_t Crypto_error = 0;
/* determine pw length + 1 (macro handles it), max USERBUF , not overflowable MACRO USED */
size_t text_length = stringlength(value) + 1; /* terminating null, shouldnt make a diff, sys dependend, this is correct */
/* check if the library is working as it should .. */
Crypto_error = gcry_md_open(&Crypto_handle, algo, flags);
if (Crypto_error || Crypto_handle == NULL)
fprintf(stderr, "Failure: %s\t/\t%s\n",
gcry_strsource(Crypto_error),
gcry_strerror(Crypto_error)
);
Crypto_error = gcry_md_enable(Crypto_handle, algo);
if (Crypto_error)
fprintf(stderr, "Failure: %s\t/\t%s\n",
gcry_strsource(Crypto_error),
gcry_strerror(Crypto_error)
);
if (Crypto_error || !gcry_md_is_enabled(Crypto_handle, algo)) {
fprintf(stderr, "Failure: %s\t/\t%s\n",
gcry_strsource(Crypto_error),
gcry_strerror(Crypto_error)
);
abort();
}
/* if algo works start the hashing */
if (gcry_md_test_algo(algo) == GPG_ERR_NO_ERROR) {
/* pass pw into hash function bytewise (unsigned char) */
for (int x = 0 ; x < text_length; x++) {
gcry_md_putc(Crypto_handle, (unsigned char)value[x]);
}
/* finalize calculation */
gcry_md_final(Crypto_handle);
/* allocate (secure) heap memory for the hash */
unsigned char* byte_result = gcry_malloc_secure(gcry_md_get_algo_dlen(algo)*4); // NOTE: we actually ran out of space here once
/* helpers to make them human readable and comparable */
unsigned char* helper = gcry_malloc_secure(16); /* actually only need 1 char */
if ( !gcry_is_secure(helper)|| !gcry_is_secure(byte_result)) {
fprintf(stderr, "Could not allocate in secure memory!\n");
abort();
}
// NOTE: 10.6.2012 fixed a strcpy issue - where digests with a value of zer0 [00] in the middle would be
// cut off - using memcpy instead
/* copy hash into a RAW string */
memcpy(byte_result, gcry_md_read(Crypto_handle, algo), gcry_md_get_algo_dlen(algo)*2); /* read in the raw byte string - size times two for hex notation */
if (dest == NULL) { /* the caller has to allocate the destination memory */
fprintf(stderr, "\t Hashing-Function: destination memory adress is not valid!\n\
The caller of this function is responsible for allocating a destination buffer that is large enough\n\
for holding the digest value\n");
abort();
}
memset((void*)dest, 0, sizeof(dest)); /* clear memory where hash is to be written */
/* format the raw string to hex notation and
* pass it piece by piece into our char *dest
* and concatenate */
for (int i = 0; i < gcry_md_get_algo_dlen(algo); i++) {
sprintf((char*)helper, "%02x", (unsigned char)byte_result[i]);
stringconcat(dest, (const char*)helper);
}
dest[ strlen( dest ) ] = '\0';
/* generally clean up after ourselves ... */
gcry_md_close(Crypto_handle); /* releases all security relevant information */
gcry_free(Crypto_handle);
gcry_free(byte_result);
gcry_free(helper);
Crypto_error = 0;
Crypto_handle = NULL;
byte_result = NULL;
helper = NULL;
} else /* if the hash mechanism isnt working abort */
abort();
}
void gcrypt_init() {
static bool initialized = false;
if (gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P) || initialized)
return;
if (!gcry_check_version(GCRYPT_VERSION)) {
fprintf(stderr, "fatal error: libgcrypt version mismatch\n");
abort();
}
/* this is the actual library initialization
* with a sec mem starting pool of 64k */
gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN),
gcry_control(GCRYCTL_INIT_SECMEM, 16384*4, 0),
gcry_control(GCRYCTL_RESUME_SECMEM_WARN),
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
initialized = true;
}