postgresql/contrib/pgcrypto/crypt-md5.c
Amit Kapila 7e735035f2 Make the order of the header file includes consistent in contrib modules.
The basic rule we follow here is to always first include 'postgres.h' or
'postgres_fe.h' whichever is applicable, then system header includes and
then Postgres header includes.  In this, we also follow that all the
Postgres header includes are in order based on their ASCII value.  We
generally follow these rules, but the code has deviated in many places.
This commit makes it consistent just for contrib modules.  The later
commits will enforce similar rules in other parts of code.

Author: Vignesh C
Reviewed-by: Amit Kapila
Discussion: https://postgr.es/m/CALDaNm2Sznv8RR6Ex-iJO6xAdsxgWhCoETkaYX=+9DW3q0QCfA@mail.gmail.com
2019-10-24 08:05:34 +05:30

164 lines
3.6 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 char *magic = "$1$"; /* This string is magic for this algorithm.
* Having it this way, we can get better later
* on */
static char *p;
static 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;
/* */
err = px_find_digest("md5", &ctx);
if (err)
return NULL;
err = px_find_digest("md5", &ctx1);
/* 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, (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;
}