-
-
Notifications
You must be signed in to change notification settings - Fork 349
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement scrypt-based password hashing
Signed-off-by: Axel Dörfler <axeld@pinc-software.de>
- Loading branch information
Showing
20 changed files
with
1,328 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
/* | ||
* Copyright 2017, Haiku, Inc. All Rights Reserved. | ||
* Distributed under the terms of the MIT License. | ||
* | ||
* Authors: | ||
* Andrew Aldridge, i80and@foxquill.com | ||
*/ | ||
|
||
|
||
#include <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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.