1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9#include "monetdb_config.h"
10#include "mcrypt.h"
11#include <string.h>
12
13#ifndef HAVE_EMBEDDED
14/* only provide digest functions if not embedded */
15#ifdef HAVE_OPENSSL
16#include <openssl/md5.h>
17#include <openssl/sha.h>
18#include <openssl/ripemd.h>
19#else
20#ifdef HAVE_COMMONCRYPTO
21#define COMMON_DIGEST_FOR_OPENSSL
22#include <CommonCrypto/CommonDigest.h>
23#endif
24#endif
25#endif
26
27/**
28 * Returns a comma separated list of supported hash algorithms suitable
29 * for final hashing by the client. This list contains the smaller
30 * (in char size) hashes.
31 * The returned string is malloced and should be freed.
32 */
33const char *
34mcrypt_getHashAlgorithms(void)
35{
36 /* Currently, four "hashes" are available, RIPEMD160, SHA-2, SHA-1
37 * and MD5. Previous versions supported UNIX crypt and plain text
38 * login, but those were removed when SHA-1 became mandatory for
39 * hashing the plain password in wire protocol version 9.
40 * Better/stronger/faster algorithms can be added in the future upon
41 * desire.
42 */
43 static const char *algorithms =
44 "PROT10"
45#ifdef HAVE_RIPEMD160_UPDATE
46 ",RIPEMD160"
47#endif
48#ifdef HAVE_SHA256_UPDATE
49 ",SHA256"
50#endif
51#ifdef HAVE_SHA1_UPDATE
52 ",SHA1"
53#endif
54#ifdef HAVE_MD5_UPDATE
55 ",MD5"
56#endif
57#ifdef HAVE_LIBSNAPPY
58 ",COMPRESSION_SNAPPY"
59#endif
60#ifdef HAVE_LIBLZ4
61 ",COMPRESSION_LZ4"
62#endif
63 ;
64 return algorithms;
65}
66
67/**
68 * Returns a malloced string representing the hex representation of
69 * the MD5 hash of the given string.
70 */
71char *
72mcrypt_MD5Sum(const char *string, size_t len)
73{
74#if !defined(HAVE_EMBEDDED) && defined(HAVE_MD5_UPDATE)
75 MD5_CTX c;
76 unsigned char md[MD5_DIGEST_LENGTH];
77 char *ret;
78
79 static_assert(MD5_DIGEST_LENGTH == 16, "MD5_DIGEST_LENGTH should be 16");
80 MD5_Init(&c);
81 MD5_Update(&c, string, len);
82 MD5_Final(md, &c);
83
84 ret = malloc(MD5_DIGEST_LENGTH * 2 + 1);
85 if(ret) {
86 snprintf(ret, MD5_DIGEST_LENGTH * 2 + 1,
87 "%02x%02x%02x%02x%02x%02x%02x%02x"
88 "%02x%02x%02x%02x%02x%02x%02x%02x",
89 md[0], md[1], md[2], md[3],
90 md[4], md[5], md[6], md[7],
91 md[8], md[9], md[10], md[11],
92 md[12], md[13], md[14], md[15]);
93 }
94
95 return ret;
96#else
97 (void) string;
98 (void) len;
99 fprintf(stderr, "No MD5 digest function available.\n");
100 return NULL;
101#endif
102}
103
104/**
105 * Returns a malloced string representing the hex representation of
106 * the SHA-1 hash of the given string.
107 */
108char *
109mcrypt_SHA1Sum(const char *string, size_t len)
110{
111#if !defined(HAVE_EMBEDDED) && defined(HAVE_SHA1_UPDATE)
112 SHA_CTX c;
113 unsigned char md[SHA_DIGEST_LENGTH];
114 char *ret;
115
116 static_assert(SHA_DIGEST_LENGTH == 20, "SHA_DIGEST_LENGTH should be 20");
117 SHA1_Init(&c);
118 SHA1_Update(&c, string, len);
119 SHA1_Final(md, &c);
120
121 ret = malloc(SHA_DIGEST_LENGTH * 2 + 1);
122 if(ret) {
123 snprintf(ret, SHA_DIGEST_LENGTH * 2 + 1,
124 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
125 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
126 md[0], md[1], md[2], md[3], md[4],
127 md[5], md[6], md[7], md[8], md[9],
128 md[10], md[11], md[12], md[13], md[14],
129 md[15], md[16], md[17], md[18], md[19]);
130 }
131
132 return ret;
133#else
134 (void) string;
135 (void) len;
136 fprintf(stderr, "No SHA1 digest function available.\n");
137 return NULL;
138#endif
139}
140
141/**
142 * Returns a malloced string representing the hex representation of
143 * the SHA-224 hash of the given string.
144 */
145char *
146mcrypt_SHA224Sum(const char *string, size_t len)
147{
148#if !defined(HAVE_EMBEDDED) && defined(HAVE_SHA224_UPDATE)
149 SHA256_CTX c;
150 unsigned char md[SHA224_DIGEST_LENGTH];
151 char *ret;
152
153 static_assert(SHA224_DIGEST_LENGTH == 28, "SHA224_DIGEST_LENGTH should be 28");
154 SHA224_Init(&c);
155 SHA224_Update(&c, string, len);
156 SHA224_Final(md, &c);
157
158 ret = malloc(SHA224_DIGEST_LENGTH * 2 + 1);
159 if(ret) {
160 snprintf(ret, SHA224_DIGEST_LENGTH * 2 + 1,
161 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
162 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
163 "%02x%02x%02x%02x%02x%02x%02x%02x",
164 md[0], md[1], md[2], md[3], md[4],
165 md[5], md[6], md[7], md[8], md[9],
166 md[10], md[11], md[12], md[13], md[14],
167 md[15], md[16], md[17], md[18], md[19],
168 md[20], md[21], md[22], md[23], md[24],
169 md[25], md[26], md[27]);
170 }
171
172 return ret;
173#else
174 (void) string;
175 (void) len;
176 fprintf(stderr, "No SHA224 digest function available.\n");
177 return NULL;
178#endif
179}
180
181/**
182 * Returns a malloced string representing the hex representation of
183 * the SHA-256 hash of the given string.
184 */
185char *
186mcrypt_SHA256Sum(const char *string, size_t len)
187{
188#if !defined(HAVE_EMBEDDED) && defined(HAVE_SHA256_UPDATE)
189 SHA256_CTX c;
190 unsigned char md[SHA256_DIGEST_LENGTH];
191 char *ret;
192
193 static_assert(SHA256_DIGEST_LENGTH == 32, "SHA256_DIGEST_LENGTH should be 32");
194 SHA256_Init(&c);
195 SHA256_Update(&c, string, len);
196 SHA256_Final(md, &c);
197
198 ret = malloc(SHA256_DIGEST_LENGTH * 2 + 1);
199 if(ret) {
200 snprintf(ret, SHA256_DIGEST_LENGTH * 2 + 1,
201 "%02x%02x%02x%02x%02x%02x%02x%02x"
202 "%02x%02x%02x%02x%02x%02x%02x%02x"
203 "%02x%02x%02x%02x%02x%02x%02x%02x"
204 "%02x%02x%02x%02x%02x%02x%02x%02x",
205 md[0], md[1], md[2], md[3], md[4],
206 md[5], md[6], md[7], md[8], md[9],
207 md[10], md[11], md[12], md[13], md[14],
208 md[15], md[16], md[17], md[18], md[19],
209 md[20], md[21], md[22], md[23], md[24],
210 md[25], md[26], md[27], md[28], md[29],
211 md[30], md[31]);
212 }
213
214 return ret;
215#else
216 (void) string;
217 (void) len;
218 fprintf(stderr, "No SHA256 digest function available.\n");
219 return NULL;
220#endif
221}
222
223/**
224 * Returns a malloced string representing the hex representation of
225 * the SHA-384 hash of the given string.
226 */
227char *
228mcrypt_SHA384Sum(const char *string, size_t len)
229{
230#if !defined(HAVE_EMBEDDED) && defined(HAVE_SHA384_UPDATE)
231 SHA512_CTX c;
232 unsigned char md[SHA384_DIGEST_LENGTH];
233 char *ret;
234
235 static_assert(SHA384_DIGEST_LENGTH == 48, "SHA384_DIGEST_LENGTH should be 48");
236 SHA384_Init(&c);
237 SHA384_Update(&c, string, len);
238 SHA384_Final(md, &c);
239
240 ret = malloc(SHA384_DIGEST_LENGTH * 2 + 1);
241 if(ret) {
242 snprintf(ret, SHA384_DIGEST_LENGTH * 2 + 1,
243 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
244 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
245 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
246 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
247 "%02x%02x%02x%02x%02x%02x%02x%02x",
248 md[0], md[1], md[2], md[3], md[4],
249 md[5], md[6], md[7], md[8], md[9],
250 md[10], md[11], md[12], md[13], md[14],
251 md[15], md[16], md[17], md[18], md[19],
252 md[20], md[21], md[22], md[23], md[24],
253 md[25], md[26], md[27], md[28], md[29],
254 md[30], md[31], md[32], md[33], md[34],
255 md[35], md[36], md[37], md[38], md[39],
256 md[40], md[41], md[42], md[43], md[44],
257 md[45], md[46], md[47]);
258 }
259
260 return ret;
261#else
262 (void) string;
263 (void) len;
264 fprintf(stderr, "No SHA384 digest function available.\n");
265 return NULL;
266#endif
267}
268
269/**
270 * Returns a malloced string representing the hex representation of
271 * the SHA-512 hash of the given string.
272 */
273char *
274mcrypt_SHA512Sum(const char *string, size_t len)
275{
276#if !defined(HAVE_EMBEDDED) && defined(HAVE_SHA512_UPDATE)
277 SHA512_CTX c;
278 unsigned char md[SHA512_DIGEST_LENGTH];
279 char *ret;
280
281 static_assert(SHA512_DIGEST_LENGTH == 64, "SHA512_DIGEST_LENGTH should be 64");
282 SHA512_Init(&c);
283 SHA512_Update(&c, string, len);
284 SHA512_Final(md, &c);
285
286 ret = malloc(SHA512_DIGEST_LENGTH * 2 + 1);
287 if(ret) {
288 snprintf(ret, SHA512_DIGEST_LENGTH * 2 + 1,
289 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
290 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
291 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
292 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
293 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
294 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
295 "%02x%02x%02x%02x",
296 md[0], md[1], md[2], md[3], md[4],
297 md[5], md[6], md[7], md[8], md[9],
298 md[10], md[11], md[12], md[13], md[14],
299 md[15], md[16], md[17], md[18], md[19],
300 md[20], md[21], md[22], md[23], md[24],
301 md[25], md[26], md[27], md[28], md[29],
302 md[30], md[31], md[32], md[33], md[34],
303 md[35], md[36], md[37], md[38], md[39],
304 md[40], md[41], md[42], md[43], md[44],
305 md[45], md[46], md[47], md[48], md[49],
306 md[50], md[51], md[52], md[53], md[54],
307 md[55], md[56], md[57], md[58], md[59],
308 md[60], md[61], md[62], md[63]);
309 }
310
311 return ret;
312#else
313 (void) string;
314 (void) len;
315 fprintf(stderr, "No SHA512 digest function available.\n");
316 return NULL;
317#endif
318}
319
320/**
321 * Returns a malloced string representing the hex representation of
322 * the RIPEMD-160 hash of the given string.
323 */
324char *
325mcrypt_RIPEMD160Sum(const char *string, size_t len)
326{
327#if !defined(HAVE_EMBEDDED) && defined(HAVE_RIPEMD160_UPDATE)
328 RIPEMD160_CTX c;
329 unsigned char md[RIPEMD160_DIGEST_LENGTH];
330 char *ret;
331
332 static_assert(RIPEMD160_DIGEST_LENGTH == 20, "RIPEMD160_DIGEST_LENGTH should be 20");
333 RIPEMD160_Init(&c);
334 RIPEMD160_Update(&c, string, len);
335 RIPEMD160_Final(md, &c);
336
337 ret = malloc(RIPEMD160_DIGEST_LENGTH * 2 + 1);
338 if(ret) {
339 snprintf(ret, RIPEMD160_DIGEST_LENGTH * 2 + 1,
340 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
341 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
342 md[0], md[1], md[2], md[3], md[4],
343 md[5], md[6], md[7], md[8], md[9],
344 md[10], md[11], md[12], md[13], md[14],
345 md[15], md[16], md[17], md[18], md[19]);
346 }
347
348 return ret;
349#else
350 (void) string;
351 (void) len;
352 fprintf(stderr, "No RIPEMD160 digest function available.\n");
353 return NULL;
354#endif
355}
356
357/**
358 * Returns a malloced string representing the hex representation of
359 * the by the backend used hash of the given string.
360 */
361#define concat(x,y,z) x##y##z
362#define mcryptsum(h) concat(mcrypt_, h, Sum)
363char *
364mcrypt_BackendSum(const char *string, size_t len)
365{
366#if !defined(HAVE_EMBEDDED) && (defined(HAVE_OPENSSL) || defined(HAVE_COMMONCRYPTO))
367 return mcryptsum(MONETDB5_PASSWDHASH_TOKEN)(string, len);
368#else
369 (void) string;
370 (void) len;
371 fprintf(stderr, "No digest function available.\n");
372 return NULL;
373#endif
374}
375
376/**
377 * Returns the hash for the given password, challenge and algorithm.
378 * The hash calculated using the given algorithm over the password
379 * concatenated with the challenge. The returned string is allocated
380 * using malloc, and hence should be freed with free by the
381 * caller. Returns NULL when the given algorithm is not supported.
382 */
383char *
384mcrypt_hashPassword(
385 const char *algo,
386 const char *password,
387 const char *challenge)
388{
389#if !defined(HAVE_EMBEDDED) && (defined(HAVE_OPENSSL) || defined(HAVE_COMMONCRYPTO))
390 unsigned char md[64]; /* should be SHA512_DIGEST_LENGTH */
391 char ret[sizeof(md) * 2 + 1];
392 int len;
393
394 /* make valgrind happy, prevent us from printing garbage afterwards */
395 memset(md, 0, sizeof(md));
396
397#ifdef HAVE_RIPEMD160_UPDATE
398 if (strcmp(algo, "RIPEMD160") == 0) {
399 RIPEMD160_CTX c;
400
401 RIPEMD160_Init(&c);
402 RIPEMD160_Update(&c, password, strlen(password));
403 RIPEMD160_Update(&c, challenge, strlen(challenge));
404 RIPEMD160_Final(md, &c);
405
406 len = 40;
407 } else
408#endif
409#ifdef HAVE_SHA512_UPDATE
410 if (strcmp(algo, "SHA512") == 0) {
411 SHA512_CTX c;
412
413 SHA512_Init(&c);
414 SHA512_Update(&c, password, strlen(password));
415 SHA512_Update(&c, challenge, strlen(challenge));
416 SHA512_Final(md, &c);
417
418 len = 128;
419 } else
420#endif
421#ifdef HAVE_SHA384_UPDATE
422 if (strcmp(algo, "SHA384") == 0) {
423 SHA512_CTX c;
424
425 SHA384_Init(&c);
426 SHA384_Update(&c, password, strlen(password));
427 SHA384_Update(&c, challenge, strlen(challenge));
428 SHA384_Final(md, &c);
429
430 len = 96;
431 } else
432#endif
433#ifdef HAVE_SHA256_UPDATE
434 if (strcmp(algo, "SHA256") == 0) {
435 SHA256_CTX c;
436
437 SHA256_Init(&c);
438 SHA256_Update(&c, password, strlen(password));
439 SHA256_Update(&c, challenge, strlen(challenge));
440 SHA256_Final(md, &c);
441
442 len = 64;
443 } else
444#endif
445#ifdef HAVE_SHA224_UPDATE
446 if (strcmp(algo, "SHA224") == 0) {
447 SHA256_CTX c;
448
449 SHA224_Init(&c);
450 SHA224_Update(&c, password, strlen(password));
451 SHA224_Update(&c, challenge, strlen(challenge));
452 SHA224_Final(md, &c);
453
454 len = 56;
455 } else
456#endif
457#ifdef HAVE_SHA1_UPDATE
458 if (strcmp(algo, "SHA1") == 0) {
459 SHA_CTX c;
460
461 SHA1_Init(&c);
462 SHA1_Update(&c, password, strlen(password));
463 SHA1_Update(&c, challenge, strlen(challenge));
464 SHA1_Final(md, &c);
465
466 len = 40;
467 } else
468#endif
469#ifdef HAVE_MD5_UPDATE
470 if (strcmp(algo, "MD5") == 0) {
471 MD5_CTX c;
472
473 MD5_Init(&c);
474 MD5_Update(&c, password, strlen(password));
475 MD5_Update(&c, challenge, strlen(challenge));
476 MD5_Final(md, &c);
477
478 len = 32;
479 } else
480#endif
481#endif
482 {
483 (void) algo;
484 (void) password;
485 (void) challenge;
486 fprintf(stderr, "MonetDB was built without OpenSSL, but what you are trying to do requires it.\n");
487 return NULL;
488 }
489
490#if !defined(HAVE_EMBEDDED) && (defined(HAVE_OPENSSL) || defined(HAVE_COMMONCRYPTO))
491 snprintf(ret, sizeof(ret),
492 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
493 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
494 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
495 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
496 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
497 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
498 "%02x%02x%02x%02x",
499 md[0], md[1], md[2], md[3],
500 md[4], md[5], md[6], md[7],
501 md[8], md[9], md[10], md[11],
502 md[12], md[13], md[14], md[15],
503 md[16], md[17], md[18], md[19],
504 md[20], md[21], md[22], md[23],
505 md[24], md[25], md[26], md[27],
506 md[28], md[29], md[30], md[31],
507 md[32], md[33], md[34], md[35],
508 md[36], md[37], md[38], md[39],
509 md[40], md[41], md[42], md[43],
510 md[44], md[45], md[46], md[47],
511 md[48], md[49], md[50], md[51],
512 md[52], md[53], md[54], md[55],
513 md[56], md[57], md[58], md[59],
514 md[60], md[61], md[62], md[63]);
515 ret[len] = '\0';
516
517 return strdup(ret);
518#endif
519}
520