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: 2023-11-29 06:10:49 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-2023, 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         142 : bytesToHex(uint8 b[16], char *s)
      29             : {
      30             :     static const char *hex = "0123456789abcdef";
      31             :     int         q,
      32             :                 w;
      33             : 
      34        2414 :     for (q = 0, w = 0; q < 16; q++)
      35             :     {
      36        2272 :         s[w++] = hex[(b[q] >> 4) & 0x0F];
      37        2272 :         s[w++] = hex[b[q] & 0x0F];
      38             :     }
      39         142 :     s[w] = '\0';
      40         142 : }
      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             :  *                int pg_md5_hash(const void *buff, size_t len, char *hexsum)
      49             :  *
      50             :  *  INPUT         buff    the buffer containing the bytes that you want
      51             :  *                        the MD5 sum of.
      52             :  *                len     number of bytes in the buffer.
      53             :  *
      54             :  *  OUTPUT        hexsum  the MD5 sum as a '\0'-terminated string of
      55             :  *                        hexadecimal digits.  an MD5 sum is 16 bytes long.
      56             :  *                        each byte is represented by two hexadecimal
      57             :  *                        characters.  you thus need to provide an array
      58             :  *                        of 33 characters, including the trailing '\0'.
      59             :  *
      60             :  *                errstr  filled with a constant-string error message
      61             :  *                        on failure return; NULL on success.
      62             :  *
      63             :  *  RETURNS       false on failure (out of memory for internal buffers
      64             :  *                or MD5 computation failure) or true on success.
      65             :  *
      66             :  *  STANDARDS     MD5 is described in RFC 1321.
      67             :  *
      68             :  *  AUTHOR        Sverre H. Huseby <sverrehu@online.no>
      69             :  *
      70             :  */
      71             : 
      72             : bool
      73         142 : pg_md5_hash(const void *buff, size_t len, char *hexsum, const char **errstr)
      74             : {
      75             :     uint8       sum[MD5_DIGEST_LENGTH];
      76             :     pg_cryptohash_ctx *ctx;
      77             : 
      78         142 :     *errstr = NULL;
      79         142 :     ctx = pg_cryptohash_create(PG_MD5);
      80         142 :     if (ctx == NULL)
      81             :     {
      82           0 :         *errstr = pg_cryptohash_error(NULL);    /* returns OOM */
      83           0 :         return false;
      84             :     }
      85             : 
      86         284 :     if (pg_cryptohash_init(ctx) < 0 ||
      87         284 :         pg_cryptohash_update(ctx, buff, len) < 0 ||
      88         142 :         pg_cryptohash_final(ctx, sum, sizeof(sum)) < 0)
      89             :     {
      90           0 :         *errstr = pg_cryptohash_error(ctx);
      91           0 :         pg_cryptohash_free(ctx);
      92           0 :         return false;
      93             :     }
      94             : 
      95         142 :     bytesToHex(sum, hexsum);
      96         142 :     pg_cryptohash_free(ctx);
      97         142 :     return true;
      98             : }
      99             : 
     100             : /*
     101             :  * pg_md5_binary
     102             :  *
     103             :  * As above, except that the MD5 digest is returned as a binary string
     104             :  * (of size MD5_DIGEST_LENGTH) rather than being converted to ASCII hex.
     105             :  */
     106             : bool
     107           0 : pg_md5_binary(const void *buff, size_t len, void *outbuf, const char **errstr)
     108             : {
     109             :     pg_cryptohash_ctx *ctx;
     110             : 
     111           0 :     *errstr = NULL;
     112           0 :     ctx = pg_cryptohash_create(PG_MD5);
     113           0 :     if (ctx == NULL)
     114             :     {
     115           0 :         *errstr = pg_cryptohash_error(NULL);    /* returns OOM */
     116           0 :         return false;
     117             :     }
     118             : 
     119           0 :     if (pg_cryptohash_init(ctx) < 0 ||
     120           0 :         pg_cryptohash_update(ctx, buff, len) < 0 ||
     121           0 :         pg_cryptohash_final(ctx, outbuf, MD5_DIGEST_LENGTH) < 0)
     122             :     {
     123           0 :         *errstr = pg_cryptohash_error(ctx);
     124           0 :         pg_cryptohash_free(ctx);
     125           0 :         return false;
     126             :     }
     127             : 
     128           0 :     pg_cryptohash_free(ctx);
     129           0 :     return true;
     130             : }
     131             : 
     132             : 
     133             : /*
     134             :  * Computes MD5 checksum of "passwd" (a null-terminated string) followed
     135             :  * by "salt" (which need not be null-terminated).
     136             :  *
     137             :  * Output format is "md5" followed by a 32-hex-digit MD5 checksum.
     138             :  * Hence, the output buffer "buf" must be at least 36 bytes long.
     139             :  *
     140             :  * Returns true if okay, false on error with *errstr providing some
     141             :  * error context.
     142             :  */
     143             : bool
     144          54 : pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len,
     145             :                char *buf, const char **errstr)
     146             : {
     147          54 :     size_t      passwd_len = strlen(passwd);
     148             : 
     149             :     /* +1 here is just to avoid risk of unportable malloc(0) */
     150          54 :     char       *crypt_buf = malloc(passwd_len + salt_len + 1);
     151             :     bool        ret;
     152             : 
     153          54 :     if (!crypt_buf)
     154             :     {
     155           0 :         *errstr = _("out of memory");
     156           0 :         return false;
     157             :     }
     158             : 
     159             :     /*
     160             :      * Place salt at the end because it may be known by users trying to crack
     161             :      * the MD5 output.
     162             :      */
     163          54 :     memcpy(crypt_buf, passwd, passwd_len);
     164          54 :     memcpy(crypt_buf + passwd_len, salt, salt_len);
     165             : 
     166          54 :     strcpy(buf, "md5");
     167          54 :     ret = pg_md5_hash(crypt_buf, passwd_len + salt_len, buf + 3, errstr);
     168             : 
     169          54 :     free(crypt_buf);
     170             : 
     171          54 :     return ret;
     172             : }

Generated by: LCOV version 1.14