mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
1abf76e82c
Few cleanups and couple of new things: - add SHA2 algorithm to older OpenSSL - add BIGNUM math to have public-key cryptography work on non-OpenSSL build. - gen_random_bytes() function The status of SHA2 algoritms and public-key encryption can now be changed to 'always available.' That makes pgcrypto functionally complete and unless there will be new editions of AES, SHA2 or OpenPGP standards, there is no major changes planned.
169 lines
4.0 KiB
C
169 lines
4.0 KiB
C
/*
|
|
* ----------------------------------------------------------------------------
|
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
|
* <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
|
|
* can do whatever you want with this stuff. If we meet some day, and you think
|
|
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.5 1999/12/17 20:21:45 peter Exp $
|
|
*
|
|
* $PostgreSQL: pgsql/contrib/pgcrypto/crypt-md5.c,v 1.7 2006/07/13 04:15:24 neilc Exp $
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "px.h"
|
|
#include "px-crypt.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 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)))
|
|
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, (uint8 *) pw, strlen(pw));
|
|
|
|
/* Then our magic string */
|
|
px_md_update(ctx, (uint8 *) magic, strlen(magic));
|
|
|
|
/* Then the raw salt */
|
|
px_md_update(ctx, (uint8 *) sp, sl);
|
|
|
|
/* Then just as many characters of the MD5(pw,salt,pw) */
|
|
px_md_update(ctx1, (uint8 *) pw, strlen(pw));
|
|
px_md_update(ctx1, (uint8 *) sp, sl);
|
|
px_md_update(ctx1, (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. */
|
|
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, (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, (uint8 *) pw, strlen(pw));
|
|
else
|
|
px_md_update(ctx1, final, MD5_SIZE);
|
|
|
|
if (i % 3)
|
|
px_md_update(ctx1, (uint8 *) sp, sl);
|
|
|
|
if (i % 7)
|
|
px_md_update(ctx1, (uint8 *) pw, strlen(pw));
|
|
|
|
if (i & 1)
|
|
px_md_update(ctx1, final, MD5_SIZE);
|
|
else
|
|
px_md_update(ctx1, (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. */
|
|
memset(final, 0, sizeof final);
|
|
|
|
px_md_free(ctx1);
|
|
px_md_free(ctx);
|
|
|
|
return passwd;
|
|
}
|