#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <errno.h>
#include <md5.h>
#include <crypt.h>
static const char crypt_alg_magic[] = "$1$";
#define SALT_LEN 8
static uchar_t itoa64[] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static void
to64(char *s, uint64_t v, int n)
{
while (--n >= 0) {
*s++ = itoa64[v & 0x3f];
v >>= 6;
}
}
char *
crypt_genhash_impl(char *ctbuffer,
size_t ctbufflen,
const char *plaintext,
const char *switchsalt,
const char **params)
{
char *p;
int sl, l, pl, i;
uchar_t *sp, *ep;
uchar_t final[16];
MD5_CTX ctx, ctx1;
const int crypt_alg_magic_len = strlen(crypt_alg_magic);
sp = (uchar_t *)switchsalt;
if (strncmp((char *)sp, crypt_alg_magic, crypt_alg_magic_len) == 0) {
sp += crypt_alg_magic_len;
}
for (ep = sp; *ep && *ep != '$' && ep < (sp + SALT_LEN); ep++)
continue;
sl = ep - sp;
MD5Init(&ctx);
MD5Update(&ctx, (uchar_t *)plaintext, strlen(plaintext));
MD5Update(&ctx, (uchar_t *)crypt_alg_magic, strlen(crypt_alg_magic));
MD5Update(&ctx, (uchar_t *)sp, sl);
MD5Init(&ctx1);
MD5Update(&ctx1, (uchar_t *)plaintext, strlen(plaintext));
MD5Update(&ctx1, sp, sl);
MD5Update(&ctx1, (uchar_t *)plaintext, strlen(plaintext));
MD5Final(final, &ctx1);
for (pl = strlen(plaintext); pl > 0; pl -= 16)
MD5Update(&ctx, final, pl > 16 ? 16 : pl);
(void) memset(final, 0, sizeof (final));
for (i = strlen(plaintext); i; i >>= 1) {
if (i & 1) {
MD5Update(&ctx, final, 1);
} else {
MD5Update(&ctx, (uchar_t *)plaintext, 1);
}
}
(void) strlcpy(ctbuffer, crypt_alg_magic, ctbufflen);
(void) strncat(ctbuffer, (const char *)sp, sl);
(void) strlcat(ctbuffer, "$", ctbufflen);
MD5Final(final, &ctx);
for (i = 0; i < 1000; i++) {
MD5Init(&ctx1);
if (i & 1)
MD5Update(&ctx1, (uchar_t *)plaintext,
strlen(plaintext));
else
MD5Update(&ctx1, final, 16);
if (i % 3)
MD5Update(&ctx1, sp, sl);
if (i % 7)
MD5Update(&ctx1, (uchar_t *)plaintext,
strlen(plaintext));
if (i & 1)
MD5Update(&ctx1, final, 16);
else
MD5Update(&ctx1, (uchar_t *)plaintext,
strlen(plaintext));
MD5Final(final, &ctx1);
}
p = ctbuffer + strlen(ctbuffer);
l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
l = final[11]; to64(p, l, 2); p += 2;
*p = '\0';
(void) memset(final, 0, sizeof (final));
return (ctbuffer);
}
char *
crypt_gensalt_impl(char *gsbuffer,
size_t gsbufflen,
const char *oldsalt,
const struct passwd *userinfo,
const char **params)
{
int fd;
int err;
ssize_t got;
uint64_t rndval;
if ((fd = open("/dev/urandom", O_RDONLY)) == -1) {
return (NULL);
}
(void) strlcpy(gsbuffer, crypt_alg_magic, gsbufflen);
got = read(fd, &rndval, sizeof (rndval));
if (got < sizeof (rndval)) {
err = errno;
(void) close(fd);
errno = err;
return (NULL);
}
to64(&gsbuffer[strlen(crypt_alg_magic)], rndval, sizeof (rndval));
(void) close(fd);
return (gsbuffer);
}