PostgreSQL Source Code  git master
md5_common.c
Go to the documentation of this file.
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
28 bytesToHex(uint8 b[16], char *s)
29 {
30  static const char *hex = "0123456789abcdef";
31  int q,
32  w;
33 
34  for (q = 0, w = 0; q < 16; q++)
35  {
36  s[w++] = hex[(b[q] >> 4) & 0x0F];
37  s[w++] = hex[b[q] & 0x0F];
38  }
39  s[w] = '\0';
40 }
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
74 pg_md5_hash(const void *buff, size_t len, char *hexsum, const char **errstr)
75 {
77  pg_cryptohash_ctx *ctx;
78 
79  *errstr = NULL;
81  if (ctx == NULL)
82  {
83  *errstr = pg_cryptohash_error(NULL); /* returns OOM */
84  return false;
85  }
86 
87  if (pg_cryptohash_init(ctx) < 0 ||
88  pg_cryptohash_update(ctx, buff, len) < 0 ||
89  pg_cryptohash_final(ctx, sum, sizeof(sum)) < 0)
90  {
91  *errstr = pg_cryptohash_error(ctx);
92  pg_cryptohash_free(ctx);
93  return false;
94  }
95 
96  bytesToHex(sum, hexsum);
97  pg_cryptohash_free(ctx);
98  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
108 pg_md5_binary(const void *buff, size_t len, void *outbuf, const char **errstr)
109 {
110  pg_cryptohash_ctx *ctx;
111 
112  *errstr = NULL;
114  if (ctx == NULL)
115  {
116  *errstr = pg_cryptohash_error(NULL); /* returns OOM */
117  return false;
118  }
119 
120  if (pg_cryptohash_init(ctx) < 0 ||
121  pg_cryptohash_update(ctx, buff, len) < 0 ||
122  pg_cryptohash_final(ctx, outbuf, MD5_DIGEST_LENGTH) < 0)
123  {
124  *errstr = pg_cryptohash_error(ctx);
125  pg_cryptohash_free(ctx);
126  return false;
127  }
128 
129  pg_cryptohash_free(ctx);
130  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
145 pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len,
146  char *buf, const char **errstr)
147 {
148  size_t passwd_len = strlen(passwd);
149 
150  /* +1 here is just to avoid risk of unportable malloc(0) */
151  char *crypt_buf = malloc(passwd_len + salt_len + 1);
152  bool ret;
153 
154  if (!crypt_buf)
155  {
156  *errstr = _("out of memory");
157  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  */
164  memcpy(crypt_buf, passwd, passwd_len);
165  memcpy(crypt_buf + passwd_len, salt, salt_len);
166 
167  strcpy(buf, "md5");
168  ret = pg_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3, errstr);
169 
170  free(crypt_buf);
171 
172  return ret;
173 }
unsigned char uint8
Definition: c.h:504
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
Definition: cryptohash.c:136
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:100
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:238
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
Definition: cryptohash.c:74
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
Definition: cryptohash.c:172
const char * pg_cryptohash_error(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:254
@ PG_MD5
Definition: cryptohash.h:21
#define _(x)
Definition: elog.c:90
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
int b
Definition: isn.c:70
#define MD5_DIGEST_LENGTH
Definition: md5.h:20
bool pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, char *buf, const char **errstr)
Definition: md5_common.c:145
bool pg_md5_hash(const void *buff, size_t len, char *hexsum, const char **errstr)
Definition: md5_common.c:74
bool pg_md5_binary(const void *buff, size_t len, void *outbuf, const char **errstr)
Definition: md5_common.c:108
static void bytesToHex(uint8 b[16], char *s)
Definition: md5_common.c:28
const void size_t len
static char * buf
Definition: pg_test_fsync.c:73