LCOV - code coverage report
Current view: top level - src/common - md5_common.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 26 47 55.3 %
Date: 2024-05-01 21:11:23 Functions: 3 4 75.0 %
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-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        9102 : bytesToHex(uint8 b[16], char *s)
      29             : {
      30             :     static const char *hex = "0123456789abcdef";
      31             :     int         q,
      32             :                 w;
      33             : 
      34      154734 :     for (q = 0, w = 0; q < 16; q++)
      35             :     {
      36      145632 :         s[w++] = hex[(b[q] >> 4) & 0x0F];
      37      145632 :         s[w++] = hex[b[q] & 0x0F];
      38             :     }
      39        9102 :     s[w] = '\0';
      40        9102 : }
      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        9102 : 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        9102 :     *errstr = NULL;
      80        9102 :     ctx = pg_cryptohash_create(PG_MD5);
      81        9102 :     if (ctx == NULL)
      82             :     {
      83           0 :         *errstr = pg_cryptohash_error(NULL);    /* returns OOM */
      84           0 :         return false;
      85             :     }
      86             : 
      87       18204 :     if (pg_cryptohash_init(ctx) < 0 ||
      88       18204 :         pg_cryptohash_update(ctx, buff, len) < 0 ||
      89        9102 :         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        9102 :     bytesToHex(sum, hexsum);
      97        9102 :     pg_cryptohash_free(ctx);
      98        9102 :     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, void *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          54 : pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len,
     146             :                char *buf, const char **errstr)
     147             : {
     148          54 :     size_t      passwd_len = strlen(passwd);
     149             : 
     150             :     /* +1 here is just to avoid risk of unportable malloc(0) */
     151          54 :     char       *crypt_buf = malloc(passwd_len + salt_len + 1);
     152             :     bool        ret;
     153             : 
     154          54 :     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          54 :     memcpy(crypt_buf, passwd, passwd_len);
     165          54 :     memcpy(crypt_buf + passwd_len, salt, salt_len);
     166             : 
     167          54 :     strcpy(buf, "md5");
     168          54 :     ret = pg_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3, errstr);
     169             : 
     170          54 :     free(crypt_buf);
     171             : 
     172          54 :     return ret;
     173             : }

Generated by: LCOV version 1.14