[haiku-commits] haiku: hrev50881 - in src: system/libroot/posix/crypt tests/system/libroot/posix

  • From: axeld@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 17 Jan 2017 23:09:41 +0100 (CET)

hrev50881 adds 1 changeset to branch 'master'
old head: 108c68dc8245acf828db8fcdc7bb37faed7de594
new head: f31b1a2faf808b6d39636a02366ba98a0ae6ebb2
overview: 
http://cgit.haiku-os.org/haiku/log/?qt=range&q=f31b1a2faf80+%5E108c68dc8245

----------------------------------------------------------------------------

f31b1a2faf80: Implement scrypt-based password hashing
  
  Signed-off-by: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>

                                   [ Andrew Aldridge <i80and@xxxxxxxxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev50881
Commit:      f31b1a2faf808b6d39636a02366ba98a0ae6ebb2
URL:         http://cgit.haiku-os.org/haiku/commit/?id=f31b1a2faf80
Author:      Andrew Aldridge <i80and@xxxxxxxxxxxx>
Date:        Tue Jan 17 15:03:03 2017 UTC
Committer:   Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Commit-Date: Tue Jan 17 22:09:04 2017 UTC

----------------------------------------------------------------------------

20 files changed, 1328 insertions(+), 145 deletions(-)
src/apps/aboutsystem/AboutSystem.cpp             |   9 +
src/bin/multiuser/passwd.cpp                     |   4 +-
src/preferences/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/{crypt_util.c => crypt_legacy_util.c}  | 172 +++++++-------
src/system/libroot/posix/crypt/crypto_scrypt.cpp | 233 +++++++++++++++++++
src/system/libroot/posix/crypt/crypto_scrypt.h   |  47 ++++
.../libroot/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 +
src/tests/system/libroot/posix/LibRootPosix.cpp  |  22 ++

----------------------------------------------------------------------------

diff --git a/src/apps/aboutsystem/AboutSystem.cpp 
b/src/apps/aboutsystem/AboutSystem.cpp
index 4aea876..ee80b19 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 44beda2..33df0c5 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 51c72b5..54e3209 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 0bf11c5..eee2621 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 2d988cd..210b92b 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 db3bb04..d0e6670 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 0000000..bdd686b
--- /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@xxxxxxxxxxxx
+ */
+
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <SupportDefs.h>
+
+#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<void*>(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<long>(pow(2, nLog2));
+       if (crypto_scrypt(reinterpret_cast<const uint8*>(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 c647e37..bf2192a 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 0000000..62774a4
--- /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 c72a55f..734bbc3 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 <string.h>
+#include "crypt_legacy.h"
 
 #ifdef DEBUG
 #include <stdio.h>
@@ -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@xxxxxxxxxxxxxxxxxxx (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 0000000..78d77b5
--- /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 <sys/types.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 0000000..e7e0082
--- /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 <stdint.h>
+#include <unistd.h>
+
+/**
+ * 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 0000000..eea418c
--- /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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <ByteOrder.h>
+#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<uint32_t*>(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 0000000..d2a8e6b
--- /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 0000000..792b783
--- /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 <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <ByteOrder.h>
+#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 0000000..1208eb6
--- /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 <stddef.h>
+#include <stdint.h>
+#include <SHA256.h>
+
+/* 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 0000000..c290757
--- /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@xxxxxxxxxxxx
+ */
+
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "CryptTest.h"
+
+#include <cppunit/TestCaller.h>
+#include <cppunit/TestSuite.h>
+
+
+#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>(
+               "CryptTest::TestLegacy",
+               &CryptTest::TestLegacy));
+       suite.addTest(new CppUnit::TestCaller<CryptTest>(
+               "CryptTest::TestCustomSalt",
+               &CryptTest::TestCustomSalt));
+       suite.addTest(new CppUnit::TestCaller<CryptTest>(
+               "CryptTest::TestSaltGeneration",
+               &CryptTest::TestSaltGeneration));
+       suite.addTest(new CppUnit::TestCaller<CryptTest>(
+               "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 0000000..ee208ad
--- /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@xxxxxxxxxxxx
+ */
+
+
+#ifndef CRYPT_TEST_H
+#define CRYPT_TEST_H
+
+
+#include <TestCase.h>
+#include <TestSuite.h>
+
+
+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 b62c971..fbd2c4f 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 0000000..c7c32b5
--- /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@xxxxxxxxxxxx
+ */
+
+
+#include <TestSuite.h>
+#include <TestSuiteAddon.h>
+
+#include "CryptTest.h"
+
+
+BTestSuite*
+getTestSuite()
+{
+       BTestSuite* suite = new BTestSuite("LibRootPosix");
+       CryptTest::AddTests(*suite);
+       return suite;
+}


Other related posts:

  • » [haiku-commits] haiku: hrev50881 - in src: system/libroot/posix/crypt tests/system/libroot/posix - axeld