LCOV - code coverage report
Current view: top level - src/common - md5_common.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 55.3 % 47 26
Test Date: 2026-03-12 06:14:44 Functions: 75.0 % 4 3
Legend: Lines:     hit not hit

            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-2026, 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           71 : bytesToHex(uint8 b[16], char *s)
      29              : {
      30              :     static const char *hex = "0123456789abcdef";
      31              :     int         q,
      32              :                 w;
      33              : 
      34         1207 :     for (q = 0, w = 0; q < 16; q++)
      35              :     {
      36         1136 :         s[w++] = hex[(b[q] >> 4) & 0x0F];
      37         1136 :         s[w++] = hex[b[q] & 0x0F];
      38              :     }
      39           71 :     s[w] = '\0';
      40           71 : }
      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           71 : 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              : 
      79           71 :     *errstr = NULL;
      80           71 :     ctx = pg_cryptohash_create(PG_MD5);
      81           71 :     if (ctx == NULL)
      82              :     {
      83            0 :         *errstr = pg_cryptohash_error(NULL);    /* returns OOM */
      84            0 :         return false;
      85              :     }
      86              : 
      87          142 :     if (pg_cryptohash_init(ctx) < 0 ||
      88          142 :         pg_cryptohash_update(ctx, buff, len) < 0 ||
      89           71 :         pg_cryptohash_final(ctx, sum, sizeof(sum)) < 0)
      90              :     {
      91            0 :         *errstr = pg_cryptohash_error(ctx);
      92            0 :         pg_cryptohash_free(ctx);
      93            0 :         return false;
      94              :     }
      95              : 
      96           71 :     bytesToHex(sum, hexsum);
      97           71 :     pg_cryptohash_free(ctx);
      98           71 :     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            0 : pg_md5_binary(const void *buff, size_t len, uint8 *outbuf, const char **errstr)
     109              : {
     110              :     pg_cryptohash_ctx *ctx;
     111              : 
     112            0 :     *errstr = NULL;
     113            0 :     ctx = pg_cryptohash_create(PG_MD5);
     114            0 :     if (ctx == NULL)
     115              :     {
     116            0 :         *errstr = pg_cryptohash_error(NULL);    /* returns OOM */
     117            0 :         return false;
     118              :     }
     119              : 
     120            0 :     if (pg_cryptohash_init(ctx) < 0 ||
     121            0 :         pg_cryptohash_update(ctx, buff, len) < 0 ||
     122            0 :         pg_cryptohash_final(ctx, outbuf, MD5_DIGEST_LENGTH) < 0)
     123              :     {
     124            0 :         *errstr = pg_cryptohash_error(ctx);
     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
     145           27 : pg_md5_encrypt(const char *passwd, const uint8 *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              :     {
     156            0 :         *errstr = _("out of memory");
     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              :      */
     164           27 :     memcpy(crypt_buf, passwd, passwd_len);
     165           27 :     memcpy(crypt_buf + passwd_len, salt, salt_len);
     166              : 
     167           27 :     strcpy(buf, "md5");
     168           27 :     ret = pg_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3, errstr);
     169              : 
     170           27 :     free(crypt_buf);
     171              : 
     172           27 :     return ret;
     173              : }
        

Generated by: LCOV version 2.0-1