/
Cryptography.c
210 lines (171 loc) · 4.8 KB
/
Cryptography.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/** vim: set noet ci pi sts=0 sw=4 ts=4
* @file Cryptography.c
* @brief Cryptographic functions (hashes, random numbers)
*/
#include "Cryptography.h"
#include "Time.h"
#ifdef WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <wincrypt.h>
#elif defined POSIX
#include <openssl/evp.h>
#endif
#include <math.h>
#include <stdlib.h>
static boolean seeded = false;
/**
* Hash a block of memory using SHA512.
*
* @param source [in] pointer to block of memory to hash
* @param length [in] number of bytes from source to hash.
* @returns pointer to digest (64 bytes in length)
*
* @warning You need to free the returned memory yourself
*/
uint8* SAL_Cryptography_SHA512(uint8* source, uint32 length) {
#ifdef WINDOWS
HCRYPTPROV provider = 0;
HCRYPTHASH hasher = 0;
DWORD hashLength;
uint8* hash;
CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
CryptCreateHash(provider, CALG_SHA_512, 0, 0, &hasher);
CryptHashData(hasher, source, length, 0);
hash = AllocateArray(uint8, 64);
CryptGetHashParam(hasher, HP_HASHVAL, hash, &hashLength, 0);
CryptDestroyHash(hasher);
CryptReleaseContext(provider, 0);
return hash;
#elif defined POSIX
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
uint8 *hash = AllocateArray(uint8, EVP_MD_size(EVP_sha512()));
EVP_DigestInit_ex(ctx, EVP_sha512(), NULL);
EVP_DigestUpdate(ctx, (void*)source, length);
EVP_DigestFinal_ex(ctx, (unsigned char*)hash, NULL);
return hash;
#endif
}
/**
* Hash a block of memory using SHA-1
*
* @param source [in] pointer to block of memory to hash
* @param length [in] number of bytes from source to hash.
* @returns pointer to digest (20 bytes in length)
*
* @warning You need to free the returned memory yourself
*/
uint8* SAL_Cryptography_SHA1(uint8* source, uint32 length) {
#ifdef WINDOWS
HCRYPTPROV provider = 0;
HCRYPTHASH hasher = 0;
DWORD hashLength;
uint8* hash;
CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
CryptCreateHash(provider, CALG_SHA1, 0, 0, &hasher);
CryptHashData(hasher, source, length, 0);
hash = AllocateArray(uint8, 20);
CryptGetHashParam(hasher, HP_HASHVAL, hash, &hashLength, 0);
CryptDestroyHash(hasher);
CryptReleaseContext(provider, 0);
return hash;
#elif defined POSIX
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
uint8 *hash = AllocateArray(uint8, EVP_MD_size(EVP_sha1()));
EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
EVP_DigestUpdate(ctx, (void*)source, length);
EVP_DigestFinal_ex(ctx, (unsigned char*)hash, NULL);
return hash;
#endif
}
/**
* Generate pseudorandom bytes.
*
* @param count [in] number of bytes to generate
* @returns pointer to @a count bytes.
*
* @warning You need to free the returned memory yourself
*/
uint8* SAL_Cryptography_RandomBytes(uint64 count) {
uint8* bytes = NULL;
uint8 i;
if (count > 0) {
bytes = AllocateArray(uint8, count); // Integer division rounds towards 0, count % 4 is the remainder
if (!seeded) {
srand( (uint32)SAL_Time_Now() );
seeded = true;
}
for (; count > 3; count -= 4)
*((uint32*)bytes + count - 4) = rand();
for (i = 0; i < count; i++)
*(bytes + i) = (uint8)rand();
}
return bytes;
}
/**
* Generate a 8 byte pseudorandom value.
*
* @param floor [in] Lower bound of random value
* @param ceiling [in] Upper bound of random value
* @returns 8 pseudorandom bytes
*/
uint64 SAL_Cryptography_RandomUInt64(uint64 floor, uint64 ceiling) {
uint64 result;
if (!seeded) {
srand( (uint32)SAL_Time_Now() );
seeded = true;
}
result = (uint32)rand();
result <<= 32;
result += (uint32)rand();
result = result % (ceiling - floor) + floor;
return result;
}
/**
* Generate a 4 byte pseudorandom value.
*
* @param floor [in] Lower bound of random value
* @param ceiling [in] Upper bound of random value
* @returns 4 pseudorandom bytes
*/
uint32 SAL_Cryptography_RandomUInt32(uint32 floor, uint32 ceiling) {
uint32 result;
if (!seeded) {
srand( (uint32)SAL_Time_Now() );
seeded = true;
}
result = rand() % (ceiling - floor) + floor;
return (uint32)result;
}
/**
* Generate a 2 byte pseudorandom value.
*
* @param floor [in] Lower bound of random value
* @param ceiling [in] Upper bound of random value
* @returns 2 pseudorandom bytes
*/
uint16 SAL_Cryptography_RandomUInt16(uint16 floor, uint16 ceiling) {
uint16 result;
if (!seeded) {
srand( (uint32)SAL_Time_Now() );
seeded = true;
}
result = rand() % (ceiling - floor) + floor;
return (uint16)result;
}
/**
* Generate a 1 byte pseudorandom value.
*
* @param floor [in] Lower bound of random value
* @param ceiling [in] Upper bound of random value
* @returns 1 pseudorandom byte
*/
uint8 SAL_Cryptography_RandomUInt8(uint8 floor, uint8 ceiling) {
uint8 result;
if (!seeded) {
srand( (uint32)SAL_Time_Now() );
seeded = true;
}
result = rand() % (ceiling - floor) + floor;
return (uint8)result;
}