Make libcrypt thread-safe. Add crypt_r(3).
glibc has a pretty nice function called crypt_r(3), which is nothing more than crypt(3), but thread-safe. It accomplishes this by introducing a 'struct crypt_data' structure that contains a buffer that is large enough to hold the resulting string. Let's go ahead and also add this function. It would be a shame if a useful function like this wouldn't be usable in multithreaded apps. Refactor crypt.c and all of the backends to no longer declare static arrays, but write their output in a provided buffer. There is no need to do any buffer length computation here, as we'll just need to ensure that 'struct crypt_data' is large enough, which it is. _PASSWORD_LEN is defined to 128 bytes, but in this case I'm picking 256, as this is going to be part of the actual ABI. Differential Revision: https://reviews.freebsd.org/D7306
This commit is contained in:
parent
3a77833e87
commit
5f521d7ba7
@ -484,11 +484,18 @@ pid_t vfork(void) __returns_twice;
|
||||
|
||||
#if __BSD_VISIBLE
|
||||
struct timeval; /* select(2) */
|
||||
|
||||
struct crypt_data {
|
||||
int initialized; /* For compatibility with glibc. */
|
||||
char __buf[256]; /* Buffer returned by crypt_r(). */
|
||||
};
|
||||
|
||||
int acct(const char *);
|
||||
int async_daemon(void);
|
||||
int check_utility_compat(const char *);
|
||||
const char *
|
||||
crypt_get_format(void);
|
||||
char *crypt_r(const char *, const char *, struct crypt_data *);
|
||||
int crypt_set_format(const char *);
|
||||
int des_cipher(const char *, char *, long, int);
|
||||
int des_setkey(const char *key);
|
||||
|
@ -17,7 +17,8 @@ SRCS= crypt.c misc.c \
|
||||
crypt-sha256.c sha256c.c \
|
||||
crypt-sha512.c sha512c.c
|
||||
MAN= crypt.3
|
||||
MLINKS= crypt.3 crypt_get_format.3 crypt.3 crypt_set_format.3
|
||||
MLINKS= crypt.3 crypt_get_format.3 crypt.3 crypt_r.3 \
|
||||
crypt.3 crypt_set_format.3
|
||||
CFLAGS+= -I${.CURDIR}/../libmd -I${.CURDIR}/../libutil \
|
||||
-I${.CURDIR}/../../sys/crypto/sha2
|
||||
|
||||
|
@ -41,31 +41,27 @@ __FBSDID("$FreeBSD$");
|
||||
* UNIX password
|
||||
*/
|
||||
|
||||
char *
|
||||
crypt_md5(const char *pw, const char *salt)
|
||||
int
|
||||
crypt_md5(const char *pw, const char *salt, char *buffer)
|
||||
{
|
||||
MD5_CTX ctx,ctx1;
|
||||
unsigned long l;
|
||||
int sl, pl;
|
||||
u_int i;
|
||||
u_char final[MD5_SIZE];
|
||||
static const char *sp, *ep;
|
||||
static char passwd[120], *p;
|
||||
const char *ep;
|
||||
static const char *magic = "$1$";
|
||||
|
||||
/* 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);
|
||||
/* If the salt starts with the magic string, skip that. */
|
||||
if (!strncmp(salt, magic, strlen(magic)))
|
||||
salt += strlen(magic);
|
||||
|
||||
/* It stops at the first '$', max 8 chars */
|
||||
for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
|
||||
for (ep = salt; *ep && *ep != '$' && ep < salt + 8; ep++)
|
||||
continue;
|
||||
|
||||
/* get the length of the true salt */
|
||||
sl = ep - sp;
|
||||
sl = ep - salt;
|
||||
|
||||
MD5Init(&ctx);
|
||||
|
||||
@ -76,12 +72,12 @@ crypt_md5(const char *pw, const char *salt)
|
||||
MD5Update(&ctx, (const u_char *)magic, strlen(magic));
|
||||
|
||||
/* Then the raw salt */
|
||||
MD5Update(&ctx, (const u_char *)sp, (u_int)sl);
|
||||
MD5Update(&ctx, (const u_char *)salt, (u_int)sl);
|
||||
|
||||
/* Then just as many characters of the MD5(pw,salt,pw) */
|
||||
MD5Init(&ctx1);
|
||||
MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
|
||||
MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
|
||||
MD5Update(&ctx1, (const u_char *)salt, (u_int)sl);
|
||||
MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
|
||||
MD5Final(final, &ctx1);
|
||||
for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE)
|
||||
@ -99,9 +95,9 @@ crypt_md5(const char *pw, const char *salt)
|
||||
MD5Update(&ctx, (const u_char *)pw, 1);
|
||||
|
||||
/* Now make the output string */
|
||||
strcpy(passwd, magic);
|
||||
strncat(passwd, sp, (u_int)sl);
|
||||
strcat(passwd, "$");
|
||||
buffer = stpcpy(buffer, magic);
|
||||
buffer = stpncpy(buffer, salt, (u_int)sl);
|
||||
*buffer++ = '$';
|
||||
|
||||
MD5Final(final, &ctx);
|
||||
|
||||
@ -118,7 +114,7 @@ crypt_md5(const char *pw, const char *salt)
|
||||
MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
|
||||
|
||||
if(i % 3)
|
||||
MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
|
||||
MD5Update(&ctx1, (const u_char *)salt, (u_int)sl);
|
||||
|
||||
if(i % 7)
|
||||
MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
|
||||
@ -130,24 +126,22 @@ crypt_md5(const char *pw, const char *salt)
|
||||
MD5Final(final, &ctx1);
|
||||
}
|
||||
|
||||
p = passwd + strlen(passwd);
|
||||
|
||||
l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
|
||||
_crypt_to64(p, l, 4); p += 4;
|
||||
_crypt_to64(buffer, l, 4); buffer += 4;
|
||||
l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
|
||||
_crypt_to64(p, l, 4); p += 4;
|
||||
_crypt_to64(buffer, l, 4); buffer += 4;
|
||||
l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
|
||||
_crypt_to64(p, l, 4); p += 4;
|
||||
_crypt_to64(buffer, l, 4); buffer += 4;
|
||||
l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
|
||||
_crypt_to64(p, l, 4); p += 4;
|
||||
_crypt_to64(buffer, l, 4); buffer += 4;
|
||||
l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
|
||||
_crypt_to64(p, l, 4); p += 4;
|
||||
_crypt_to64(buffer, l, 4); buffer += 4;
|
||||
l = final[11];
|
||||
_crypt_to64(p, l, 2); p += 2;
|
||||
*p = '\0';
|
||||
_crypt_to64(buffer, l, 2); buffer += 2;
|
||||
*buffer = '\0';
|
||||
|
||||
/* Don't leave anything around in vm they could use. */
|
||||
memset(final, 0, sizeof(final));
|
||||
|
||||
return (passwd);
|
||||
return (0);
|
||||
}
|
||||
|
@ -46,16 +46,14 @@ __FBSDID("$FreeBSD$");
|
||||
*/
|
||||
|
||||
/* ARGSUSED */
|
||||
char *
|
||||
crypt_nthash(const char *pw, const char *salt __unused)
|
||||
int
|
||||
crypt_nthash(const char *pw, const char *salt __unused, char *buffer)
|
||||
{
|
||||
size_t unipwLen;
|
||||
int i, j;
|
||||
static char hexconvtab[] = "0123456789abcdef";
|
||||
int i;
|
||||
static const char hexconvtab[] = "0123456789abcdef";
|
||||
static const char *magic = "$3$";
|
||||
static char passwd[120];
|
||||
u_int16_t unipw[128];
|
||||
char final[MD4_SIZE*2 + 1];
|
||||
u_char hash[MD4_SIZE];
|
||||
const char *s;
|
||||
MD4_CTX ctx;
|
||||
@ -70,19 +68,14 @@ crypt_nthash(const char *pw, const char *salt __unused)
|
||||
MD4Init(&ctx);
|
||||
MD4Update(&ctx, (u_char *)unipw, unipwLen*sizeof(u_int16_t));
|
||||
MD4Final(hash, &ctx);
|
||||
|
||||
for (i = j = 0; i < MD4_SIZE; i++) {
|
||||
final[j++] = hexconvtab[hash[i] >> 4];
|
||||
final[j++] = hexconvtab[hash[i] & 15];
|
||||
|
||||
buffer = stpcpy(buffer, magic);
|
||||
*buffer++ = '$';
|
||||
for (i = 0; i < MD4_SIZE; i++) {
|
||||
*buffer++ = hexconvtab[hash[i] >> 4];
|
||||
*buffer++ = hexconvtab[hash[i] & 15];
|
||||
}
|
||||
final[j] = '\0';
|
||||
*buffer = '\0';
|
||||
|
||||
strcpy(passwd, magic);
|
||||
strcat(passwd, "$");
|
||||
strncat(passwd, final, MD4_SIZE*2);
|
||||
|
||||
/* Don't leave anything around in vm they could use. */
|
||||
memset(final, 0, sizeof(final));
|
||||
|
||||
return (passwd);
|
||||
return (0);
|
||||
}
|
||||
|
@ -59,11 +59,10 @@ static const char sha256_rounds_prefix[] = "rounds=";
|
||||
/* Maximum number of rounds. */
|
||||
#define ROUNDS_MAX 999999999
|
||||
|
||||
static char *
|
||||
crypt_sha256_r(const char *key, const char *salt, char *buffer, int buflen)
|
||||
int
|
||||
crypt_sha256(const char *key, const char *salt, char *buffer)
|
||||
{
|
||||
u_long srounds;
|
||||
int n;
|
||||
uint8_t alt_result[32], temp_result[32];
|
||||
SHA256_CTX ctx, alt_ctx;
|
||||
size_t salt_len, key_len, cnt, rounds;
|
||||
@ -210,42 +209,27 @@ crypt_sha256_r(const char *key, const char *salt, char *buffer, int buflen)
|
||||
|
||||
/* Now we can construct the result string. It consists of three
|
||||
* parts. */
|
||||
cp = stpncpy(buffer, sha256_salt_prefix, MAX(0, buflen));
|
||||
buflen -= sizeof(sha256_salt_prefix) - 1;
|
||||
cp = stpcpy(buffer, sha256_salt_prefix);
|
||||
|
||||
if (rounds_custom) {
|
||||
n = snprintf(cp, MAX(0, buflen), "%s%zu$",
|
||||
sha256_rounds_prefix, rounds);
|
||||
if (rounds_custom)
|
||||
cp += sprintf(cp, "%s%zu$", sha256_rounds_prefix, rounds);
|
||||
|
||||
cp += n;
|
||||
buflen -= n;
|
||||
}
|
||||
cp = stpncpy(cp, salt, salt_len);
|
||||
|
||||
cp = stpncpy(cp, salt, MIN((size_t)MAX(0, buflen), salt_len));
|
||||
buflen -= MIN((size_t)MAX(0, buflen), salt_len);
|
||||
*cp++ = '$';
|
||||
|
||||
if (buflen > 0) {
|
||||
*cp++ = '$';
|
||||
--buflen;
|
||||
}
|
||||
|
||||
b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4, &buflen, &cp);
|
||||
b64_from_24bit(0, alt_result[31], alt_result[30], 3, &buflen, &cp);
|
||||
if (buflen <= 0) {
|
||||
errno = ERANGE;
|
||||
buffer = NULL;
|
||||
}
|
||||
else
|
||||
*cp = '\0'; /* Terminate the string. */
|
||||
b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4, &cp);
|
||||
b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4, &cp);
|
||||
b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4, &cp);
|
||||
b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4, &cp);
|
||||
b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4, &cp);
|
||||
b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4, &cp);
|
||||
b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4, &cp);
|
||||
b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4, &cp);
|
||||
b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4, &cp);
|
||||
b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4, &cp);
|
||||
b64_from_24bit(0, alt_result[31], alt_result[30], 3, &cp);
|
||||
*cp = '\0'; /* Terminate the string. */
|
||||
|
||||
/* Clear the buffer for the intermediate result so that people
|
||||
* attaching to processes or reading core dumps cannot get any
|
||||
@ -263,37 +247,7 @@ crypt_sha256_r(const char *key, const char *salt, char *buffer, int buflen)
|
||||
if (copied_salt != NULL)
|
||||
memset(copied_salt, '\0', salt_len);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* This entry point is equivalent to crypt(3). */
|
||||
char *
|
||||
crypt_sha256(const char *key, const char *salt)
|
||||
{
|
||||
/* We don't want to have an arbitrary limit in the size of the
|
||||
* password. We can compute an upper bound for the size of the
|
||||
* result in advance and so we can prepare the buffer we pass to
|
||||
* `crypt_sha256_r'. */
|
||||
static char *buffer;
|
||||
static int buflen;
|
||||
int needed;
|
||||
char *new_buffer;
|
||||
|
||||
needed = (sizeof(sha256_salt_prefix) - 1
|
||||
+ sizeof(sha256_rounds_prefix) + 9 + 1
|
||||
+ strlen(salt) + 1 + 43 + 1);
|
||||
|
||||
if (buflen < needed) {
|
||||
new_buffer = (char *)realloc(buffer, needed);
|
||||
|
||||
if (new_buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
buffer = new_buffer;
|
||||
buflen = needed;
|
||||
}
|
||||
|
||||
return crypt_sha256_r(key, salt, buffer, buflen);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
@ -59,11 +59,10 @@ static const char sha512_rounds_prefix[] = "rounds=";
|
||||
/* Maximum number of rounds. */
|
||||
#define ROUNDS_MAX 999999999
|
||||
|
||||
static char *
|
||||
crypt_sha512_r(const char *key, const char *salt, char *buffer, int buflen)
|
||||
int
|
||||
crypt_sha512(const char *key, const char *salt, char *buffer)
|
||||
{
|
||||
u_long srounds;
|
||||
int n;
|
||||
uint8_t alt_result[64], temp_result[64];
|
||||
SHA512_CTX ctx, alt_ctx;
|
||||
size_t salt_len, key_len, cnt, rounds;
|
||||
@ -210,54 +209,39 @@ crypt_sha512_r(const char *key, const char *salt, char *buffer, int buflen)
|
||||
|
||||
/* Now we can construct the result string. It consists of three
|
||||
* parts. */
|
||||
cp = stpncpy(buffer, sha512_salt_prefix, MAX(0, buflen));
|
||||
buflen -= sizeof(sha512_salt_prefix) - 1;
|
||||
cp = stpcpy(buffer, sha512_salt_prefix);
|
||||
|
||||
if (rounds_custom) {
|
||||
n = snprintf(cp, MAX(0, buflen), "%s%zu$",
|
||||
sha512_rounds_prefix, rounds);
|
||||
if (rounds_custom)
|
||||
cp += sprintf(cp, "%s%zu$", sha512_rounds_prefix, rounds);
|
||||
|
||||
cp += n;
|
||||
buflen -= n;
|
||||
}
|
||||
cp = stpncpy(cp, salt, salt_len);
|
||||
|
||||
cp = stpncpy(cp, salt, MIN((size_t)MAX(0, buflen), salt_len));
|
||||
buflen -= MIN((size_t)MAX(0, buflen), salt_len);
|
||||
*cp++ = '$';
|
||||
|
||||
if (buflen > 0) {
|
||||
*cp++ = '$';
|
||||
--buflen;
|
||||
}
|
||||
b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4, &cp);
|
||||
b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4, &cp);
|
||||
b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4, &cp);
|
||||
b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4, &cp);
|
||||
b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4, &cp);
|
||||
b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4, &cp);
|
||||
b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4, &cp);
|
||||
b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4, &cp);
|
||||
b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4, &cp);
|
||||
b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4, &cp);
|
||||
b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4, &cp);
|
||||
b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4, &cp);
|
||||
b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4, &cp);
|
||||
b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4, &cp);
|
||||
b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4, &cp);
|
||||
b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4, &cp);
|
||||
b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4, &cp);
|
||||
b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4, &cp);
|
||||
b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4, &cp);
|
||||
b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4, &cp);
|
||||
b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4, &cp);
|
||||
b64_from_24bit(0, 0, alt_result[63], 2, &cp);
|
||||
|
||||
b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4, &buflen, &cp);
|
||||
b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4, &buflen, &cp);
|
||||
b64_from_24bit(0, 0, alt_result[63], 2, &buflen, &cp);
|
||||
|
||||
if (buflen <= 0) {
|
||||
errno = ERANGE;
|
||||
buffer = NULL;
|
||||
}
|
||||
else
|
||||
*cp = '\0'; /* Terminate the string. */
|
||||
*cp = '\0'; /* Terminate the string. */
|
||||
|
||||
/* Clear the buffer for the intermediate result so that people
|
||||
* attaching to processes or reading core dumps cannot get any
|
||||
@ -275,37 +259,7 @@ crypt_sha512_r(const char *key, const char *salt, char *buffer, int buflen)
|
||||
if (copied_salt != NULL)
|
||||
memset(copied_salt, '\0', salt_len);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* This entry point is equivalent to crypt(3). */
|
||||
char *
|
||||
crypt_sha512(const char *key, const char *salt)
|
||||
{
|
||||
/* We don't want to have an arbitrary limit in the size of the
|
||||
* password. We can compute an upper bound for the size of the
|
||||
* result in advance and so we can prepare the buffer we pass to
|
||||
* `crypt_sha512_r'. */
|
||||
static char *buffer;
|
||||
static int buflen;
|
||||
int needed;
|
||||
char *new_buffer;
|
||||
|
||||
needed = (sizeof(sha512_salt_prefix) - 1
|
||||
+ sizeof(sha512_rounds_prefix) + 9 + 1
|
||||
+ strlen(salt) + 1 + 86 + 1);
|
||||
|
||||
if (buflen < needed) {
|
||||
new_buffer = (char *)realloc(buffer, needed);
|
||||
|
||||
if (new_buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
buffer = new_buffer;
|
||||
buflen = needed;
|
||||
}
|
||||
|
||||
return crypt_sha512_r(key, salt, buffer, buflen);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd March 9, 2014
|
||||
.Dd August 10, 2016
|
||||
.Dt CRYPT 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -41,6 +41,8 @@
|
||||
.In unistd.h
|
||||
.Ft char *
|
||||
.Fn crypt "const char *key" "const char *salt"
|
||||
.Ft char *
|
||||
.Fn crypt_r "const char *key" "const char *salt" "struct crypt_data *data"
|
||||
.Ft const char *
|
||||
.Fn crypt_get_format "void"
|
||||
.Ft int
|
||||
@ -246,10 +248,20 @@ The
|
||||
.Fn crypt_set_format
|
||||
function sets the default encoding format according to the supplied
|
||||
.Fa string .
|
||||
.Pp
|
||||
The
|
||||
.Fn crypt_r
|
||||
function behaves identically to
|
||||
.Fn crypt ,
|
||||
except that the resulting string is stored in
|
||||
.Fa data ,
|
||||
making it thread-safe.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Fn crypt
|
||||
function returns a pointer to the encrypted value on success, and NULL on
|
||||
and
|
||||
.Fn crypt_r
|
||||
functions return a pointer to the encrypted value on success, and NULL on
|
||||
failure.
|
||||
Note: this is not a standard behaviour, AT&T
|
||||
.Fn crypt
|
||||
@ -280,6 +292,11 @@ section of the code (FreeSec 1.0) was developed outside the United
|
||||
States of America as an unencumbered replacement for the U.S.-only
|
||||
.Nx
|
||||
libcrypt encryption library.
|
||||
.Pp
|
||||
The
|
||||
.Fn crypt_r
|
||||
function was added in
|
||||
.Fx 12.0 .
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
Originally written by
|
||||
|
@ -46,9 +46,9 @@ __FBSDID("$FreeBSD$");
|
||||
* and it needs to be the default for backward compatibility.
|
||||
*/
|
||||
static const struct crypt_format {
|
||||
const char *const name;
|
||||
char *(*const func)(const char *, const char *);
|
||||
const char *const magic;
|
||||
const char *name;
|
||||
int (*func)(const char *, const char *, char *);
|
||||
const char *magic;
|
||||
} crypt_formats[] = {
|
||||
{ "md5", crypt_md5, "$1$" },
|
||||
#ifdef HAS_BLOWFISH
|
||||
@ -104,20 +104,37 @@ crypt_set_format(const char *format)
|
||||
* otherwise, the currently selected format is used.
|
||||
*/
|
||||
char *
|
||||
crypt(const char *passwd, const char *salt)
|
||||
crypt_r(const char *passwd, const char *salt, struct crypt_data *data)
|
||||
{
|
||||
const struct crypt_format *cf;
|
||||
int (*func)(const char *, const char *, char *);
|
||||
#ifdef HAS_DES
|
||||
int len;
|
||||
#endif
|
||||
|
||||
for (cf = crypt_formats; cf->name != NULL; ++cf)
|
||||
if (cf->magic != NULL && strstr(salt, cf->magic) == salt)
|
||||
return (cf->func(passwd, salt));
|
||||
if (cf->magic != NULL && strstr(salt, cf->magic) == salt) {
|
||||
func = cf->func;
|
||||
goto match;
|
||||
}
|
||||
#ifdef HAS_DES
|
||||
len = strlen(salt);
|
||||
if ((len == 13 || len == 2) && strspn(salt, DES_SALT_ALPHABET) == len)
|
||||
return (crypt_des(passwd, salt));
|
||||
if ((len == 13 || len == 2) && strspn(salt, DES_SALT_ALPHABET) == len) {
|
||||
func = crypt_des;
|
||||
goto match;
|
||||
}
|
||||
#endif
|
||||
return (crypt_format->func(passwd, salt));
|
||||
func = crypt_format->func;
|
||||
match:
|
||||
if (func(passwd, salt, data->__buf) != 0)
|
||||
return (NULL);
|
||||
return (data->__buf);
|
||||
}
|
||||
|
||||
char *
|
||||
crypt(const char *passwd, const char *salt)
|
||||
{
|
||||
static struct crypt_data data;
|
||||
|
||||
return (crypt_r(passwd, salt, &data));
|
||||
}
|
||||
|
@ -32,12 +32,12 @@
|
||||
#define MD4_SIZE 16
|
||||
#define MD5_SIZE 16
|
||||
|
||||
char *crypt_des(const char *pw, const char *salt);
|
||||
char *crypt_md5(const char *pw, const char *salt);
|
||||
char *crypt_nthash(const char *pw, const char *salt);
|
||||
char *crypt_blowfish(const char *pw, const char *salt);
|
||||
char *crypt_sha256 (const char *pw, const char *salt);
|
||||
char *crypt_sha512 (const char *pw, const char *salt);
|
||||
int crypt_des(const char *pw, const char *salt, char *buf);
|
||||
int crypt_md5(const char *pw, const char *salt, char *buf);
|
||||
int crypt_nthash(const char *pw, const char *salt, char *buf);
|
||||
int crypt_blowfish(const char *pw, const char *salt, char *buf);
|
||||
int crypt_sha256 (const char *pw, const char *salt, char *buf);
|
||||
int crypt_sha512 (const char *pw, const char *salt, char *buf);
|
||||
|
||||
extern void _crypt_to64(char *s, u_long v, int n);
|
||||
extern void b64_from_24bit(uint8_t B2, uint8_t B1, uint8_t B0, int n, int *buflen, char **cp);
|
||||
extern void b64_from_24bit(uint8_t B2, uint8_t B1, uint8_t B0, int n, char **cp);
|
||||
|
@ -47,7 +47,7 @@ _crypt_to64(char *s, u_long v, int n)
|
||||
}
|
||||
|
||||
void
|
||||
b64_from_24bit(uint8_t B2, uint8_t B1, uint8_t B0, int n, int *buflen, char **cp)
|
||||
b64_from_24bit(uint8_t B2, uint8_t B1, uint8_t B0, int n, char **cp)
|
||||
{
|
||||
uint32_t w;
|
||||
int i;
|
||||
@ -56,8 +56,6 @@ b64_from_24bit(uint8_t B2, uint8_t B1, uint8_t B0, int n, int *buflen, char **cp
|
||||
for (i = 0; i < n; i++) {
|
||||
**cp = itoa64[w&0x3f];
|
||||
(*cp)++;
|
||||
if ((*buflen)-- < 0)
|
||||
break;
|
||||
w >>= 6;
|
||||
}
|
||||
}
|
||||
|
@ -75,8 +75,6 @@ __FBSDID("$FreeBSD$");
|
||||
static void encode_base64(u_int8_t *, u_int8_t *, u_int16_t);
|
||||
static void decode_base64(u_int8_t *, u_int16_t, const u_int8_t *);
|
||||
|
||||
static char encrypted[_PASSWORD_LEN];
|
||||
|
||||
const static u_int8_t Base64Code[] =
|
||||
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
@ -135,8 +133,8 @@ decode_base64(u_int8_t *buffer, u_int16_t len, const u_int8_t *data)
|
||||
/* We handle $Vers$log2(NumRounds)$salt+passwd$
|
||||
i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
|
||||
|
||||
char *
|
||||
crypt_blowfish(const char *key, const char *salt)
|
||||
int
|
||||
crypt_blowfish(const char *key, const char *salt, char *buffer)
|
||||
{
|
||||
blf_ctx state;
|
||||
u_int32_t rounds, i, k;
|
||||
@ -157,10 +155,8 @@ crypt_blowfish(const char *key, const char *salt)
|
||||
/* Discard "$" identifier */
|
||||
salt++;
|
||||
|
||||
if (*salt > BCRYPT_VERSION) {
|
||||
/* How do I handle errors ? Return NULL */
|
||||
return NULL;
|
||||
}
|
||||
if (*salt > BCRYPT_VERSION)
|
||||
return (-1);
|
||||
|
||||
/* Check for minor versions */
|
||||
if (salt[1] != '$') {
|
||||
@ -174,7 +170,7 @@ crypt_blowfish(const char *key, const char *salt)
|
||||
salt++;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
return (-1);
|
||||
}
|
||||
} else
|
||||
minr = 0;
|
||||
@ -184,15 +180,15 @@ crypt_blowfish(const char *key, const char *salt)
|
||||
|
||||
if (salt[2] != '$')
|
||||
/* Out of sync with passwd entry */
|
||||
return NULL;
|
||||
return (-1);
|
||||
|
||||
memcpy(arounds, salt, sizeof(arounds));
|
||||
if (arounds[sizeof(arounds) - 1] != '$')
|
||||
return NULL;
|
||||
return (-1);
|
||||
arounds[sizeof(arounds) - 1] = 0;
|
||||
logr = strtonum(arounds, BCRYPT_MINLOGROUNDS, 31, NULL);
|
||||
if (logr == 0)
|
||||
return NULL;
|
||||
return (-1);
|
||||
/* Computer power doesn't increase linearly, 2^x should be fine */
|
||||
rounds = 1U << logr;
|
||||
|
||||
@ -201,7 +197,7 @@ crypt_blowfish(const char *key, const char *salt)
|
||||
}
|
||||
|
||||
if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT)
|
||||
return NULL;
|
||||
return (-1);
|
||||
|
||||
/* We dont want the base64 salt but the raw data */
|
||||
decode_base64(csalt, BCRYPT_MAXSALT, (const u_int8_t *) salt);
|
||||
@ -248,23 +244,23 @@ crypt_blowfish(const char *key, const char *salt)
|
||||
}
|
||||
|
||||
|
||||
i = 0;
|
||||
encrypted[i++] = '$';
|
||||
encrypted[i++] = BCRYPT_VERSION;
|
||||
*buffer++ = '$';
|
||||
*buffer++ = BCRYPT_VERSION;
|
||||
if (minr)
|
||||
encrypted[i++] = minr;
|
||||
encrypted[i++] = '$';
|
||||
*buffer++ = minr;
|
||||
*buffer++ = '$';
|
||||
|
||||
snprintf(encrypted + i, 4, "%2.2u$", logr);
|
||||
snprintf(buffer, 4, "%2.2u$", logr);
|
||||
buffer += 3;
|
||||
|
||||
encode_base64((u_int8_t *) encrypted + i + 3, csalt, BCRYPT_MAXSALT);
|
||||
encode_base64((u_int8_t *) encrypted + strlen(encrypted), ciphertext,
|
||||
4 * BCRYPT_BLOCKS - 1);
|
||||
encode_base64((u_int8_t *)buffer, csalt, BCRYPT_MAXSALT);
|
||||
buffer += strlen(buffer);
|
||||
encode_base64((u_int8_t *)buffer, ciphertext, 4 * BCRYPT_BLOCKS - 1);
|
||||
memset(&state, 0, sizeof(state));
|
||||
memset(ciphertext, 0, sizeof(ciphertext));
|
||||
memset(csalt, 0, sizeof(csalt));
|
||||
memset(cdata, 0, sizeof(cdata));
|
||||
return encrypted;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -588,13 +588,12 @@ des_cipher(const char *in, char *out, u_long salt, int count)
|
||||
return(retval);
|
||||
}
|
||||
|
||||
char *
|
||||
crypt_des(const char *key, const char *setting)
|
||||
int
|
||||
crypt_des(const char *key, const char *setting, char *buffer)
|
||||
{
|
||||
int i;
|
||||
u_int32_t count, salt, l, r0, r1, keybuf[2];
|
||||
u_char *p, *q;
|
||||
static char output[21];
|
||||
u_char *q;
|
||||
|
||||
if (!des_initialised)
|
||||
des_init();
|
||||
@ -610,7 +609,7 @@ crypt_des(const char *key, const char *setting)
|
||||
key++;
|
||||
}
|
||||
if (des_setkey((char *)keybuf))
|
||||
return(NULL);
|
||||
return (-1);
|
||||
|
||||
if (*setting == _PASSWORD_EFMT1) {
|
||||
/*
|
||||
@ -629,7 +628,7 @@ crypt_des(const char *key, const char *setting)
|
||||
* Encrypt the key with itself.
|
||||
*/
|
||||
if (des_cipher((char *)keybuf, (char *)keybuf, 0L, 1))
|
||||
return(NULL);
|
||||
return (-1);
|
||||
/*
|
||||
* And XOR with the next 8 characters of the key.
|
||||
*/
|
||||
@ -638,19 +637,9 @@ crypt_des(const char *key, const char *setting)
|
||||
*q++ ^= *key++ << 1;
|
||||
|
||||
if (des_setkey((char *)keybuf))
|
||||
return(NULL);
|
||||
return (-1);
|
||||
}
|
||||
strncpy(output, setting, 9);
|
||||
|
||||
/*
|
||||
* Double check that we weren't given a short setting.
|
||||
* If we were, the above code will probably have created
|
||||
* wierd values for count and salt, but we don't really care.
|
||||
* Just make sure the output string doesn't have an extra
|
||||
* NUL in it.
|
||||
*/
|
||||
output[9] = '\0';
|
||||
p = (u_char *)output + strlen(output);
|
||||
buffer = stpncpy(buffer, setting, 9);
|
||||
} else {
|
||||
/*
|
||||
* "old"-style:
|
||||
@ -662,43 +651,41 @@ crypt_des(const char *key, const char *setting)
|
||||
salt = (ascii_to_bin(setting[1]) << 6)
|
||||
| ascii_to_bin(setting[0]);
|
||||
|
||||
output[0] = setting[0];
|
||||
*buffer++ = setting[0];
|
||||
/*
|
||||
* If the encrypted password that the salt was extracted from
|
||||
* is only 1 character long, the salt will be corrupted. We
|
||||
* need to ensure that the output string doesn't have an extra
|
||||
* NUL in it!
|
||||
*/
|
||||
output[1] = setting[1] ? setting[1] : output[0];
|
||||
|
||||
p = (u_char *)output + 2;
|
||||
*buffer++ = setting[1] ? setting[1] : setting[0];
|
||||
}
|
||||
setup_salt(salt);
|
||||
/*
|
||||
* Do it.
|
||||
*/
|
||||
if (do_des(0L, 0L, &r0, &r1, (int)count))
|
||||
return(NULL);
|
||||
return (-1);
|
||||
/*
|
||||
* Now encode the result...
|
||||
*/
|
||||
l = (r0 >> 8);
|
||||
*p++ = ascii64[(l >> 18) & 0x3f];
|
||||
*p++ = ascii64[(l >> 12) & 0x3f];
|
||||
*p++ = ascii64[(l >> 6) & 0x3f];
|
||||
*p++ = ascii64[l & 0x3f];
|
||||
*buffer++ = ascii64[(l >> 18) & 0x3f];
|
||||
*buffer++ = ascii64[(l >> 12) & 0x3f];
|
||||
*buffer++ = ascii64[(l >> 6) & 0x3f];
|
||||
*buffer++ = ascii64[l & 0x3f];
|
||||
|
||||
l = (r0 << 16) | ((r1 >> 16) & 0xffff);
|
||||
*p++ = ascii64[(l >> 18) & 0x3f];
|
||||
*p++ = ascii64[(l >> 12) & 0x3f];
|
||||
*p++ = ascii64[(l >> 6) & 0x3f];
|
||||
*p++ = ascii64[l & 0x3f];
|
||||
*buffer++ = ascii64[(l >> 18) & 0x3f];
|
||||
*buffer++ = ascii64[(l >> 12) & 0x3f];
|
||||
*buffer++ = ascii64[(l >> 6) & 0x3f];
|
||||
*buffer++ = ascii64[l & 0x3f];
|
||||
|
||||
l = r1 << 2;
|
||||
*p++ = ascii64[(l >> 12) & 0x3f];
|
||||
*p++ = ascii64[(l >> 6) & 0x3f];
|
||||
*p++ = ascii64[l & 0x3f];
|
||||
*p = 0;
|
||||
*buffer++ = ascii64[(l >> 12) & 0x3f];
|
||||
*buffer++ = ascii64[(l >> 6) & 0x3f];
|
||||
*buffer++ = ascii64[l & 0x3f];
|
||||
*buffer = '\0';
|
||||
|
||||
return(output);
|
||||
return (0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user