1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-18 13:44:19 +03:00
postgres/contrib/pgcrypto/crypt-md5.c
Daniel Gustafsson affd38e55a pgcrypto: Remove static storage class from variables
Variables p, sp and ep were labeled with static storage class
but are all assigned before use so they cannot carry any data
across calls.  Fix by removing the static label.

Also while in there, make the magic variable const as it will
never change.

Author: Japin Li <japinli@hotmail.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/ME0P300MB0445096B67ACE8CE25772F00B6F72@ME0P300MB0445.AUSP300.PROD.OUTLOOK.COM
2025-02-06 15:13:40 +01:00

170 lines
3.8 KiB
C

/*
* File imported from FreeBSD, original by Poul-Henning Kamp.
*
* $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.5 1999/12/17 20:21:45 peter Exp $
*
* contrib/pgcrypto/crypt-md5.c
*/
#include "postgres.h"
#include "px-crypt.h"
#include "px.h"
#define MD5_SIZE 16
static const char _crypt_a64[] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static void
_crypt_to64(char *s, unsigned long v, int n)
{
while (--n >= 0)
{
*s++ = _crypt_a64[v & 0x3f];
v >>= 6;
}
}
/*
* UNIX password
*/
char *
px_crypt_md5(const char *pw, const char *salt, char *passwd, unsigned dstlen)
{
static const char *magic = "$1$"; /* This string is magic for this
* algorithm. Having it this way, we
* can get better later on */
char *p;
const char *sp,
*ep;
unsigned char final[MD5_SIZE];
int sl,
pl,
i;
PX_MD *ctx,
*ctx1;
int err;
unsigned long l;
if (!passwd || dstlen < 120)
return NULL;
/* Refine the Salt first */
sp = salt;
/* If it starts with the magic string, then skip that */
if (strncmp(sp, magic, strlen(magic)) == 0)
sp += strlen(magic);
/* It stops at the first '$', max 8 chars */
for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
continue;
/* get the length of the true salt */
sl = ep - sp;
/* we need two PX_MD objects */
err = px_find_digest("md5", &ctx);
if (err)
return NULL;
err = px_find_digest("md5", &ctx1);
if (err)
{
/* this path is possible under low-memory circumstances */
px_md_free(ctx);
return NULL;
}
/* The password first, since that is what is most unknown */
px_md_update(ctx, (const uint8 *) pw, strlen(pw));
/* Then our magic string */
px_md_update(ctx, (const uint8 *) magic, strlen(magic));
/* Then the raw salt */
px_md_update(ctx, (const uint8 *) sp, sl);
/* Then just as many characters of the MD5(pw,salt,pw) */
px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
px_md_update(ctx1, (const uint8 *) sp, sl);
px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
px_md_finish(ctx1, final);
for (pl = strlen(pw); pl > 0; pl -= MD5_SIZE)
px_md_update(ctx, final, pl > MD5_SIZE ? MD5_SIZE : pl);
/* Don't leave anything around in vm they could use. */
px_memset(final, 0, sizeof final);
/* Then something really weird... */
for (i = strlen(pw); i; i >>= 1)
if (i & 1)
px_md_update(ctx, final, 1);
else
px_md_update(ctx, (const uint8 *) pw, 1);
/* Now make the output string */
strcpy(passwd, magic);
strncat(passwd, sp, sl);
strcat(passwd, "$");
px_md_finish(ctx, final);
/*
* and now, just to make sure things don't run too fast On a 60 Mhz
* Pentium this takes 34 msec, so you would need 30 seconds to build a
* 1000 entry dictionary...
*/
for (i = 0; i < 1000; i++)
{
px_md_reset(ctx1);
if (i & 1)
px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
else
px_md_update(ctx1, final, MD5_SIZE);
if (i % 3)
px_md_update(ctx1, (const uint8 *) sp, sl);
if (i % 7)
px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
if (i & 1)
px_md_update(ctx1, final, MD5_SIZE);
else
px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
px_md_finish(ctx1, final);
}
p = passwd + strlen(passwd);
l = (final[0] << 16) | (final[6] << 8) | final[12];
_crypt_to64(p, l, 4);
p += 4;
l = (final[1] << 16) | (final[7] << 8) | final[13];
_crypt_to64(p, l, 4);
p += 4;
l = (final[2] << 16) | (final[8] << 8) | final[14];
_crypt_to64(p, l, 4);
p += 4;
l = (final[3] << 16) | (final[9] << 8) | final[15];
_crypt_to64(p, l, 4);
p += 4;
l = (final[4] << 16) | (final[10] << 8) | final[5];
_crypt_to64(p, l, 4);
p += 4;
l = final[11];
_crypt_to64(p, l, 2);
p += 2;
*p = '\0';
/* Don't leave anything around in vm they could use. */
px_memset(final, 0, sizeof final);
px_md_free(ctx1);
px_md_free(ctx);
return passwd;
}