Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * md5_common.c
4 : : * Routines shared between all MD5 implementations used for encrypted
5 : : * passwords.
6 : : *
7 : : * Sverre H. Huseby <sverrehu@online.no>
8 : : *
9 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
10 : : * Portions Copyright (c) 1994, Regents of the University of California
11 : : *
12 : : * IDENTIFICATION
13 : : * src/common/md5_common.c
14 : : *
15 : : *-------------------------------------------------------------------------
16 : : */
17 : :
18 : : #ifndef FRONTEND
19 : : #include "postgres.h"
20 : : #else
21 : : #include "postgres_fe.h"
22 : : #endif
23 : :
24 : : #include "common/cryptohash.h"
25 : : #include "common/md5.h"
26 : :
27 : : static void
1221 michael@paquier.xyz 28 :CBC 4551 : bytesToHex(uint8 b[16], char *s)
29 : : {
30 : : static const char *hex = "0123456789abcdef";
31 : : int q,
32 : : w;
33 : :
34 [ + + ]: 77367 : for (q = 0, w = 0; q < 16; q++)
35 : : {
36 : 72816 : s[w++] = hex[(b[q] >> 4) & 0x0F];
37 : 72816 : s[w++] = hex[b[q] & 0x0F];
38 : : }
39 : 4551 : s[w] = '\0';
40 : 4551 : }
41 : :
42 : : /*
43 : : * pg_md5_hash
44 : : *
45 : : * Calculates the MD5 sum of the bytes in a buffer.
46 : : *
47 : : * SYNOPSIS #include "md5.h"
48 : : * bool pg_md5_hash(const void *buff, size_t len, char *hexsum,
49 : : * const char **errstr)
50 : : *
51 : : * INPUT buff the buffer containing the bytes that you want
52 : : * the MD5 sum of.
53 : : * len number of bytes in the buffer.
54 : : *
55 : : * OUTPUT hexsum the MD5 sum as a '\0'-terminated string of
56 : : * hexadecimal digits. an MD5 sum is 16 bytes long.
57 : : * each byte is represented by two hexadecimal
58 : : * characters. you thus need to provide an array
59 : : * of 33 characters, including the trailing '\0'.
60 : : *
61 : : * errstr filled with a constant-string error message
62 : : * on failure return; NULL on success.
63 : : *
64 : : * RETURNS false on failure (out of memory for internal buffers
65 : : * or MD5 computation failure) or true on success.
66 : : *
67 : : * STANDARDS MD5 is described in RFC 1321.
68 : : *
69 : : * AUTHOR Sverre H. Huseby <sverrehu@online.no>
70 : : *
71 : : */
72 : :
73 : : bool
824 74 : 4551 : pg_md5_hash(const void *buff, size_t len, char *hexsum, const char **errstr)
75 : : {
76 : : uint8 sum[MD5_DIGEST_LENGTH];
77 : : pg_cryptohash_ctx *ctx;
78 : :
727 tgl@sss.pgh.pa.us 79 : 4551 : *errstr = NULL;
1221 michael@paquier.xyz 80 : 4551 : ctx = pg_cryptohash_create(PG_MD5);
81 [ - + ]: 4551 : if (ctx == NULL)
82 : : {
727 tgl@sss.pgh.pa.us 83 :UBC 0 : *errstr = pg_cryptohash_error(NULL); /* returns OOM */
1221 michael@paquier.xyz 84 : 0 : return false;
85 : : }
86 : :
1221 michael@paquier.xyz 87 [ + - + - ]:CBC 9102 : if (pg_cryptohash_init(ctx) < 0 ||
88 [ - + ]: 9102 : pg_cryptohash_update(ctx, buff, len) < 0 ||
1154 89 : 4551 : pg_cryptohash_final(ctx, sum, sizeof(sum)) < 0)
90 : : {
824 michael@paquier.xyz 91 :UBC 0 : *errstr = pg_cryptohash_error(ctx);
1221 92 : 0 : pg_cryptohash_free(ctx);
93 : 0 : return false;
94 : : }
95 : :
1221 michael@paquier.xyz 96 :CBC 4551 : bytesToHex(sum, hexsum);
97 : 4551 : pg_cryptohash_free(ctx);
98 : 4551 : return true;
99 : : }
100 : :
101 : : /*
102 : : * pg_md5_binary
103 : : *
104 : : * As above, except that the MD5 digest is returned as a binary string
105 : : * (of size MD5_DIGEST_LENGTH) rather than being converted to ASCII hex.
106 : : */
107 : : bool
824 michael@paquier.xyz 108 :UBC 0 : pg_md5_binary(const void *buff, size_t len, void *outbuf, const char **errstr)
109 : : {
110 : : pg_cryptohash_ctx *ctx;
111 : :
112 : 0 : *errstr = NULL;
1221 113 : 0 : ctx = pg_cryptohash_create(PG_MD5);
114 [ # # ]: 0 : if (ctx == NULL)
115 : : {
824 116 : 0 : *errstr = pg_cryptohash_error(NULL); /* returns OOM */
1221 117 : 0 : return false;
118 : : }
119 : :
120 [ # # # # ]: 0 : if (pg_cryptohash_init(ctx) < 0 ||
121 [ # # ]: 0 : pg_cryptohash_update(ctx, buff, len) < 0 ||
1154 122 : 0 : pg_cryptohash_final(ctx, outbuf, MD5_DIGEST_LENGTH) < 0)
123 : : {
824 124 : 0 : *errstr = pg_cryptohash_error(ctx);
1221 125 : 0 : pg_cryptohash_free(ctx);
126 : 0 : return false;
127 : : }
128 : :
129 : 0 : pg_cryptohash_free(ctx);
130 : 0 : return true;
131 : : }
132 : :
133 : :
134 : : /*
135 : : * Computes MD5 checksum of "passwd" (a null-terminated string) followed
136 : : * by "salt" (which need not be null-terminated).
137 : : *
138 : : * Output format is "md5" followed by a 32-hex-digit MD5 checksum.
139 : : * Hence, the output buffer "buf" must be at least 36 bytes long.
140 : : *
141 : : * Returns true if okay, false on error with *errstr providing some
142 : : * error context.
143 : : */
144 : : bool
1221 michael@paquier.xyz 145 :CBC 27 : pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len,
146 : : char *buf, const char **errstr)
147 : : {
148 : 27 : size_t passwd_len = strlen(passwd);
149 : :
150 : : /* +1 here is just to avoid risk of unportable malloc(0) */
151 : 27 : char *crypt_buf = malloc(passwd_len + salt_len + 1);
152 : : bool ret;
153 : :
154 [ - + ]: 27 : if (!crypt_buf)
155 : : {
824 michael@paquier.xyz 156 :UBC 0 : *errstr = _("out of memory");
1221 157 : 0 : return false;
158 : : }
159 : :
160 : : /*
161 : : * Place salt at the end because it may be known by users trying to crack
162 : : * the MD5 output.
163 : : */
1221 michael@paquier.xyz 164 :CBC 27 : memcpy(crypt_buf, passwd, passwd_len);
165 : 27 : memcpy(crypt_buf + passwd_len, salt, salt_len);
166 : :
167 : 27 : strcpy(buf, "md5");
824 168 : 27 : ret = pg_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3, errstr);
169 : :
1221 170 : 27 : free(crypt_buf);
171 : :
172 : 27 : return ret;
173 : : }
|