Implement scrypt-based password hashing
Signed-off-by: Axel Dörfler <[email protected]>
This commit is contained in:
committed by
Axel Dörfler
parent
108c68dc82
commit
f31b1a2faf
@@ -1420,6 +1420,15 @@ AboutView::_CreateCreditsView()
|
|||||||
_AddCopyrightsFromAttribute();
|
_AddCopyrightsFromAttribute();
|
||||||
_AddPackageCreditEntries();
|
_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);
|
return new CropView(creditsScroller, 0, 1, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ main(int argc, const char* const* argv)
|
|||||||
memset(repeatedPassword, 0, sizeof(repeatedPassword));
|
memset(repeatedPassword, 0, sizeof(repeatedPassword));
|
||||||
|
|
||||||
// crypt it
|
// crypt it
|
||||||
encryptedPassword = crypt(password, user);
|
encryptedPassword = crypt(password, NULL);
|
||||||
memset(password, 0, sizeof(password));
|
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.AddInt32("last changed", time(NULL)) != B_OK
|
||||||
|| message.AddString("password", "x") != B_OK
|
|| message.AddString("password", "x") != B_OK
|
||||||
|| message.AddString("shadow password", encryptedPassword) != 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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
void
|
||||||
PasswordWindow::MessageReceived(BMessage* message)
|
PasswordWindow::MessageReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
@@ -196,9 +161,7 @@ PasswordWindow::MessageReceived(BMessage* message)
|
|||||||
alert->Go();
|
alert->Go();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const char* salt = _SanitizeSalt(fPasswordControl->Text());
|
fSettings.SetPassword(crypt(fPasswordControl->Text(), NULL));
|
||||||
fSettings.SetPassword(crypt(fPasswordControl->Text(), salt));
|
|
||||||
delete[] salt;
|
|
||||||
} else
|
} else
|
||||||
fSettings.SetPassword("");
|
fSettings.SetPassword("");
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void _Setup();
|
void _Setup();
|
||||||
char* _SanitizeSalt(const char* password);
|
|
||||||
|
|
||||||
BRadioButton* fUseCustom;
|
BRadioButton* fUseCustom;
|
||||||
BRadioButton* fUseNetwork;
|
BRadioButton* fUseNetwork;
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
$(librootNoDebugObjects)
|
$(librootNoDebugObjects)
|
||||||
[ TargetStaticLibsupc++ ]
|
[ TargetStaticLibsupc++ ]
|
||||||
[ TargetLibgcc ]
|
[ TargetLibgcc ]
|
||||||
|
shared
|
||||||
;
|
;
|
||||||
|
|
||||||
# Use the standard libroot.so soname, so when the debug version is
|
# Use the standard libroot.so soname, so when the debug version is
|
||||||
@@ -99,6 +100,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
$(librootDebugObjects)
|
$(librootDebugObjects)
|
||||||
[ TargetStaticLibsupc++ ]
|
[ TargetStaticLibsupc++ ]
|
||||||
[ TargetLibgcc ]
|
[ TargetLibgcc ]
|
||||||
|
shared
|
||||||
;
|
;
|
||||||
|
|
||||||
StaticLibrary [ MultiArchDefaultGristFiles libm.a ] : empty.c ;
|
StaticLibrary [ MultiArchDefaultGristFiles libm.a ] : empty.c ;
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
SubDir HAIKU_TOP src system libroot posix crypt ;
|
SubDir HAIKU_TOP src system libroot posix crypt ;
|
||||||
|
|
||||||
|
UsePrivateHeaders shared ;
|
||||||
|
UsePrivateSystemHeaders ;
|
||||||
|
|
||||||
local architectureObject ;
|
local architectureObject ;
|
||||||
for architectureObject in [ MultiArchSubDirSetup ] {
|
for architectureObject in [ MultiArchSubDirSetup ] {
|
||||||
on $(architectureObject) {
|
on $(architectureObject) {
|
||||||
@@ -11,8 +14,12 @@ for architectureObject in [ MultiArchSubDirSetup ] {
|
|||||||
: -Wall -Wmissing-prototypes -Wsign-compare ] ;
|
: -Wall -Wmissing-prototypes -Wsign-compare ] ;
|
||||||
|
|
||||||
MergeObject <$(architecture)>posix_crypt.o :
|
MergeObject <$(architecture)>posix_crypt.o :
|
||||||
crypt.c
|
crypt_legacy.c
|
||||||
crypt_util.c
|
crypt_legacy_util.c
|
||||||
|
crypto_scrypt_smix.cpp
|
||||||
|
crypto_scrypt.cpp
|
||||||
|
crypt.cpp
|
||||||
|
pbkdf2.cpp
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Andrew Aldridge, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
@@ -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
|
||||||
+5
-15
@@ -24,6 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "crypt_legacy.h"
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -426,7 +427,7 @@ void init_des()
|
|||||||
sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1];
|
sb[sg][inx+1] = eperm32tab[0][(to_permute >> 24) & 0xff][1];
|
||||||
sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0];
|
sb[sg][inx ] |= eperm32tab[1][(to_permute >> 16) & 0xff][0];
|
||||||
sb[sg][inx+1] |= eperm32tab[1][(to_permute >> 16) & 0xff][1];
|
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+1] |= eperm32tab[2][(to_permute >> 8) & 0xff][1];
|
||||||
sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0];
|
sb[sg][inx ] |= eperm32tab[3][(to_permute) & 0xff][0];
|
||||||
sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1];
|
sb[sg][inx+1] |= eperm32tab[3][(to_permute) & 0xff][1];
|
||||||
@@ -439,7 +440,7 @@ void init_des()
|
|||||||
sb[sg][inx] |=
|
sb[sg][inx] |=
|
||||||
((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) |
|
((long64)eperm32tab[1][(to_permute >> 16) & 0xff][0] << 32) |
|
||||||
(long64)eperm32tab[1][(to_permute >> 16) & 0xff][1];
|
(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][0] << 32) |
|
||||||
(long64)eperm32tab[2][(to_permute >> 8) & 0xff][1];
|
(long64)eperm32tab[2][(to_permute >> 8) & 0xff][1];
|
||||||
sb[sg][inx] |=
|
sb[sg][inx] |=
|
||||||
@@ -727,8 +728,8 @@ ufc_long *_ufc_doit();
|
|||||||
* UNIX crypt function
|
* UNIX crypt function
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char *crypt(key, salt)
|
char *crypt_legacy(key, salt)
|
||||||
char *key, *salt;
|
const char *key, *salt;
|
||||||
{ ufc_long *s;
|
{ ufc_long *s;
|
||||||
char ktab[9];
|
char ktab[9];
|
||||||
|
|
||||||
@@ -760,17 +761,6 @@ char *crypt(key, salt)
|
|||||||
return output_conversion(s[0], s[1], 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
|
* UNIX encrypt function. Takes a bitvector
|
||||||
* represented by one byte per bit and
|
* represented by one byte per bit and
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
@@ -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_ */
|
||||||
@@ -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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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_ */
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
@@ -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_ */
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Andrew Aldridge, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Andrew Aldridge, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -73,6 +73,13 @@ SimpleTest test_wcfuncs : test_wcfuncs.c ;
|
|||||||
SimpleTest test_wctype : test_wctype.c ;
|
SimpleTest test_wctype : test_wctype.c ;
|
||||||
SimpleTest wcs_test : wcs_test.cpp ;
|
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 math ;
|
||||||
SubInclude HAIKU_TOP src tests system libroot posix string ;
|
SubInclude HAIKU_TOP src tests system libroot posix string ;
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Andrew Aldridge, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <TestSuite.h>
|
||||||
|
#include <TestSuiteAddon.h>
|
||||||
|
|
||||||
|
#include "CryptTest.h"
|
||||||
|
|
||||||
|
|
||||||
|
BTestSuite*
|
||||||
|
getTestSuite()
|
||||||
|
{
|
||||||
|
BTestSuite* suite = new BTestSuite("LibRootPosix");
|
||||||
|
CryptTest::AddTests(*suite);
|
||||||
|
return suite;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user