libroot: introduce crypt_r

Change-Id: Ieacd1b383ac078a440227c7954f5531a36fbbd62
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5827
Tested-by: Commit checker robot <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
David Karoly
2023-02-10 18:00:44 +00:00
parent c83c6cde11
commit 125b262675
10 changed files with 132 additions and 35 deletions
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright 2023, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _GNU_CRYPT_H_
#define _GNU_CRYPT_H_
#include <features.h>
#ifdef _DEFAULT_SOURCE
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
struct crypt_data {
int initialized;
char buf[512];
};
char *crypt_rn(const char *key, const char *salt, struct crypt_data *data, size_t size);
static inline char *
crypt_r(const char *key, const char *salt, struct crypt_data *data)
{
return crypt_rn(key, salt, data, sizeof(struct crypt_data));
}
#ifdef __cplusplus
}
#endif
#endif
#endif /* _GNU_CRYPT_H_ */
+2
View File
@@ -1,5 +1,6 @@
SubDir HAIKU_TOP src libs gnu ; SubDir HAIKU_TOP src libs gnu ;
UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ;
UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility gnu ] : true ; UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility gnu ] : true ;
UsePrivateHeaders shared ; UsePrivateHeaders shared ;
@@ -10,6 +11,7 @@ local architectureObject ;
for architectureObject in [ MultiArchSubDirSetup ] { for architectureObject in [ MultiArchSubDirSetup ] {
on $(architectureObject) { on $(architectureObject) {
SharedLibrary [ MultiArchDefaultGristFiles libgnu.so ] : SharedLibrary [ MultiArchDefaultGristFiles libgnu.so ] :
crypt.cpp
memmem.c memmem.c
qsort.c qsort.c
xattr.cpp xattr.cpp
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright 2023 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <crypt.h>
/* move this to libroot_private.h ??? */
extern "C" char *_crypt_rn(const char* key, const char* setting, struct crypt_data* data, size_t size);
char *
crypt_rn(const char* key, const char* setting, struct crypt_data* data, size_t size)
{
return _crypt_rn(key, setting, data, size);
}
+2
View File
@@ -2,6 +2,8 @@ SubDir HAIKU_TOP src system libroot posix crypt ;
UsePrivateHeaders libroot ; UsePrivateHeaders libroot ;
UsePrivateSystemHeaders ; UsePrivateSystemHeaders ;
SubDirSysHdrs $(HAIKU_TOP) headers compatibility bsd ;
SubDirSysHdrs $(HAIKU_TOP) headers compatibility gnu ;
local architectureObject ; local architectureObject ;
for architectureObject in [ MultiArchSubDirSetup ] { for architectureObject in [ MultiArchSubDirSetup ] {
+31 -19
View File
@@ -8,6 +8,7 @@
#include <assert.h> #include <assert.h>
#include <crypt.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
@@ -24,8 +25,8 @@
#define SALT_STR_BYTES (SALT_BYTES * 2 + 1) #define SALT_STR_BYTES (SALT_BYTES * 2 + 1)
#define DEFAULT_N_LOG2 14 #define DEFAULT_N_LOG2 14
// $s$99$ salt $ hash \0
#define CRYPT_OUTPUT_BYTES (6 + 64 + 1 + 64 + 1) #define CRYPT_OUTPUT_BYTES (6 + 64 + 1 + 64 + 1)
#define SALT_OUTPUT_BYTES (6 + 64 + 1 + 1)
static const char* kHexAlphabet = "0123456789abcdef"; static const char* kHexAlphabet = "0123456789abcdef";
static const int8 kHexLookup[] = { static const int8 kHexLookup[] = {
@@ -97,17 +98,16 @@ fromHex(const char* hex, uint8* outBuffer, size_t outBufferLength)
//! Generate a new salt appropriate for crypt(). //! Generate a new salt appropriate for crypt().
static char* static int
crypt_gensalt() crypt_gensalt_rn(char *outbuf, size_t bufsize)
{ {
static char result[CRYPT_OUTPUT_BYTES];
uint8 salt[SALT_BYTES]; uint8 salt[SALT_BYTES];
char saltString[SALT_STR_BYTES]; char saltString[SALT_STR_BYTES];
size_t totalBytesRead = 0; size_t totalBytesRead = 0;
int fd = open("/dev/random", O_RDONLY, 0); int fd = open("/dev/random", O_RDONLY, 0);
if (fd < 0) if (fd < 0)
return NULL; return -1;
while (totalBytesRead < sizeof(salt)) { while (totalBytesRead < sizeof(salt)) {
const ssize_t bytesRead = read(fd, const ssize_t bytesRead = read(fd,
@@ -115,7 +115,7 @@ crypt_gensalt()
sizeof(salt) - totalBytesRead); sizeof(salt) - totalBytesRead);
if (bytesRead <= 0) { if (bytesRead <= 0) {
close(fd); close(fd);
return NULL; return -1;
} }
totalBytesRead += bytesRead; totalBytesRead += bytesRead;
@@ -123,34 +123,38 @@ crypt_gensalt()
close(fd); close(fd);
assert(toHex(salt, sizeof(salt), saltString, sizeof(saltString)) == 0); assert(toHex(salt, sizeof(salt), saltString, sizeof(saltString)) == 0);
snprintf(result, sizeof(result), "$s$%d$%s$", DEFAULT_N_LOG2, saltString); snprintf(outbuf, bufsize, "$s$%d$%s$", DEFAULT_N_LOG2, saltString);
return result; return 0;
} }
char * extern "C" char *
crypt(const char* key, const char* setting) _crypt_rn(const char* key, const char* setting, struct crypt_data* data, size_t size)
{ {
static char outBuffer[CRYPT_OUTPUT_BYTES];
uint8 saltBinary[SALT_BYTES]; uint8 saltBinary[SALT_BYTES];
char saltString[SALT_STR_BYTES]; char saltString[SALT_STR_BYTES];
char gensaltResult[SALT_OUTPUT_BYTES];
uint8 resultBuffer[32]; uint8 resultBuffer[32];
char hexResultBuffer[64 + 1]; char hexResultBuffer[64 + 1];
int nLog2 = DEFAULT_N_LOG2; int nLog2 = DEFAULT_N_LOG2;
if (setting == NULL) { if (setting == NULL) {
setting = crypt_gensalt(); int res = crypt_gensalt_rn(gensaltResult, sizeof(gensaltResult));
if (setting == NULL) {
// crypt_gensalt should set errno itself. // crypt_gensalt_r should set errno itself.
if (res < 0)
return NULL; return NULL;
}
setting = gensaltResult;
} }
// Some idioms existed where the password was also used as the salt. // Some idioms existed where the password was also used as the salt.
// As a crude heuristic, use the old crypt algorithm if the salt is // As a crude heuristic, use the old crypt algorithm if the salt is
// shortish. // shortish.
if (strlen(setting) < 16) if (strlen(setting) < 16) {
return crypt_legacy(key, setting); crypt_legacy(key, setting, data->buf);
return data->buf;
}
// We don't want to fall into the old algorithm by accident somehow, so // We don't want to fall into the old algorithm by accident somehow, so
// if our salt is kind of like our salt, but not exactly, return an // if our salt is kind of like our salt, but not exactly, return an
@@ -183,10 +187,18 @@ crypt(const char* key, const char* setting)
assert(toHex(resultBuffer, sizeof(resultBuffer), hexResultBuffer, assert(toHex(resultBuffer, sizeof(resultBuffer), hexResultBuffer,
sizeof(hexResultBuffer)) == 0); sizeof(hexResultBuffer)) == 0);
snprintf(outBuffer, sizeof(outBuffer), "$s$%d$%s$%s", nLog2, saltString, snprintf(data->buf, size - sizeof(int), "$s$%d$%s$%s", nLog2, saltString,
hexResultBuffer); hexResultBuffer);
return outBuffer; return data->buf;
}
char *
crypt(const char* key, const char* salt)
{
static struct crypt_data data;
return _crypt_rn(key, salt, &data, sizeof(struct crypt_data));
} }
@@ -5,7 +5,7 @@
extern "C" { extern "C" {
#endif #endif
char *crypt_legacy(const char *key, const char *salt); void crypt_legacy(const char *key, const char *salt, char *outbuf);
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -694,10 +694,8 @@ ufc_long *_ufc_dofinalperm(l1, l2, r1, r2)
* prefixing with the salt * prefixing with the salt
*/ */
STATIC char *output_conversion(v1, v2, salt) STATIC void output_conversion_r(ufc_long v1, ufc_long v2, const char *salt, char *outbuf)
ufc_long v1, v2; {
char *salt;
{ static char outbuf[14];
int i, s, shf; int i, s, shf;
outbuf[0] = salt[0]; outbuf[0] = salt[0];
@@ -718,8 +716,6 @@ STATIC char *output_conversion(v1, v2, salt)
outbuf[12] = bin_to_ascii(s); outbuf[12] = bin_to_ascii(s);
outbuf[13] = 0; outbuf[13] = 0;
return outbuf;
} }
ufc_long *_ufc_doit(); ufc_long *_ufc_doit();
@@ -728,9 +724,9 @@ ufc_long *_ufc_doit();
* UNIX crypt function * UNIX crypt function
*/ */
char *crypt_legacy(key, salt) void crypt_legacy(const char *key, const char *salt, char *outbuf)
const char *key, *salt; {
{ ufc_long *s; ufc_long *s;
char ktab[9]; char ktab[9];
/* /*
@@ -758,7 +754,7 @@ char *crypt_legacy(key, salt)
/* /*
* And convert back to 6 bit ASCII * And convert back to 6 bit ASCII
*/ */
return output_conversion(s[0], s[1], salt); output_conversion_r(s[0], s[1], salt, outbuf);
} }
/* /*
@@ -901,7 +897,7 @@ char *crypt16(key, salt)
/* /*
* And convert back to 6 bit ASCII * And convert back to 6 bit ASCII
*/ */
strcpy (res, output_conversion(s[0], s[1], salt)); output_conversion_r(s[0], s[1], salt, res);
clearmem(ttab, sizeof ttab); clearmem(ttab, sizeof ttab);
if (strlen (key) > 8) (void)strncpy(ttab, key+8, 8); if (strlen (key) > 8) (void)strncpy(ttab, key+8, 8);
@@ -915,7 +911,7 @@ char *crypt16(key, salt)
/* /*
* And convert back to 6 bit ASCII * And convert back to 6 bit ASCII
*/ */
strcpy (q, output_conversion(t[0], t[1], salt)); output_conversion_r(t[0], t[1], salt, q);
strcpy (res+13, q+2); strcpy (res+13, q+2);
clearmem(ktab, sizeof ktab); clearmem(ktab, sizeof ktab);
@@ -7,6 +7,7 @@
*/ */
#include <crypt.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@@ -87,6 +88,22 @@ CryptTest::TestBadSalt()
} }
void
CryptTest::TestCryptR()
{
char tmp[200];
struct crypt_data data;
data.initialized = 0;
char* buf = crypt_r(PASSWORD, NULL, &data);
CPPUNIT_ASSERT(buf != NULL);
strlcpy(tmp, buf, sizeof(tmp));
buf = crypt(PASSWORD, tmp);
CPPUNIT_ASSERT(strcmp(buf, tmp) == 0);
}
void void
CryptTest::AddTests(BTestSuite& parent) CryptTest::AddTests(BTestSuite& parent)
{ {
@@ -103,5 +120,8 @@ CryptTest::AddTests(BTestSuite& parent)
suite.addTest(new CppUnit::TestCaller<CryptTest>( suite.addTest(new CppUnit::TestCaller<CryptTest>(
"CryptTest::TestBadSalt", "CryptTest::TestBadSalt",
&CryptTest::TestBadSalt)); &CryptTest::TestBadSalt));
suite.addTest(new CppUnit::TestCaller<CryptTest>(
"CryptTest::TestCryptR",
&CryptTest::TestCryptR));
parent.addTest("CryptTest", &suite); parent.addTest("CryptTest", &suite);
} }
@@ -27,6 +27,7 @@ public:
void TestCustomSalt(); void TestCustomSalt();
void TestSaltGeneration(); void TestSaltGeneration();
void TestBadSalt(); void TestBadSalt();
void TestCryptR();
static void AddTests(BTestSuite& suite); static void AddTests(BTestSuite& suite);
}; };
+3 -1
View File
@@ -1,6 +1,8 @@
SubDir HAIKU_TOP src tests system libroot posix ; SubDir HAIKU_TOP src tests system libroot posix ;
UsePrivateHeaders libroot system ; UsePrivateHeaders libroot system ;
SubDirSysHdrs $(HAIKU_TOP) headers compatibility bsd ;
SubDirSysHdrs $(HAIKU_TOP) headers compatibility gnu ;
# filter warnings about strftime()-formats in locale_test # filter warnings about strftime()-formats in locale_test
TARGET_WARNING_C++FLAGS_$(TARGET_PACKAGING_ARCH) TARGET_WARNING_C++FLAGS_$(TARGET_PACKAGING_ARCH)
@@ -87,7 +89,7 @@ UnitTestLib librootposixtest.so :
CryptTest.cpp CryptTest.cpp
: be [ TargetLibstdc++ ] [ TargetLibsupc++ ] : be libgnu.so [ TargetLibstdc++ ] [ TargetLibsupc++ ]
; ;
SubInclude HAIKU_TOP src tests system libroot posix math ; SubInclude HAIKU_TOP src tests system libroot posix math ;