From f31b1a2faf808b6d39636a02366ba98a0ae6ebb2 Mon Sep 17 00:00:00 2001 From: Andrew Aldridge Date: Tue, 17 Jan 2017 15:03:03 +0000 Subject: [PATCH] Implement scrypt-based password hashing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Axel Dörfler --- src/apps/aboutsystem/AboutSystem.cpp | 9 + src/bin/multiuser/passwd.cpp | 4 +- .../screensaver/PasswordWindow.cpp | 39 +-- src/preferences/screensaver/PasswordWindow.h | 1 - src/system/libroot/Jamfile | 2 + src/system/libroot/posix/crypt/Jamfile | 11 +- src/system/libroot/posix/crypt/crypt.cpp | 198 +++++++++++++++ .../posix/crypt/{crypt.c => crypt_legacy.c} | 22 +- src/system/libroot/posix/crypt/crypt_legacy.h | 14 ++ .../{crypt_util.c => crypt_legacy_util.c} | 172 ++++++------- .../libroot/posix/crypt/crypto_scrypt.cpp | 233 ++++++++++++++++++ .../libroot/posix/crypt/crypto_scrypt.h | 47 ++++ .../posix/crypt/crypto_scrypt_smix.cpp | 217 ++++++++++++++++ .../libroot/posix/crypt/crypto_scrypt_smix.h | 43 ++++ src/system/libroot/posix/crypt/pbkdf2.cpp | 183 ++++++++++++++ src/system/libroot/posix/crypt/pbkdf2.h | 107 ++++++++ src/tests/system/libroot/posix/CryptTest.cpp | 107 ++++++++ src/tests/system/libroot/posix/CryptTest.h | 35 +++ src/tests/system/libroot/posix/Jamfile | 7 + .../system/libroot/posix/LibRootPosix.cpp | 22 ++ 20 files changed, 1328 insertions(+), 145 deletions(-) create mode 100644 src/system/libroot/posix/crypt/crypt.cpp rename src/system/libroot/posix/crypt/{crypt.c => crypt_legacy.c} (94%) create mode 100644 src/system/libroot/posix/crypt/crypt_legacy.h rename src/system/libroot/posix/crypt/{crypt_util.c => crypt_legacy_util.c} (93%) create mode 100644 src/system/libroot/posix/crypt/crypto_scrypt.cpp create mode 100644 src/system/libroot/posix/crypt/crypto_scrypt.h create mode 100644 src/system/libroot/posix/crypt/crypto_scrypt_smix.cpp create mode 100644 src/system/libroot/posix/crypt/crypto_scrypt_smix.h create mode 100644 src/system/libroot/posix/crypt/pbkdf2.cpp create mode 100644 src/system/libroot/posix/crypt/pbkdf2.h create mode 100644 src/tests/system/libroot/posix/CryptTest.cpp create mode 100644 src/tests/system/libroot/posix/CryptTest.h create mode 100644 src/tests/system/libroot/posix/LibRootPosix.cpp diff --git a/src/apps/aboutsystem/AboutSystem.cpp b/src/apps/aboutsystem/AboutSystem.cpp index 4aea876130..ee80b1973c 100644 --- a/src/apps/aboutsystem/AboutSystem.cpp +++ b/src/apps/aboutsystem/AboutSystem.cpp @@ -1420,6 +1420,15 @@ AboutView::_CreateCreditsView() _AddCopyrightsFromAttribute(); _AddPackageCreditEntries(); + // scrypt + _AddPackageCredit(PackageCredit("scrypt") + .SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2009 Colin Percival")) + .SetLicense(kBSDTwoClause) + .SetURL("https://tarsnap.com/scrypt.html")); + + _AddCopyrightsFromAttribute(); + _AddPackageCreditEntries(); + return new CropView(creditsScroller, 0, 1, 1, 1); } diff --git a/src/bin/multiuser/passwd.cpp b/src/bin/multiuser/passwd.cpp index 44beda27dd..33df0c54bd 100644 --- a/src/bin/multiuser/passwd.cpp +++ b/src/bin/multiuser/passwd.cpp @@ -172,7 +172,7 @@ main(int argc, const char* const* argv) memset(repeatedPassword, 0, sizeof(repeatedPassword)); // crypt it - encryptedPassword = crypt(password, user); + encryptedPassword = crypt(password, NULL); memset(password, 0, sizeof(password)); } @@ -182,7 +182,7 @@ main(int argc, const char* const* argv) || message.AddInt32("last changed", time(NULL)) != B_OK || message.AddString("password", "x") != B_OK || message.AddString("shadow password", encryptedPassword) != B_OK) { - fprintf(stderr, "Error: Out of memory!\n"); + fprintf(stderr, "Error: Failed to construct message!\n"); exit(1); } diff --git a/src/preferences/screensaver/PasswordWindow.cpp b/src/preferences/screensaver/PasswordWindow.cpp index 51c72b5033..54e32093b6 100644 --- a/src/preferences/screensaver/PasswordWindow.cpp +++ b/src/preferences/screensaver/PasswordWindow.cpp @@ -145,41 +145,6 @@ PasswordWindow::Update() } -char* -PasswordWindow::_SanitizeSalt(const char* password) -{ - char* salt; - - uint8 length = strlen(password); - - if (length < 2) - salt = new char[3]; - else - salt = new char[length + 1]; - - uint8 i = 0; - uint8 j = 0; - for (; i < length; i++) { - if (isalnum(password[i]) || password[i] == '.' || password[i] == '/') { - salt[j] = password[i]; - j++; - } - } - - /* - * We need to pad the salt. - */ - while (j < 2) { - salt[j] = '.'; - j++; - } - - salt[j] = '\0'; - - return salt; -} - - void PasswordWindow::MessageReceived(BMessage* message) { @@ -196,9 +161,7 @@ PasswordWindow::MessageReceived(BMessage* message) alert->Go(); break; } - const char* salt = _SanitizeSalt(fPasswordControl->Text()); - fSettings.SetPassword(crypt(fPasswordControl->Text(), salt)); - delete[] salt; + fSettings.SetPassword(crypt(fPasswordControl->Text(), NULL)); } else fSettings.SetPassword(""); diff --git a/src/preferences/screensaver/PasswordWindow.h b/src/preferences/screensaver/PasswordWindow.h index 0bf11c59d1..eee262113e 100644 --- a/src/preferences/screensaver/PasswordWindow.h +++ b/src/preferences/screensaver/PasswordWindow.h @@ -29,7 +29,6 @@ public: private: void _Setup(); - char* _SanitizeSalt(const char* password); BRadioButton* fUseCustom; BRadioButton* fUseNetwork; diff --git a/src/system/libroot/Jamfile b/src/system/libroot/Jamfile index 2d988cd434..210b92b42d 100644 --- a/src/system/libroot/Jamfile +++ b/src/system/libroot/Jamfile @@ -85,6 +85,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { $(librootNoDebugObjects) [ TargetStaticLibsupc++ ] [ TargetLibgcc ] + shared ; # Use the standard libroot.so soname, so when the debug version is @@ -99,6 +100,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { $(librootDebugObjects) [ TargetStaticLibsupc++ ] [ TargetLibgcc ] + shared ; StaticLibrary [ MultiArchDefaultGristFiles libm.a ] : empty.c ; diff --git a/src/system/libroot/posix/crypt/Jamfile b/src/system/libroot/posix/crypt/Jamfile index db3bb04ebf..d0e6670287 100644 --- a/src/system/libroot/posix/crypt/Jamfile +++ b/src/system/libroot/posix/crypt/Jamfile @@ -1,5 +1,8 @@ SubDir HAIKU_TOP src system libroot posix crypt ; +UsePrivateHeaders shared ; +UsePrivateSystemHeaders ; + local architectureObject ; for architectureObject in [ MultiArchSubDirSetup ] { on $(architectureObject) { @@ -11,8 +14,12 @@ for architectureObject in [ MultiArchSubDirSetup ] { : -Wall -Wmissing-prototypes -Wsign-compare ] ; MergeObject <$(architecture)>posix_crypt.o : - crypt.c - crypt_util.c + crypt_legacy.c + crypt_legacy_util.c + crypto_scrypt_smix.cpp + crypto_scrypt.cpp + crypt.cpp + pbkdf2.cpp ; } } diff --git a/src/system/libroot/posix/crypt/crypt.cpp b/src/system/libroot/posix/crypt/crypt.cpp new file mode 100644 index 0000000000..bdd686b636 --- /dev/null +++ b/src/system/libroot/posix/crypt/crypt.cpp @@ -0,0 +1,198 @@ +/* + * Copyright 2017, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrew Aldridge, i80and@foxquill.com + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "crypt_legacy.h" +#include "crypto_scrypt.h" + +#define SALT_BYTES 32 +#define SALT_STR_BYTES (SALT_BYTES * 2 + 1) +#define DEFAULT_N_LOG2 14 + +// $s$99$ salt $ hash \0 +#define CRYPT_OUTPUT_BYTES (6 + 64 + 1 + 64 + 1) + +static const char* kHexAlphabet = "0123456789abcdef"; +static const char kHexLookup[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15}; + + +static int +toHex(const uint8* buffer, size_t bufferLength, char* outBuffer, + size_t outBufferLength) +{ + size_t i; + size_t outIndex = 0; + + if (outBufferLength <= bufferLength * 2) { + outBuffer[0] = '\0'; + return 1; + } + + for (i = 0; i < bufferLength; i += 1) { + const uint8 n = buffer[i]; + const uint8 upper = n >> 4; + const uint8 lower = n & 0x0f; + + assert(lower < 16 && upper < 16); + outBuffer[outIndex++] = kHexAlphabet[upper]; + outBuffer[outIndex++] = kHexAlphabet[lower]; + outBuffer[outIndex] = '\0'; + } + + outBuffer[outIndex] = '\0'; + + return 0; +} + + +static size_t +fromHex(const char* hex, uint8* outBuffer, size_t outBufferLength) +{ + size_t i = 0; + size_t outIndex = 0; + + if (hex[0] == '\0' || outBufferLength == 0) + return 0; + + while (hex[i] != '\0' && hex[i + 1] != '\0') { + const uint8 char1 = hex[i]; + const uint8 char2 = hex[i + 1]; + + if (char1 >= sizeof(kHexLookup) || char2 >= sizeof(kHexLookup)) + return outIndex; + + const char index1 = kHexLookup[char1]; + const char index2 = kHexLookup[char2]; + + if (outIndex >= outBufferLength) + return 0; + + outBuffer[outIndex++] = (index1 << 4) | index2; + i += 2; + } + + return outIndex; +} + + +//! Generate a new salt appropriate for crypt(). +static char* +crypt_gensalt() +{ + static char result[CRYPT_OUTPUT_BYTES]; + uint8 salt[SALT_BYTES]; + char saltString[SALT_STR_BYTES]; + size_t totalBytesRead = 0; + + int fd = open("/dev/random", O_RDONLY, 0); + if (fd < 0) + return NULL; + + while (totalBytesRead < sizeof(salt)) { + const ssize_t bytesRead = read(fd, + static_cast(salt + totalBytesRead), + sizeof(salt) - totalBytesRead); + if (bytesRead <= 0) { + close(fd); + return NULL; + } + + totalBytesRead += bytesRead; + } + close(fd); + + assert(toHex(salt, sizeof(salt), saltString, sizeof(saltString)) == 0); + snprintf(result, sizeof(result), "$s$%d$%s$", DEFAULT_N_LOG2, saltString); + return result; +} + + +char * +crypt(const char* key, const char* setting) +{ + static char outBuffer[CRYPT_OUTPUT_BYTES]; + uint8 saltBinary[SALT_BYTES]; + char saltString[SALT_STR_BYTES]; + uint8 resultBuffer[32]; + char hexResultBuffer[64 + 1]; + int nLog2 = DEFAULT_N_LOG2; + + if (setting == NULL) { + setting = crypt_gensalt(); + if (setting == NULL) { + // crypt_gensalt should set errno itself. + return NULL; + } + } + + // 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 + // shortish. + if (strlen(setting) < 16) + return crypt_legacy(key, setting); + + // 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 + // error. + if (sscanf(setting, "$s$%2d$%64s$", &nLog2, saltString) != 2) { + errno = EINVAL; + return NULL; + } + + // Set a lower bound on N_log2: below 12 scrypt is weaker than bcrypt. + if (nLog2 < 12) { + errno = EINVAL; + return NULL; + } + + size_t saltBinaryLength = fromHex(saltString, saltBinary, + sizeof(saltBinary)); + if (saltBinaryLength != sizeof(saltBinary)) { + errno = EINVAL; + return NULL; + } + + long n = static_cast(pow(2, nLog2)); + if (crypto_scrypt(reinterpret_cast(key), strlen(key), + saltBinary, saltBinaryLength, n, 8, 1, resultBuffer, + sizeof(resultBuffer)) != 0) { + // crypto_scrypt sets errno itself + return NULL; + } + + assert(toHex(resultBuffer, sizeof(resultBuffer), hexResultBuffer, + sizeof(hexResultBuffer)) == 0); + snprintf(outBuffer, sizeof(outBuffer), "$s$%d$%s$%s", nLog2, saltString, + hexResultBuffer); + + return outBuffer; +} + + +//! To make fcrypt users happy. They don't need to call init_des. +char* +fcrypt(const char* key, const char* salt) +{ + return crypt(key, salt); +} diff --git a/src/system/libroot/posix/crypt/crypt.c b/src/system/libroot/posix/crypt/crypt_legacy.c similarity index 94% rename from src/system/libroot/posix/crypt/crypt.c rename to src/system/libroot/posix/crypt/crypt_legacy.c index c647e3766a..bf2192ad39 100644 --- a/src/system/libroot/posix/crypt/crypt.c +++ b/src/system/libroot/posix/crypt/crypt_legacy.c @@ -12,7 +12,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. - * + * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @@ -51,19 +51,19 @@ ufc_long *_ufc_doit(l1, l2, r1, r2, itr) k = &_ufc_keytab[0][0]; for(i=8; i--; ) { s = *k++ ^ r1; - l1 ^= SBA(sb1, s & 0xffff); l2 ^= SBA(sb1, (s & 0xffff)+4); - l1 ^= SBA(sb0, s >>= 16); l2 ^= SBA(sb0, (s) +4); - s = *k++ ^ r2; + l1 ^= SBA(sb1, s & 0xffff); l2 ^= SBA(sb1, (s & 0xffff)+4); + l1 ^= SBA(sb0, s >>= 16); l2 ^= SBA(sb0, (s) +4); + s = *k++ ^ r2; l1 ^= SBA(sb3, s & 0xffff); l2 ^= SBA(sb3, (s & 0xffff)+4); l1 ^= SBA(sb2, s >>= 16); l2 ^= SBA(sb2, (s) +4); - s = *k++ ^ l1; - r1 ^= SBA(sb1, s & 0xffff); r2 ^= SBA(sb1, (s & 0xffff)+4); - r1 ^= SBA(sb0, s >>= 16); r2 ^= SBA(sb0, (s) +4); - s = *k++ ^ l2; - r1 ^= SBA(sb3, s & 0xffff); r2 ^= SBA(sb3, (s & 0xffff)+4); + s = *k++ ^ l1; + r1 ^= SBA(sb1, s & 0xffff); r2 ^= SBA(sb1, (s & 0xffff)+4); + r1 ^= SBA(sb0, s >>= 16); r2 ^= SBA(sb0, (s) +4); + s = *k++ ^ l2; + r1 ^= SBA(sb3, s & 0xffff); r2 ^= SBA(sb3, (s & 0xffff)+4); r1 ^= SBA(sb2, s >>= 16); r2 ^= SBA(sb2, (s) +4); - } + } s=l1; l1=r1; r1=s; s=l2; l2=r2; r2=s; } ary[0] = l1; ary[1] = l2; ary[2] = r1; ary[3] = r2; @@ -111,7 +111,7 @@ ufc_long *_ufc_doit(l1, l2, r1, r2, itr) r ^= SBA(sb2, (s >> 16) & 0xffff); r ^= SBA(sb1, (s >> 32) & 0xffff); r ^= SBA(sb0, (s >> 48) & 0xffff); - } + } s=l; l=r; r=s; } diff --git a/src/system/libroot/posix/crypt/crypt_legacy.h b/src/system/libroot/posix/crypt/crypt_legacy.h new file mode 100644 index 0000000000..62774a47f2 --- /dev/null +++ b/src/system/libroot/posix/crypt/crypt_legacy.h @@ -0,0 +1,14 @@ +#ifndef CRYPT_LEGACY_H +#define CRYPT_LEGACY_H + +#ifdef __cplusplus +extern "C" { +#endif + +char *crypt_legacy(const char *key, const char *salt); + +#ifdef __cplusplus +} +#endif + +#endif // CRYPT_LEGACY_H diff --git a/src/system/libroot/posix/crypt/crypt_util.c b/src/system/libroot/posix/crypt/crypt_legacy_util.c similarity index 93% rename from src/system/libroot/posix/crypt/crypt_util.c rename to src/system/libroot/posix/crypt/crypt_legacy_util.c index c72a55fcc2..734bbc3507 100644 --- a/src/system/libroot/posix/crypt/crypt_util.c +++ b/src/system/libroot/posix/crypt/crypt_legacy_util.c @@ -24,6 +24,7 @@ */ #include +#include "crypt_legacy.h" #ifdef DEBUG #include @@ -47,11 +48,11 @@ static char patchlevel_str[] = PATCHLEVEL; -/* - * Permutation done once on the 56 bit +/* + * Permutation done once on the 56 bit * key derived from the original 8 byte ASCII key. */ -static int pc1[56] = { +static int pc1[56] = { 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, @@ -62,15 +63,15 @@ static int pc1[56] = { * How much to rotate each 28 bit half of the pc1 permutated * 56 bit key before using pc2 to give the i' key */ -static int rots[16] = { - 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +static int rots[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; -/* - * Permutation giving the key - * of the i' DES round +/* + * Permutation giving the key + * of the i' DES round */ -static int pc2[48] = { +static int pc2[48] = { 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, @@ -81,7 +82,7 @@ static int pc2[48] = { * The E expansion table which selects * bits from the 32 bit intermediate result. */ -static int esel[48] = { +static int esel[48] = { 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, @@ -89,16 +90,16 @@ static int esel[48] = { }; static int e_inverse[64]; -/* - * Permutation done on the - * result of sbox lookups +/* + * Permutation done on the + * result of sbox lookups */ static int perm32[32] = { 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 }; -/* +/* * The sboxes */ static int sbox[8][4][16]= { @@ -151,19 +152,19 @@ static int sbox[8][4][16]= { } }; -/* - * This is the initial +/* + * This is the initial * permutation matrix */ -static int initial_perm[64] = { +static int initial_perm[64] = { 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 }; -/* - * This is the final +/* + * This is the final * permutation matrix */ static int final_perm[64] = { @@ -173,8 +174,8 @@ static int final_perm[64] = { 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 }; -/* - * The 16 DES keys in BITMASK format +/* + * The 16 DES keys in BITMASK format */ #ifdef _UFC_32_ long32 _ufc_keytab[16][2]; @@ -201,15 +202,15 @@ long64 _ufc_keytab[16]; #ifdef _UFC_32_ long32 _ufc_sb0[8192], _ufc_sb1[8192], _ufc_sb2[8192], _ufc_sb3[8192]; -static long32 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; +static long32 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; #endif #ifdef _UFC_64_ long64 _ufc_sb0[4096], _ufc_sb1[4096], _ufc_sb2[4096], _ufc_sb3[4096]; -static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; +static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; #endif -/* +/* * eperm32tab: do 32 bit permutation and E selection * * The first index is the byte number in the 32 bit value to be permuted @@ -220,7 +221,7 @@ static long64 *sb[4] = {_ufc_sb0, _ufc_sb1, _ufc_sb2, _ufc_sb3}; */ static ufc_long eperm32tab[4][256][2]; -/* +/* * do_pc1: permform pc1 permutation in the key schedule generation. * * The first index is the byte number in the 8 byte ASCII key @@ -248,7 +249,7 @@ static ufc_long do_pc2[8][128]; /* * efp: undo an extra e selection and do final * permutation giving the DES result. - * + * * Invoked 6 bit a time on two 48 bit values * giving two 32 bit longs. */ @@ -349,7 +350,7 @@ void init_des() mask1 = bytemask[comes_from_bit % 8 + 1]; mask2 = longmask[bit % 28 + 4]; for(j = 0; j < 128; j++) { - if(j & mask1) + if(j & mask1) do_pc1[comes_from_bit / 8][bit / 28][j] |= mask2; } } @@ -369,14 +370,14 @@ void init_des() } } - /* + /* * Now generate the table used to do combined * 32 bit permutation and e expansion * * We use it because we have to permute 16384 32 bit * longs into 48 bit in order to initialize sb. * - * Looping 48 rounds per permutation becomes + * Looping 48 rounds per permutation becomes * just too slow... * */ @@ -385,17 +386,17 @@ void init_des() for(bit = 0; bit < 48; bit++) { ufc_long mask1,comes_from; - + comes_from = perm32[esel[bit]-1]-1; mask1 = bytemask[comes_from % 8]; - + for(j = 256; j--;) { if(j & mask1) eperm32tab[comes_from / 8][j][bit / 24] |= BITMASK(bit % 24); } } - - /* + + /* * Create the sb tables: * * For each 12 bit segment of an 48 bit intermediate @@ -410,14 +411,14 @@ void init_des() for(sg = 0; sg < 4; sg++) { int j1, j2; int s1, s2; - + for(j1 = 0; j1 < 64; j1++) { s1 = s_lookup(2 * sg, j1); for(j2 = 0; j2 < 64; j2++) { ufc_long to_permute, inx; - + s2 = s_lookup(2 * sg + 1, j2); - to_permute = (((ufc_long)s1 << 4) | + to_permute = (((ufc_long)s1 << 4) | (ufc_long)s2) << (24 - 8 * (ufc_long)sg); #ifdef _UFC_32_ @@ -426,20 +427,20 @@ void init_des() sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1]; sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0]; sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1]; - sb[sg][inx ] |= eperm32tab[2][(to_permute >> 8) & 0xff][0]; + sb[sg][inx ] |= eperm32tab[2][(to_permute >> 8) & 0xff][0]; sb[sg][inx+1] |= eperm32tab[2][(to_permute >> 8) & 0xff][1]; sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0]; sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1]; #endif #ifdef _UFC_64_ inx = ((j1 << 6) | j2); - sb[sg][inx] = + sb[sg][inx] = ((long64)eperm32tab[0][(to_permute >> 24) & 0xff][0] << 32) | (long64)eperm32tab[0][(to_permute >> 24) & 0xff][1]; sb[sg][inx] |= ((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) | (long64)eperm32tab[1][(to_permute >> 16) & 0xff][1]; - sb[sg][inx] |= + sb[sg][inx] |= ((long64)eperm32tab[2][(to_permute >> 8) & 0xff][0] << 32) | (long64)eperm32tab[2][(to_permute >> 8) & 0xff][1]; sb[sg][inx] |= @@ -448,9 +449,9 @@ void init_des() #endif } } - } + } - /* + /* * Create an inverse matrix for esel telling * where to plug out bits if undoing it */ @@ -459,7 +460,7 @@ void init_des() e_inverse[esel[bit] - 1 + 32] = bit + 48; } - /* + /* * create efp: the matrix used to * undo the E expansion and effect final permutation */ @@ -474,7 +475,7 @@ void init_des() o_long = bit / 32; /* 0..1 */ o_bit = bit % 32; /* 0..31 */ - /* + /* * And find a bit in the e permutated value setting this bit. * * Note: the e selection may have selected the same bit several @@ -495,7 +496,7 @@ void init_des() } } - + /* * Create revfinal: an array to undo final * the effects of efp @@ -515,7 +516,7 @@ void init_des() initialized++; } -/* +/* * Process the elements of the sb table permuting the * bits swapped in the expansion by the current salt. */ @@ -547,7 +548,7 @@ STATIC void shuffle_sb(k, saltbits) } #endif -/* +/* * Setup the unit for a new salt * Hopefully we'll not see a new salt in each crypt call. */ @@ -566,8 +567,8 @@ STATIC void setup_salt(s) if(s[0] == current_salt[0] && s[1] == current_salt[1]) return; current_salt[0] = s[0]; current_salt[1] = s[1]; - - /* + + /* * This is the only crypt change to DES: * entries are swapped in the expansion table * according to the bits set in the salt. @@ -576,10 +577,10 @@ STATIC void setup_salt(s) for(i = 0; i < 2; i++) { long c=ascii_to_bin(s[i]); #ifdef notdef - /* + /* * Some applications do rely on illegal * salts. It seems that UFC-crypt behaves - * identically to standard crypt + * identically to standard crypt * implementations on illegal salts -- glad */ if(c < 0 || c > 63) @@ -596,7 +597,7 @@ STATIC void setup_salt(s) * to reflect the changed e * selection table */ - shuffle_sb(_ufc_sb0, current_saltbits ^ saltbits); + shuffle_sb(_ufc_sb0, current_saltbits ^ saltbits); shuffle_sb(_ufc_sb1, current_saltbits ^ saltbits); shuffle_sb(_ufc_sb2, current_saltbits ^ saltbits); shuffle_sb(_ufc_sb3, current_saltbits ^ saltbits); @@ -650,7 +651,7 @@ STATIC void ufc_mk_keytab(key) direction = 0; } -/* +/* * Undo an extra E selection and do final permutations */ @@ -688,8 +689,8 @@ ufc_long *_ufc_dofinalperm(l1, l2, r1, r2) return ary; } -/* - * crypt only: convert from 64 bit to 11 bit ASCII +/* + * crypt only: convert from 64 bit to 11 bit ASCII * prefixing with the salt */ @@ -723,12 +724,12 @@ STATIC char *output_conversion(v1, v2, salt) ufc_long *_ufc_doit(); -/* +/* * UNIX crypt function */ - -char *crypt(key, salt) - char *key, *salt; + +char *crypt_legacy(key, salt) + const char *key, *salt; { ufc_long *s; char ktab[9]; @@ -747,7 +748,7 @@ char *crypt(key, salt) /* * Go for the 25 DES encryptions */ - s = _ufc_doit((ufc_long)0, (ufc_long)0, + s = _ufc_doit((ufc_long)0, (ufc_long)0, (ufc_long)0, (ufc_long)0, (ufc_long)25); /* * Do final permutations @@ -760,18 +761,7 @@ char *crypt(key, salt) return output_conversion(s[0], s[1], salt); } -/* - * To make fcrypt users happy. - * They don't need to call init_des. - */ - -char *fcrypt(key, salt) - char *key; - char *salt; - { return crypt(key, salt); - } - -/* +/* * UNIX encrypt function. Takes a bitvector * represented by one byte per bit and * encrypt/decrypt according to edflag @@ -796,12 +786,12 @@ void encrypt(block, edflag) for(i = 0; i < 8; i++) { #ifdef _UFC_32_ long32 x; - x = _ufc_keytab[15-i][0]; - _ufc_keytab[15-i][0] = _ufc_keytab[i][0]; + x = _ufc_keytab[15-i][0]; + _ufc_keytab[15-i][0] = _ufc_keytab[i][0]; _ufc_keytab[i][0] = x; - x = _ufc_keytab[15-i][1]; - _ufc_keytab[15-i][1] = _ufc_keytab[i][1]; + x = _ufc_keytab[15-i][1]; + _ufc_keytab[15-i][1] = _ufc_keytab[i][1]; _ufc_keytab[i][1] = x; #endif #ifdef _UFC_64_ @@ -856,10 +846,10 @@ void encrypt(block, edflag) for(i = 0; i < 32; i++) { *block++ = (r1 & longmask[i]) != 0; } - + } -/* +/* * UNIX setkey function. Take a 64 bit DES * key and setup the machinery. */ @@ -877,14 +867,14 @@ void setkey(key) c = c << 1 | *key++; ktab[i] = c >> 1; } - + ufc_mk_keytab(ktab); } -/* +/* * Ultrix crypt16 function, thanks to pcl@convex.oxford.ac.uk (Paul Leyland) */ - + char *crypt16(key, salt) char *key, *salt; { ufc_long *s, *t; @@ -894,44 +884,44 @@ char *crypt16(key, salt) * Hack DES tables according to salt */ setup_salt(salt); - + /* * Setup key schedule */ clearmem(ktab, sizeof ktab); (void)strncpy(ktab, key, 8); ufc_mk_keytab(ktab); - + /* * Go for first 20 DES encryptions */ - s = _ufc_doit((ufc_long)0, (ufc_long)0, + s = _ufc_doit((ufc_long)0, (ufc_long)0, (ufc_long)0, (ufc_long)0, (ufc_long)20); - + /* * And convert back to 6 bit ASCII */ strcpy (res, output_conversion(s[0], s[1], salt)); - + clearmem(ttab, sizeof ttab); if (strlen (key) > 8) (void)strncpy(ttab, key+8, 8); ufc_mk_keytab(ttab); - + /* * Go for second 5 DES encryptions */ - t = _ufc_doit((ufc_long)0, (ufc_long)0, + t = _ufc_doit((ufc_long)0, (ufc_long)0, (ufc_long)0, (ufc_long)0, (ufc_long)5); /* * And convert back to 6 bit ASCII */ strcpy (q, output_conversion(t[0], t[1], salt)); strcpy (res+13, q+2); - + clearmem(ktab, sizeof ktab); (void)strncpy(ktab, key, 8); ufc_mk_keytab(ktab); - + return res; } @@ -963,14 +953,14 @@ void ufc_setup_password(cookie, s) } void ufc_do_pw(cookie, guess) - long *cookie; + long *cookie; char *guess; { char ktab[9]; ufc_long *s; clearmem(ktab, sizeof ktab); (void)strncpy(ktab, guess, 8); ufc_mk_keytab(ktab); - s = _ufc_doit((ufc_long)0, (ufc_long)0, + s = _ufc_doit((ufc_long)0, (ufc_long)0, (ufc_long)0, (ufc_long)0, (ufc_long)25); cookie[0] = s[0]; cookie[1] = s[1]; cookie[2] = s[2]; cookie[3] = s[3]; diff --git a/src/system/libroot/posix/crypt/crypto_scrypt.cpp b/src/system/libroot/posix/crypt/crypto_scrypt.cpp new file mode 100644 index 0000000000..78d77b5d7f --- /dev/null +++ b/src/system/libroot/posix/crypt/crypto_scrypt.cpp @@ -0,0 +1,233 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include +#include + +#include +#include +#include +#include + +#include "pbkdf2.h" + +#include "crypto_scrypt_smix.h" + +#include "crypto_scrypt.h" + +static void (*smix_func)(uint8_t *, size_t, uint64_t, void *, void *) = NULL; + +/** + * _crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen, smix): + * Perform the requested scrypt computation, using ${smix} as the smix routine. + */ +static int +_crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, + uint8_t * buf, size_t buflen, + void (*smix)(uint8_t *, size_t, uint64_t, void *, void *)) +{ + void * B0, * V0, * XY0; + uint8_t * B; + uint32_t * V; + uint32_t * XY; + size_t r = _r, p = _p; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > (SIZE_MAX - 64) / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ +#ifdef HAVE_POSIX_MEMALIGN + if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) + goto err0; + B = (uint8_t *)(B0); + if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) + goto err1; + XY = (uint32_t *)(XY0); +#if !defined(MAP_ANON) || !defined(HAVE_MMAP) + if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0) + goto err2; + V = (uint32_t *)(V0); +#endif +#else + if ((B0 = malloc(128 * r * p + 63)) == NULL) + goto err0; + B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); + if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) + goto err1; + XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); +#if !defined(MAP_ANON) || !defined(HAVE_MMAP) + if ((V0 = malloc(128 * r * N + 63)) == NULL) + goto err2; + V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); +#endif +#endif +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + goto err2; + V = (uint32_t *)(V0); +#endif + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + (smix)(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); + + /* Free memory. */ +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if (munmap(V0, 128 * r * N)) + goto err2; +#else + free(V0); +#endif + free(XY0); + free(B0); + + /* Success! */ + return (0); + +err2: + free(XY0); +err1: + free(B0); +err0: + /* Failure! */ + return (-1); +} + +#define TESTLEN 64 +static struct scrypt_test { + const char * passwd; + const char * salt; + uint64_t N; + uint32_t r; + uint32_t p; + uint8_t result[TESTLEN]; +} testcase = { + "pleaseletmein", + "SodiumChloride", + 16, + 8, + 1, + { + 0x25, 0xa9, 0xfa, 0x20, 0x7f, 0x87, 0xca, 0x09, + 0xa4, 0xef, 0x8b, 0x9f, 0x77, 0x7a, 0xca, 0x16, + 0xbe, 0xb7, 0x84, 0xae, 0x18, 0x30, 0xbf, 0xbf, + 0xd3, 0x83, 0x25, 0xaa, 0xbb, 0x93, 0x77, 0xdf, + 0x1b, 0xa7, 0x84, 0xd7, 0x46, 0xea, 0x27, 0x3b, + 0xf5, 0x16, 0xa4, 0x6f, 0xbf, 0xac, 0xf5, 0x11, + 0xc5, 0xbe, 0xba, 0x4c, 0x4a, 0xb3, 0xac, 0xc7, + 0xfa, 0x6f, 0x46, 0x0b, 0x6c, 0x0f, 0x47, 0x7b, + } +}; + +static int +testsmix(void (*smix)(uint8_t *, size_t, uint64_t, void *, void *)) +{ + uint8_t hbuf[TESTLEN]; + + /* Perform the computation. */ + if (_crypto_scrypt( + (const uint8_t *)testcase.passwd, strlen(testcase.passwd), + (const uint8_t *)testcase.salt, strlen(testcase.salt), + testcase.N, testcase.r, testcase.p, hbuf, TESTLEN, smix)) + return (-1); + + /* Does it match? */ + return (memcmp(testcase.result, hbuf, TESTLEN)); +} + +static void +selectsmix(void) +{ + /* If generic smix works, use it. */ + if (!testsmix(crypto_scrypt_smix)) { + smix_func = crypto_scrypt_smix; + return; + } + + /* If we get here, something really bad happened. */ + abort(); +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, + uint8_t * buf, size_t buflen) +{ + + if (smix_func == NULL) + selectsmix(); + + return (_crypto_scrypt(passwd, passwdlen, salt, saltlen, N, _r, _p, + buf, buflen, smix_func)); +} diff --git a/src/system/libroot/posix/crypt/crypto_scrypt.h b/src/system/libroot/posix/crypt/crypto_scrypt.h new file mode 100644 index 0000000000..e7e008293a --- /dev/null +++ b/src/system/libroot/posix/crypt/crypto_scrypt.h @@ -0,0 +1,47 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _CRYPTO_SCRYPT_H_ +#define _CRYPTO_SCRYPT_H_ + +#include +#include + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int crypto_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, + uint32_t, uint32_t, uint8_t *, size_t); + +#endif /* !_CRYPTO_SCRYPT_H_ */ diff --git a/src/system/libroot/posix/crypt/crypto_scrypt_smix.cpp b/src/system/libroot/posix/crypt/crypto_scrypt_smix.cpp new file mode 100644 index 0000000000..eea418c4a4 --- /dev/null +++ b/src/system/libroot/posix/crypt/crypto_scrypt_smix.cpp @@ -0,0 +1,217 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include +#include +#include +#include +#include "pbkdf2.h" +#include "crypto_scrypt_smix.h" + +static void blkcpy(void *, const void *, size_t); +static void blkxor(void *, const void *, size_t); +static void salsa20_8(uint32_t[16]); +static void blockmix_salsa8(const uint32_t *, uint32_t *, uint32_t *, size_t); +static uint64_t integerify(const void *, size_t); + +static void +blkcpy(void * dest, const void * src, size_t len) +{ + size_t * D = (size_t *)dest; + const size_t * S = (const size_t *)src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, const void * src, size_t len) +{ + size_t * D = (size_t *)dest; + const size_t * S = (const size_t *)src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] ^= S[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + uint32_t x[16]; + size_t i; + + blkcpy(x, B, 64); + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(const uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 16], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16 + 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8 + r * 16], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(const void * B, size_t r) +{ + const uint32_t * X = (const uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * crypto_scrypt_smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +void +crypto_scrypt_smix(uint8_t * B, size_t r, uint64_t N, void * _V, void * XY) +{ + uint32_t * X = (uint32_t *)XY; + uint32_t * Y = (uint32_t *)((uint8_t *)(XY) + 128 * r); + uint32_t * Z = (uint32_t *)((uint8_t *)(XY) + 256 * r); + uint32_t * V = (uint32_t *)_V; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) { + X[k] = B_LENDIAN_TO_HOST_INT32(((uint32_t*)B)[k]); + } + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (32 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) { + uint32_t* B32 = &(reinterpret_cast(B)[k]); + *B32 = B_HOST_TO_LENDIAN_INT32(X[k]); + } +} diff --git a/src/system/libroot/posix/crypt/crypto_scrypt_smix.h b/src/system/libroot/posix/crypt/crypto_scrypt_smix.h new file mode 100644 index 0000000000..d2a8e6b147 --- /dev/null +++ b/src/system/libroot/posix/crypt/crypto_scrypt_smix.h @@ -0,0 +1,43 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#ifndef _CRYPTO_SCRYPT_SMIX_H_ +#define _CRYPTO_SCRYPT_SMIX_H_ + +/** + * crypto_scrypt_smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +void crypto_scrypt_smix(uint8_t *, size_t, uint64_t, void *, void *); + +#endif /* !_CRYPTO_SCRYPT_SMIX_H_ */ diff --git a/src/system/libroot/posix/crypt/pbkdf2.cpp b/src/system/libroot/posix/crypt/pbkdf2.cpp new file mode 100644 index 0000000000..792b783c20 --- /dev/null +++ b/src/system/libroot/posix/crypt/pbkdf2.cpp @@ -0,0 +1,183 @@ +/* This file is distributed under the following terms: + + * Copyright 2005-2014 Colin Percival. All rights reserved. + * Copyright 2014 Sean Kelly. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "pbkdf2.h" + +/* Function which does the zeroing. */ +static void +insecure_memzero_func(volatile void * buf, size_t len) +{ + volatile uint8_t * _buf = (volatile uint8_t *)buf; + size_t i; + + for (i = 0; i < len; i++) + _buf[i] = 0; +} + +/* Pointer to memory-zeroing function. */ +void (* volatile insecure_memzero_ptr)(volatile void *, size_t) = + insecure_memzero_func; + +/** + * HMAC_SHA256_Init(ctx, K, Klen): + * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from + * ${K}. + */ +void +HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) +{ + uint8_t pad[64]; + uint8_t khash[32]; + const uint8_t * K = (const uint8_t *)_K; + size_t i; + + /* If Klen > 64, the key is really SHA256(K). */ + if (Klen > 64) { + ctx->ictx.Init(); + ctx->ictx.Update(K, Klen); + memcpy(khash, ctx->ictx.Digest(), 32); + K = khash; + Klen = 32; + } + + /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ + ctx->ictx.Init(); + memset(pad, 0x36, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + ctx->ictx.Update(pad, 64); + + /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ + ctx->octx.Init(); + memset(pad, 0x5c, 64); + for (i = 0; i < Klen; i++) + pad[i] ^= K[i]; + ctx->octx.Update(pad, 64); + + /* Clean the stack. */ + insecure_memzero(khash, 32); + insecure_memzero(pad, 64); +} + +/** + * HMAC_SHA256_Update(ctx, in, len): + * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. + */ +void +HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len) +{ + + /* Feed data to the inner SHA256 operation. */ + ctx->ictx.Update(in, len); +} + +/** + * HMAC_SHA256_Final(digest, ctx): + * Output the HMAC-SHA256 of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +void +HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx) +{ + uint8_t ihash[32]; + + /* Finish the inner SHA256 operation. */ + memcpy(ihash, ctx->ictx.Digest(), 32); + + /* Feed the inner hash to the outer SHA256 operation. */ + ctx->octx.Update(ihash, 32); + + /* Finish the outer SHA256 operation. */ + memcpy(digest, ctx->octx.Digest(), 32); + + /* Clean the stack. */ + insecure_memzero(ihash, 32); +} + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + HMAC_SHA256_CTX PShctx, hctx; + size_t i; + uint32_t ivec; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + /* Sanity-check. */ + assert(dkLen <= 32 * (size_t)(UINT32_MAX)); + + /* Compute HMAC state after processing P and S. */ + HMAC_SHA256_Init(&PShctx, passwd, passwdlen); + HMAC_SHA256_Update(&PShctx, salt, saltlen); + + /* Iterate through the blocks. */ + for (i = 0; i * 32 < dkLen; i++) { + /* Generate INT(i + 1). */ + ivec = B_HOST_TO_BENDIAN_INT32((uint32_t)(i + 1)); + + /* Compute U_1 = PRF(P, S || INT(i)). */ + memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); + HMAC_SHA256_Update(&hctx, &ivec, 4); + HMAC_SHA256_Final(U, &hctx); + + /* T_i = U_1 ... */ + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + /* Compute U_j. */ + HMAC_SHA256_Init(&hctx, passwd, passwdlen); + HMAC_SHA256_Update(&hctx, U, 32); + HMAC_SHA256_Final(U, &hctx); + + /* ... xor U_j ... */ + for (k = 0; k < 32; k++) + T[k] ^= U[k]; + } + + /* Copy as many bytes as necessary into buf. */ + clen = dkLen - i * 32; + if (clen > 32) + clen = 32; + memcpy(&buf[i * 32], T, clen); + } + + /* Clean PShctx, since we never called _Final on it. */ + insecure_memzero(&PShctx, sizeof(HMAC_SHA256_CTX)); +} diff --git a/src/system/libroot/posix/crypt/pbkdf2.h b/src/system/libroot/posix/crypt/pbkdf2.h new file mode 100644 index 0000000000..1208eb6127 --- /dev/null +++ b/src/system/libroot/posix/crypt/pbkdf2.h @@ -0,0 +1,107 @@ +/* This file is distributed under the following terms: + + * Copyright 2005-2014 Colin Percival. All rights reserved. + * Copyright 2014 Sean Kelly. All rights reserved. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include +#include +#include + +/* Pointer to memory-zeroing function. */ +extern void (* volatile insecure_memzero_ptr)(volatile void *, size_t); + +/** + * insecure_memzero(buf, len): + * Attempt to zero ${len} bytes at ${buf} in spite of optimizing compilers' + * best (standards-compliant) attempts to remove the buffer-zeroing. In + * particular, to avoid performing the zeroing, a compiler would need to + * use optimistic devirtualization; recognize that non-volatile objects do not + * need to be treated as volatile, even if they are accessed via volatile + * qualified pointers; and perform link-time optimization; in addition to the + * dead-code elimination which often causes buffer-zeroing to be elided. + * + * Note however that zeroing a buffer does not guarantee that the data held + * in the buffer is not stored elsewhere; in particular, there may be copies + * held in CPU registers or in anonymous allocations on the stack, even if + * every named variable is successfully sanitized. Solving the "wipe data + * from the system" problem will require a C language extension which does not + * yet exist. + * + * For more information, see: + * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html + * http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient.html + */ +static inline void +insecure_memzero(volatile void * buf, size_t len) +{ + + (insecure_memzero_ptr)(buf, len); +} + +/* Context structure for SHA256 operations. */ +typedef struct { + uint32_t state[8]; + uint64_t count; + uint8_t buf[64]; +} SHA256_CTX; + +/* Context structure for HMAC-SHA256 operations. */ +typedef struct { + SHA256 ictx; + SHA256 octx; +} HMAC_SHA256_CTX; + +/** + * HMAC_SHA256_Init(ctx, K, Klen): + * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from + * ${K}. + */ +void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t); + +/** + * HMAC_SHA256_Update(ctx, in, len): + * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. + */ +void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t); + +/** + * HMAC_SHA256_Final(digest, ctx): + * Output the HMAC-SHA256 of the data input to the context ${ctx} into the + * buffer ${digest}. + */ +void HMAC_SHA256_Final(uint8_t[32], HMAC_SHA256_CTX *); + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ diff --git a/src/tests/system/libroot/posix/CryptTest.cpp b/src/tests/system/libroot/posix/CryptTest.cpp new file mode 100644 index 0000000000..c290757c27 --- /dev/null +++ b/src/tests/system/libroot/posix/CryptTest.cpp @@ -0,0 +1,107 @@ +/* + * Copyright 2017, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrew Aldridge, i80and@foxquill.com + */ + + +#include +#include +#include + +#include "CryptTest.h" + +#include +#include + + +#define PASSWORD "password" +#define HASH_SALT "$s$12$101f2cf1a3b35aa671b8e006c6fb037e429d5b4ecb8dab16919097789e2d3a5f$ignorethis" +#define HASH_RESULT "$s$12$101f2cf1a3b35aa671b8e006c6fb037e429d5b4ecb8dab16919097789e2d3a5f$4c5c886740871c447639e2dd5eeba004f22c0860ce88c811032ca6de6c95b23e" + +// This salt is only 31 bytes, while we need 32 bytes +#define HASH_BAD_SALT "$s$12$101f2cf1a3b35aa671b8e006c6fb037e429d5b4ecb8dab16919097789e2d3a$ignorethis" + + +CryptTest::CryptTest() +{ +} + + +CryptTest::~CryptTest() +{ +} + + +void +CryptTest::setUp() +{ +} + + +void +CryptTest::tearDown() +{ +} + + +void +CryptTest::TestLegacy() +{ + char* buf = crypt(PASSWORD, "1d"); + CPPUNIT_ASSERT(buf != NULL); + CPPUNIT_ASSERT(strcmp(buf, "1dVzQK99LSks6") == 0); +} + + +void +CryptTest::TestCustomSalt() +{ + char* buf = crypt(PASSWORD, HASH_SALT); + CPPUNIT_ASSERT(buf != NULL); + CPPUNIT_ASSERT(strcmp(buf, HASH_RESULT) == 0); +} + + +void +CryptTest::TestSaltGeneration() +{ + char tmp[200]; + + char* buf = crypt(PASSWORD, NULL); + CPPUNIT_ASSERT(buf != NULL); + strlcpy(tmp, buf, sizeof(tmp)); + buf = crypt(PASSWORD, tmp); + CPPUNIT_ASSERT(strcmp(buf, tmp) == 0); +} + + +void +CryptTest::TestBadSalt() +{ + errno = 0; + CPPUNIT_ASSERT(crypt(PASSWORD, HASH_BAD_SALT) == NULL); + CPPUNIT_ASSERT(errno == EINVAL); +} + + +void +CryptTest::AddTests(BTestSuite& parent) +{ + CppUnit::TestSuite& suite = *new CppUnit::TestSuite("CryptTest"); + suite.addTest(new CppUnit::TestCaller( + "CryptTest::TestLegacy", + &CryptTest::TestLegacy)); + suite.addTest(new CppUnit::TestCaller( + "CryptTest::TestCustomSalt", + &CryptTest::TestCustomSalt)); + suite.addTest(new CppUnit::TestCaller( + "CryptTest::TestSaltGeneration", + &CryptTest::TestSaltGeneration)); + suite.addTest(new CppUnit::TestCaller( + "CryptTest::TestBadSalt", + &CryptTest::TestBadSalt)); + parent.addTest("CryptTest", &suite); +} diff --git a/src/tests/system/libroot/posix/CryptTest.h b/src/tests/system/libroot/posix/CryptTest.h new file mode 100644 index 0000000000..ee208adf65 --- /dev/null +++ b/src/tests/system/libroot/posix/CryptTest.h @@ -0,0 +1,35 @@ +/* + * Copyright 2017, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrew Aldridge, i80and@foxquill.com + */ + + +#ifndef CRYPT_TEST_H +#define CRYPT_TEST_H + + +#include +#include + + +class CryptTest : public CppUnit::TestCase { +public: + CryptTest(); + virtual ~CryptTest(); + + virtual void setUp(); + virtual void tearDown(); + + void TestLegacy(); + void TestCustomSalt(); + void TestSaltGeneration(); + void TestBadSalt(); + + static void AddTests(BTestSuite& suite); +}; + + +#endif // CRYPT_TEST_H diff --git a/src/tests/system/libroot/posix/Jamfile b/src/tests/system/libroot/posix/Jamfile index b62c971448..fbd2c4f113 100644 --- a/src/tests/system/libroot/posix/Jamfile +++ b/src/tests/system/libroot/posix/Jamfile @@ -73,6 +73,13 @@ SimpleTest test_wcfuncs : test_wcfuncs.c ; SimpleTest test_wctype : test_wctype.c ; SimpleTest wcs_test : wcs_test.cpp ; +UnitTestLib librootposixtest.so : + LibRootPosix.cpp + + CryptTest.cpp + + : be [ TargetLibstdc++ ] [ TargetLibsupc++ ] +; SubInclude HAIKU_TOP src tests system libroot posix math ; SubInclude HAIKU_TOP src tests system libroot posix string ; diff --git a/src/tests/system/libroot/posix/LibRootPosix.cpp b/src/tests/system/libroot/posix/LibRootPosix.cpp new file mode 100644 index 0000000000..c7c32b5466 --- /dev/null +++ b/src/tests/system/libroot/posix/LibRootPosix.cpp @@ -0,0 +1,22 @@ +/* + * Copyright 2017, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Andrew Aldridge, i80and@foxquill.com + */ + + +#include +#include + +#include "CryptTest.h" + + +BTestSuite* +getTestSuite() +{ + BTestSuite* suite = new BTestSuite("LibRootPosix"); + CryptTest::AddTests(*suite); + return suite; +}