Initial import: ultra-small bruteforce tool, docs, and .gitignore

This commit is contained in:
2025-07-04 23:43:25 +00:00
parent 15a5f50365
commit 3b51303ab6
21 changed files with 6334 additions and 59 deletions

26
brute/source/Dockerfile Normal file
View File

@@ -0,0 +1,26 @@
FROM alpine:latest AS build
RUN apk add --no-cache build-base musl-dev linux-headers upx
WORKDIR /src
# Copy all yescrypt source and header files flat
COPY yescrypt/*.h .
COPY yescrypt/yescrypt-ref.c .
COPY yescrypt/yescrypt-common.c .
COPY yescrypt/sha256.c .
COPY yescrypt/insecure_memzero.c .
COPY bruteforce.c .
RUN gcc -static -Os -s -o bruteforce \
bruteforce.c \
yescrypt-ref.c \
yescrypt-common.c \
sha256.c \
insecure_memzero.c \
&& strip --strip-all --remove-section=.comment bruteforce \
&& upx --ultra-brute bruteforce
FROM scratch
COPY --from=build /src/bruteforce /
ENTRYPOINT ["/bruteforce"]

392
brute/source/bruteforce.c Normal file
View File

@@ -0,0 +1,392 @@
#include <unistd.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
// Include yescrypt implementation
#include "yescrypt.h"
#define BUF_SIZE 4096
#define MAX_LINE 1024
#define MAX_PASS 256
// Minimal strlen
static int my_strlen(const char *s) { int n=0; while(s[n]) n++; return n; }
// Minimal strncmp
static int my_strncmp(const char *a, const char *b, int n) { for(int i=0;i<n;i++) if(a[i]!=b[i]||!a[i]||!b[i]) return a[i]-b[i]; return 0; }
// Write string to stderr
static void write_stderr(const char *s) {
syscall(SYS_write, 2, s, my_strlen(s));
}
// Write string to stdout
static void write_stdout(const char *s) {
syscall(SYS_write, 1, s, my_strlen(s));
}
// Find position of substring in string
static int strpos(const char *string, const char *substring, int offset) {
int string_len = my_strlen(string);
int sub_len = my_strlen(substring);
for(int i = offset; i <= string_len - sub_len; i++) {
int j;
for(j = 0; j < sub_len; j++) {
if(string[i + j] != substring[j]) break;
}
if(j == sub_len) return i;
}
return -1;
}
// Read a line from fd into buf, return length or 0 on EOF
static int read_line(int fd, char *buf, int max) {
int i=0, r;
char c;
while(i<max-1) {
r = syscall(SYS_read, fd, &c, 1);
if(r<=0) break;
if(c=='\n') break;
buf[i++] = c;
}
buf[i]=0;
return i;
}
// Extract user hash from shadow line
static char* extract_user_hash(const char *shadow_line, const char *username) {
int username_index = strpos(shadow_line, username, 0);
if(username_index == -1) return NULL;
// Find the start of hash (after username:)
int hash_start = username_index + my_strlen(username) + 1;
int hash_end = strpos(shadow_line, ":", hash_start);
if(hash_end == -1) return NULL;
int hash_len = hash_end - hash_start;
char *user_hash = malloc(hash_len + 1);
memcpy(user_hash, shadow_line + hash_start, hash_len);
user_hash[hash_len] = 0;
return user_hash;
}
// Parse hash to extract algorithm ID, salt, and hash value
static void parse_hash(const char *user_hash, int *hash_id, char *salt, char *hash_value) {
// Find positions of $ characters
int first_dollar = strpos(user_hash, "$", 0);
if(first_dollar == -1) return;
int second_dollar = strpos(user_hash, "$", first_dollar + 1);
if(second_dollar == -1) return;
int third_dollar = strpos(user_hash, "$", second_dollar + 1);
if(third_dollar == -1) return;
// Extract hash ID (algorithm)
int id_len = second_dollar - first_dollar - 1;
char id_str[8] = {0};
memcpy(id_str, user_hash + first_dollar + 1, id_len);
// Handle yescrypt (y) and numeric IDs
if(id_len == 1 && id_str[0] == 'y') {
*hash_id = 'y'; // yescrypt
// For yescrypt, we need to find the 4th $ to get the actual salt
int fourth_dollar = strpos(user_hash, "$", third_dollar + 1);
if(fourth_dollar == -1) return;
// Extract parameters (between 2nd and 3rd $)
int param_len = third_dollar - second_dollar - 1;
char parameters[64] = {0};
memcpy(parameters, user_hash + second_dollar + 1, param_len);
parameters[param_len] = 0;
// Extract salt (between 3rd and 4th $)
int salt_len = fourth_dollar - third_dollar - 1;
memcpy(salt, user_hash + third_dollar + 1, salt_len);
salt[salt_len] = 0;
// Extract hash value (after 4th $)
int hash_len = my_strlen(user_hash) - fourth_dollar - 1;
memcpy(hash_value, user_hash + fourth_dollar + 1, hash_len);
hash_value[hash_len] = 0;
// For yescrypt, we need to include parameters in the salt for crypt()
char combined_salt[128];
int len = 0;
combined_salt[len++] = '$';
combined_salt[len++] = 'y';
combined_salt[len++] = '$';
memcpy(combined_salt + len, parameters, param_len);
len += param_len;
combined_salt[len++] = '$';
memcpy(combined_salt + len, salt, salt_len);
len += salt_len;
combined_salt[len] = 0;
// Copy the combined salt back to the salt parameter
memcpy(salt, combined_salt, len + 1);
} else {
*hash_id = atoi(id_str);
// Extract salt (standard format)
int salt_len = third_dollar - second_dollar - 1;
memcpy(salt, user_hash + second_dollar + 1, salt_len);
salt[salt_len] = 0;
// Extract hash value
int hash_len = my_strlen(user_hash) - third_dollar - 1;
memcpy(hash_value, user_hash + third_dollar + 1, hash_len);
hash_value[hash_len] = 0;
}
}
// Create formatted salt string for crypt()
static char* create_salt(int hash_id, const char *salt) {
char *formatted_salt = malloc(128);
int len = 0;
if(hash_id == 'y') {
// For yescrypt, the salt is already properly formatted
int salt_len = my_strlen(salt);
memcpy(formatted_salt, salt, salt_len);
formatted_salt[salt_len] = 0;
} else {
// Standard format for other algorithms
formatted_salt[len++] = '$';
if(hash_id == 1) {
formatted_salt[len++] = '1';
} else if(hash_id == 5) {
formatted_salt[len++] = '5';
} else if(hash_id == 6) {
formatted_salt[len++] = '6';
} else {
// Default to SHA512
formatted_salt[len++] = '6';
}
formatted_salt[len++] = '$';
int salt_len = my_strlen(salt);
memcpy(formatted_salt + len, salt, salt_len);
len += salt_len;
formatted_salt[len] = 0;
}
return formatted_salt;
}
// Minimal itoa for positive integers
static void my_itoa(int value, char *buf) {
char tmp[16];
int i = 0, j = 0;
if (value == 0) { buf[0] = '0'; buf[1] = 0; return; }
while (value > 0) { tmp[i++] = '0' + (value % 10); value /= 10; }
while (i > 0) { buf[j++] = tmp[--i]; }
buf[j] = 0;
}
// Custom yescrypt crypt function using reference implementation parsing
static char* yescrypt_crypt(const char *password, const char *full_hash) {
static char result[128];
// Use the reference implementation's yescrypt function
uint8_t *generated_hash = yescrypt((const uint8_t *)password, (const uint8_t *)full_hash);
if (!generated_hash) {
return NULL;
}
// Compare the generated hash with the expected hash
if (strcmp((char *)generated_hash, full_hash) == 0) {
// Copy the generated hash to our result buffer
int len = strlen((char *)generated_hash);
if (len < sizeof(result)) {
memcpy(result, generated_hash, len + 1);
return result;
}
}
return NULL;
}
int main(int argc, char **argv) {
if(argc<3) {
write_stderr("Usage: ");
write_stderr(argv[0]);
write_stderr(" <username> <wordlist>\n");
return 1;
}
char *username = argv[1];
char *wordlist_path = argv[2];
const char *shadow_path = "/etc/shadow";
int sfd = syscall(SYS_open, shadow_path, O_RDONLY, 0);
if(sfd<0) {
write_stderr("Failed to open shadow file: ");
write_stderr(shadow_path);
write_stderr("\n");
return 2;
}
char line[MAX_LINE];
char *user_hash = NULL;
while(read_line(sfd, line, MAX_LINE)) {
user_hash = extract_user_hash(line, username);
if(user_hash) break;
}
syscall(SYS_close, sfd);
if(!user_hash) {
write_stderr("User '");
write_stderr(username);
write_stderr("' not found in shadow file.\n");
return 3;
}
// Parse the hash
int hash_id;
char salt[64] = {0};
char hash_value[512] = {0};
parse_hash(user_hash, &hash_id, salt, hash_value);
if(hash_id == 0) {
write_stderr("Failed to parse hash format for user '");
write_stderr(username);
write_stderr("'\n");
free(user_hash);
return 4;
}
// Print useful information
write_stderr("Target user: ");
write_stderr(username);
write_stderr("\n");
write_stderr("Hash type: ");
if(hash_id == 'y') {
write_stderr("yescrypt");
} else if(hash_id == 1) {
write_stderr("MD5");
} else if(hash_id == 5) {
write_stderr("SHA256");
} else if(hash_id == 6) {
write_stderr("SHA512");
} else {
char id_str[8];
my_itoa(hash_id, id_str);
write_stderr(id_str);
}
write_stderr("\n");
write_stderr("Full hash: ");
write_stderr(user_hash);
write_stderr("\n");
write_stderr("Starting bruteforce...\n");
// Create formatted salt for crypt()
char *formatted_salt = create_salt(hash_id, salt);
int wfd = syscall(SYS_open, wordlist_path, O_RDONLY, 0);
if(wfd<0) {
write_stderr("Failed to open wordlist: ");
write_stderr(wordlist_path);
write_stderr("\n");
free(user_hash);
free(formatted_salt);
return 5;
}
char pass[MAX_PASS];
int found=0;
char c;
int n=0;
int total_tried=0;
while(syscall(SYS_read, wfd, &c, 1) == 1) {
if(c == '\n' || c == '\r') {
if(n > 0) {
pass[n] = 0;
total_tried++;
// Show progress every 1000 attempts
if(total_tried % 1000 == 0) {
char progress_str[32];
write_stderr("Tried ");
my_itoa(total_tried, progress_str);
write_stderr(progress_str);
write_stderr(" passwords...\n");
}
char *try_hash;
if(hash_id == 'y') {
// Use yescrypt for yescrypt hashes
try_hash = yescrypt_crypt(pass, user_hash);
} else {
// Use system crypt() for other hash types
try_hash = crypt(pass, formatted_salt);
}
if(try_hash && strcmp(try_hash, user_hash)==0) {
write_stdout("Found password: ");
write_stdout(pass);
write_stdout("\n");
found=1;
break;
}
n = 0;
}
} else if(n < MAX_PASS-1) {
pass[n++] = c;
}
}
// Handle last line if no newline at end
if(n > 0 && !found) {
pass[n] = 0;
total_tried++;
char *try_hash;
if(hash_id == 'y') {
// Use yescrypt for yescrypt hashes
try_hash = yescrypt_crypt(pass, user_hash);
} else {
// Use system crypt() for other hash types
try_hash = crypt(pass, formatted_salt);
}
if(try_hash && strcmp(try_hash, user_hash)==0) {
write_stdout("Found password: ");
write_stdout(pass);
write_stdout("\n");
found=1;
}
}
syscall(SYS_close, wfd);
// Print final summary
char total_str[32];
write_stderr("Total passwords tried: ");
my_itoa(total_tried, total_str);
write_stderr(total_str);
write_stderr("\n");
if(!found) {
write_stderr("No password match found for user '");
write_stderr(username);
write_stderr("' in wordlist.\n");
} else {
write_stderr("Password successfully cracked!\n");
}
free(user_hash);
free(formatted_salt);
return found?0:6;
}

View File

@@ -0,0 +1,85 @@
# Copyright 2013-2018 Alexander Peslyak
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted.
#
# 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.
CC = gcc
LD = $(CC)
RM = rm -f
OMPFLAGS = -fopenmp
OMPFLAGS_MAYBE = $(OMPFLAGS)
#CFLAGS = -Wall -O2 -fomit-frame-pointer $(OMPFLAGS_MAYBE) -DSKIP_MEMZERO
CFLAGS = -Wall -O2 -march=native -fomit-frame-pointer $(OMPFLAGS_MAYBE) -DSKIP_MEMZERO
#CFLAGS = -Wall -O2 -funroll-loops -fomit-frame-pointer $(OMPFLAGS_MAYBE) -DSKIP_MEMZERO
#CFLAGS = -Wall -O2 -march=native -funroll-loops -fomit-frame-pointer $(OMPFLAGS_MAYBE) -DSKIP_MEMZERO
# -lrt is for userom's use of clock_gettime()
LDFLAGS = -s -lrt $(OMPFLAGS_MAYBE)
PROJ = tests phc-test initrom userom
OBJS_CORE = yescrypt-opt.o
OBJS_COMMON = yescrypt-common.o sha256.o insecure_memzero.o
OBJS_TESTS = $(OBJS_CORE) $(OBJS_COMMON) tests.o
OBJS_PHC = $(OBJS_CORE) $(OBJS_COMMON) phc-test.o
OBJS_INITROM = $(OBJS_CORE) $(OBJS_COMMON) initrom.o
OBJS_USEROM = $(OBJS_CORE) $(OBJS_COMMON) userom.o
OBJS_RM = yescrypt-*.o
all: $(PROJ)
check: tests phc-test
@echo 'Running main tests'
@time ./tests | tee TESTS-OUT
@diff -U0 TESTS-OK TESTS-OUT && echo PASSED || echo FAILED
@if [ -f PHC-TEST-OK-SHA256 ]; then \
echo 'Running PHC tests'; \
time ./phc-test > PHC-TEST-OUT; \
sha256sum -c PHC-TEST-OK-SHA256 || shasum -a 256 -c PHC-TEST-OK-SHA256; \
fi
ref:
$(MAKE) $(PROJ) OBJS_CORE=yescrypt-ref.o
check-ref:
$(MAKE) check OBJS_CORE=yescrypt-ref.o
tests: $(OBJS_TESTS)
$(LD) $(LDFLAGS) $(OBJS_TESTS) -o $@
phc-test.o: phc.c
$(CC) -c $(CFLAGS) -DTEST phc.c -o $@
phc-test: $(OBJS_PHC)
$(LD) $(LDFLAGS) $(OBJS_PHC) -o $@
initrom: $(OBJS_INITROM)
$(LD) $(LDFLAGS) $(OBJS_INITROM) -o $@
userom: $(OBJS_USEROM)
$(LD) $(LDFLAGS) $(OMPFLAGS) $(OBJS_USEROM) -o $@
userom.o: userom.c
$(CC) -c $(CFLAGS) $(OMPFLAGS) $*.c
.c.o:
$(CC) -c $(CFLAGS) $*.c
yescrypt-opt.o: yescrypt-platform.c
clean:
$(RM) $(PROJ)
$(RM) $(OBJS_TESTS) $(OBJS_PHC) $(OBJS_INITROM) $(OBJS_USEROM)
$(RM) $(OBJS_RM)
$(RM) TESTS-OUT PHC-TEST-OUT

View File

@@ -0,0 +1,217 @@
/*-
* Copyright 2013-2018 Alexander Peslyak
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* 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.
*/
#define YESCRYPT_FLAGS YESCRYPT_DEFAULTS
#define ROM_SHM_KEY 0x7965730a
#define ROM_LOCAL_PARAM "change this before use"
/* Maximum parallelism factor during ROM initialization */
#define YESCRYPT_PROM_SHM 112
#define YESCRYPT_PROM_FILE 4
//#define USE_HUGEPAGE
//#define DUMP_SHARED
#include <errno.h>
#include <stdio.h>
#include <stdlib.h> /* for atoi() */
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "yescrypt.h"
int main(int argc, const char * const *argv)
{
#if 0
uint64_t rom_bytes = 112 * (1024ULL*1024*1024);
uint64_t ram_bytes = 1 * (1024ULL*1024);
#else
uint64_t rom_bytes = 3 * (1024ULL*1024*1024);
uint64_t ram_bytes = 2 * (1024ULL*1024);
#endif
uint32_t r, min_r;
uint64_t NROM_log2, N_log2;
int shmid;
yescrypt_shared_t shared;
yescrypt_binary_t *digest;
const char *rom_filename = NULL;
int rom_fd;
if (argc > 1)
rom_bytes = atoi(argv[1]) * (1024ULL*1024*1024);
if (argc > 2)
ram_bytes = atoi(argv[2]) * (1024ULL*1024);
if (argc > 3)
rom_filename = argv[3];
if (!rom_bytes) {
puts("Wrong ROM size requested");
return 1;
}
min_r = 9;
if (rom_filename)
min_r = 8 * 256;
NROM_log2 = 0;
while (((rom_bytes >> NROM_log2) & 0xff) == 0)
NROM_log2++;
r = rom_bytes >> (7 + NROM_log2);
while (r < min_r && NROM_log2 > 0) {
r <<= 1;
NROM_log2--;
}
rom_bytes = (uint64_t)r << (7 + NROM_log2);
N_log2 = 3;
while (((uint64_t)r << (7 + N_log2)) < ram_bytes)
N_log2++;
ram_bytes = (uint64_t)r << (7 + N_log2);
printf("r=%u N=2^%u NROM=2^%u\n", r,
(unsigned int)N_log2, (unsigned int)NROM_log2);
printf("Will use %.2f KiB ROM\n", rom_bytes / 1024.0);
printf(" %.2f KiB RAM\n", ram_bytes / 1024.0);
shared.aligned_size = rom_bytes;
if (rom_filename) {
rom_fd = open(rom_filename, O_CREAT|O_RDWR|O_EXCL,
S_IRUSR|S_IRGRP|S_IWUSR);
if (rom_fd < 0) {
perror("open");
return 1;
}
if (ftruncate(rom_fd, rom_bytes)) {
perror("ftruncate");
close(rom_fd);
unlink(rom_filename);
return 1;
}
int flags =
#ifdef MAP_NOCORE
MAP_NOCORE |
#endif
#if defined(MAP_HUGETLB) && defined(USE_HUGEPAGE)
MAP_HUGETLB |
#endif
MAP_SHARED;
void *p = mmap(NULL, rom_bytes, PROT_READ | PROT_WRITE,
flags, rom_fd, 0);
#if defined(MAP_HUGETLB) && defined(USE_HUGEPAGE)
if (p == MAP_FAILED)
p = mmap(NULL, rom_bytes, PROT_READ | PROT_WRITE,
flags & ~MAP_HUGETLB, rom_fd, 0);
#endif
if (p == MAP_FAILED) {
perror("mmap");
close(rom_fd);
unlink(rom_filename);
return 1;
}
close(rom_fd);
shared.base = shared.aligned = p;
} else {
shmid = shmget(ROM_SHM_KEY, shared.aligned_size,
#ifdef SHM_HUGETLB
SHM_HUGETLB |
#endif
IPC_CREAT|IPC_EXCL | S_IRUSR|S_IRGRP|S_IWUSR);
if (shmid == -1) {
#ifdef SHM_HUGETLB
perror("shmget");
puts("Retrying without SHM_HUGETLB");
shmid = shmget(ROM_SHM_KEY, shared.aligned_size,
IPC_CREAT|IPC_EXCL | S_IRUSR|S_IRGRP|S_IWUSR);
#endif
if (shmid == -1) {
perror("shmget");
return 1;
}
}
shared.base = shared.aligned = shmat(shmid, NULL, 0);
if (shared.base == (void *)-1) {
int save_errno = errno;
shmctl(shmid, IPC_RMID, NULL);
errno = save_errno;
perror("shmat");
return 1;
}
}
printf("Initializing ROM ...");
fflush(stdout);
yescrypt_params_t rom_params = {
.flags = YESCRYPT_DEFAULTS | YESCRYPT_SHARED_PREALLOCATED,
.NROM = (uint64_t)1 << NROM_log2,
.r = r,
.p = rom_filename ? YESCRYPT_PROM_FILE : YESCRYPT_PROM_SHM };
if (yescrypt_init_shared(&shared,
(uint8_t *)ROM_LOCAL_PARAM, strlen(ROM_LOCAL_PARAM),
&rom_params)) {
puts(" FAILED");
if (rom_filename)
unlink(rom_filename);
return 1;
}
#ifdef DUMP_SHARED
fwrite(shared.aligned, shared.aligned_size, 1, stderr);
#endif
digest = yescrypt_digest_shared(&shared);
printf(" DONE (%02x%02x%02x%02x)\n",
digest->uc[0], digest->uc[1], digest->uc[2], digest->uc[3]);
{
yescrypt_local_t local;
const uint8_t *setting;
uint8_t hash[128];
if (yescrypt_init_local(&local)) {
puts("yescrypt_init_local() FAILED");
return 1;
}
yescrypt_params_t params = rom_params;
params.flags = YESCRYPT_FLAGS;
params.N = (uint64_t)1 << N_log2;
params.p = 1;
setting = yescrypt_encode_params(&params,
(const uint8_t *)"WZaPV7LSUEKMo34.", 16);
printf("'%s'\n", (char *)yescrypt_r(&shared, &local,
(const uint8_t *)"pleaseletmein", 13, setting, NULL,
hash, sizeof(hash)));
}
if (rom_filename && munmap(shared.base, rom_bytes)) {
perror("munmap");
return 1;
}
return 0;
}

View File

@@ -0,0 +1,49 @@
/*-
* Copyright 2014 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.
*/
#ifndef SKIP_MEMZERO
#include <stddef.h>
#include <stdint.h>
#include "insecure_memzero.h"
/* Function which does the zeroing. */
static void
insecure_memzero_func(volatile void * buf, size_t len)
{
volatile uint8_t * _buf = 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;
#endif

View File

@@ -0,0 +1,69 @@
/*-
* Copyright 2014 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.
*/
#ifndef _INSECURE_MEMZERO_H_
#define _INSECURE_MEMZERO_H_
#ifdef SKIP_MEMZERO
#define insecure_memzero(buf, len) /* empty */
#else
#include <stddef.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);
}
#endif
#endif /* !_INSECURE_MEMZERO_H_ */

145
brute/source/yescrypt/phc.c Normal file
View File

@@ -0,0 +1,145 @@
/*-
* Copyright 2014-2016,2018 Alexander Peslyak
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* 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.
*/
#define YESCRYPT_FLAGS YESCRYPT_DEFAULTS
#define YESCRYPT_BASE_N 8
#define YESCRYPT_R 8
#define YESCRYPT_P 1
#include "yescrypt.h"
#ifdef TEST
static
#endif
int PHS(void *out, size_t outlen, const void *in, size_t inlen,
const void *salt, size_t saltlen, unsigned int t_cost, unsigned int m_cost)
{
yescrypt_local_t local;
yescrypt_params_t params = {
.flags = YESCRYPT_FLAGS,
.N = (uint64_t)YESCRYPT_BASE_N << m_cost,
.r = YESCRYPT_R,
.p = YESCRYPT_P,
.t = t_cost,
.g = 0 };
int retval;
if (yescrypt_init_local(&local))
return -1;
retval = yescrypt_kdf(NULL, &local, in, inlen, salt, saltlen, &params,
out, outlen);
if (yescrypt_free_local(&local))
return -1;
return retval;
}
#ifdef TEST
#include <stdio.h>
#include <unistd.h> /* for sysconf() */
#include <sys/times.h>
static void print_hex(const uint8_t *buf, size_t buflen, const char *sep)
{
size_t i;
putchar('"');
for (i = 0; i < buflen; i++)
printf("\\x%02x", buf[i]);
printf("\"%s", sep);
}
static void print_PHS(const void *in, size_t inlen,
const void *salt, size_t saltlen, unsigned int t_cost, unsigned int m_cost)
{
uint8_t dk[32];
printf("PHS(");
print_hex(in, inlen, ", ");
print_hex(salt, saltlen, ", ");
printf("%u, %u) = ", t_cost, m_cost);
if (PHS(dk, sizeof(dk), in, inlen, salt, saltlen, t_cost, m_cost)) {
puts("FAILED");
return;
}
print_hex(dk, sizeof(dk), "\n");
}
static void print_all_PHS(unsigned int t_cost, unsigned int m_cost)
{
clock_t clk_tck = sysconf(_SC_CLK_TCK);
struct tms start_tms, end_tms;
clock_t start = times(&start_tms), end, start_v, end_v;
const size_t count = 0x102;
size_t inlen, i, j;
inlen = 0;
for (i = 0; i < count; i++) {
uint8_t in[128], salt[16];
for (j = 0; j < inlen; j++)
in[j] = (i + j) & 0xff;
for (j = 0; j < sizeof(salt); j++)
salt[j] = ~(i + j) & 0xff;
print_PHS(in, inlen, salt, sizeof(salt), t_cost, m_cost);
if (++inlen > sizeof(in))
inlen = 0;
}
end = times(&end_tms);
start_v = start_tms.tms_utime + start_tms.tms_stime +
start_tms.tms_cutime + start_tms.tms_cstime;
end_v = end_tms.tms_utime + end_tms.tms_stime +
end_tms.tms_cutime + end_tms.tms_cstime;
if (end == start)
end++;
if (end_v == start_v)
end_v++;
fprintf(stderr, "m_cost=%u (%.0f KiB), t_cost=%u\n"
"%llu c/s real, %llu c/s virtual (%llu hashes in %.2f seconds)\n",
m_cost, (YESCRYPT_BASE_N << m_cost) * YESCRYPT_R / 8.0, t_cost,
(unsigned long long)count * clk_tck / (end - start),
(unsigned long long)count * clk_tck / (end_v - start_v),
(unsigned long long)count, (double)(end - start) / clk_tck);
}
int main(void)
{
#if 0
setvbuf(stdout, NULL, _IOLBF, 0);
#endif
print_all_PHS(0, 0);
print_all_PHS(0, 7);
print_all_PHS(0, 8);
print_all_PHS(1, 8);
print_all_PHS(2, 8);
print_all_PHS(3, 8);
print_all_PHS(0, 11);
return 0;
}
#endif

View File

@@ -0,0 +1,652 @@
/*-
* Copyright 2005-2016 Colin Percival
* Copyright 2016-2018,2021 Alexander Peslyak
* 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 "insecure_memzero.h"
#include "sysendian.h"
#include "sha256.h"
#ifdef __ICC
/* Miscompile with icc 14.0.0 (at least), so don't use restrict there */
#define restrict
#elif __STDC_VERSION__ >= 199901L
/* Have restrict */
#elif defined(__GNUC__)
#define restrict __restrict
#else
#define restrict
#endif
/*
* Encode a length len*2 vector of (uint32_t) into a length len*8 vector of
* (uint8_t) in big-endian form.
*/
static void
be32enc_vect(uint8_t * dst, const uint32_t * src, size_t len)
{
/* Encode vector, two words at a time. */
do {
be32enc(&dst[0], src[0]);
be32enc(&dst[4], src[1]);
src += 2;
dst += 8;
} while (--len);
}
/*
* Decode a big-endian length len*8 vector of (uint8_t) into a length
* len*2 vector of (uint32_t).
*/
static void
be32dec_vect(uint32_t * dst, const uint8_t * src, size_t len)
{
/* Decode vector, two words at a time. */
do {
dst[0] = be32dec(&src[0]);
dst[1] = be32dec(&src[4]);
src += 8;
dst += 2;
} while (--len);
}
/* SHA256 round constants. */
static const uint32_t Krnd[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
/* Elementary functions used by SHA256 */
#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
#if 1 /* Explicit caching/reuse of common subexpression between rounds */
#define Maj(x, y, z) (y ^ ((x_xor_y = x ^ y) & y_xor_z))
#else /* Let the compiler cache/reuse or not */
#define Maj(x, y, z) (y ^ ((x ^ y) & (y ^ z)))
#endif
#define SHR(x, n) (x >> n)
#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
/* SHA256 round function */
#define RND(a, b, c, d, e, f, g, h, k) \
h += S1(e) + Ch(e, f, g) + k; \
d += h; \
h += S0(a) + Maj(a, b, c); \
y_xor_z = x_xor_y;
/* Adjusted round function for rotating state */
#define RNDr(S, W, i, ii) \
RND(S[(64 - i) % 8], S[(65 - i) % 8], \
S[(66 - i) % 8], S[(67 - i) % 8], \
S[(68 - i) % 8], S[(69 - i) % 8], \
S[(70 - i) % 8], S[(71 - i) % 8], \
W[i + ii] + Krnd[i + ii])
/* Message schedule computation */
#define MSCH(W, ii, i) \
W[i + ii + 16] = s1(W[i + ii + 14]) + W[i + ii + 9] + s0(W[i + ii + 1]) + W[i + ii]
/*
* SHA256 block compression function. The 256-bit state is transformed via
* the 512-bit input block to produce a new state.
*/
static void
SHA256_Transform(uint32_t state[static restrict 8],
const uint8_t block[static restrict 64],
uint32_t W[static restrict 64], uint32_t S[static restrict 8])
{
int i;
/* 1. Prepare the first part of the message schedule W. */
be32dec_vect(W, block, 8);
/* 2. Initialize working variables. */
memcpy(S, state, 32);
/* 3. Mix. */
for (i = 0; i < 64; i += 16) {
uint32_t x_xor_y, y_xor_z = S[(65 - i) % 8] ^ S[(66 - i) % 8];
RNDr(S, W, 0, i);
RNDr(S, W, 1, i);
RNDr(S, W, 2, i);
RNDr(S, W, 3, i);
RNDr(S, W, 4, i);
RNDr(S, W, 5, i);
RNDr(S, W, 6, i);
RNDr(S, W, 7, i);
RNDr(S, W, 8, i);
RNDr(S, W, 9, i);
RNDr(S, W, 10, i);
RNDr(S, W, 11, i);
RNDr(S, W, 12, i);
RNDr(S, W, 13, i);
RNDr(S, W, 14, i);
RNDr(S, W, 15, i);
if (i == 48)
break;
MSCH(W, 0, i);
MSCH(W, 1, i);
MSCH(W, 2, i);
MSCH(W, 3, i);
MSCH(W, 4, i);
MSCH(W, 5, i);
MSCH(W, 6, i);
MSCH(W, 7, i);
MSCH(W, 8, i);
MSCH(W, 9, i);
MSCH(W, 10, i);
MSCH(W, 11, i);
MSCH(W, 12, i);
MSCH(W, 13, i);
MSCH(W, 14, i);
MSCH(W, 15, i);
}
/* 4. Mix local working variables into global state. */
state[0] += S[0];
state[1] += S[1];
state[2] += S[2];
state[3] += S[3];
state[4] += S[4];
state[5] += S[5];
state[6] += S[6];
state[7] += S[7];
}
static const uint8_t PAD[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* Add padding and terminating bit-count. */
static void
SHA256_Pad(SHA256_CTX * ctx, uint32_t tmp32[static restrict 72])
{
size_t r;
/* Figure out how many bytes we have buffered. */
r = (ctx->count >> 3) & 0x3f;
/* Pad to 56 mod 64, transforming if we finish a block en route. */
if (r < 56) {
/* Pad to 56 mod 64. */
memcpy(&ctx->buf[r], PAD, 56 - r);
} else {
/* Finish the current block and mix. */
memcpy(&ctx->buf[r], PAD, 64 - r);
SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]);
/* The start of the final block is all zeroes. */
memset(&ctx->buf[0], 0, 56);
}
/* Add the terminating bit-count. */
be64enc(&ctx->buf[56], ctx->count);
/* Mix in the final block. */
SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]);
}
/* Magic initialization constants. */
static const uint32_t initial_state[8] = {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
};
/**
* SHA256_Init(ctx):
* Initialize the SHA256 context ${ctx}.
*/
void
SHA256_Init(SHA256_CTX * ctx)
{
/* Zero bits processed so far. */
ctx->count = 0;
/* Initialize state. */
memcpy(ctx->state, initial_state, sizeof(initial_state));
}
/**
* SHA256_Update(ctx, in, len):
* Input ${len} bytes from ${in} into the SHA256 context ${ctx}.
*/
static void
_SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len,
uint32_t tmp32[static restrict 72])
{
uint32_t r;
const uint8_t * src = in;
/* Return immediately if we have nothing to do. */
if (len == 0)
return;
/* Number of bytes left in the buffer from previous updates. */
r = (ctx->count >> 3) & 0x3f;
/* Update number of bits. */
ctx->count += (uint64_t)(len) << 3;
/* Handle the case where we don't need to perform any transforms. */
if (len < 64 - r) {
memcpy(&ctx->buf[r], src, len);
return;
}
/* Finish the current block. */
memcpy(&ctx->buf[r], src, 64 - r);
SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]);
src += 64 - r;
len -= 64 - r;
/* Perform complete blocks. */
while (len >= 64) {
SHA256_Transform(ctx->state, src, &tmp32[0], &tmp32[64]);
src += 64;
len -= 64;
}
/* Copy left over data into buffer. */
memcpy(ctx->buf, src, len);
}
/* Wrapper function for intermediate-values sanitization. */
void
SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len)
{
uint32_t tmp32[72];
/* Call the real function. */
_SHA256_Update(ctx, in, len, tmp32);
/* Clean the stack. */
insecure_memzero(tmp32, 288);
}
/**
* SHA256_Final(digest, ctx):
* Output the SHA256 hash of the data input to the context ${ctx} into the
* buffer ${digest}.
*/
static void
_SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx,
uint32_t tmp32[static restrict 72])
{
/* Add padding. */
SHA256_Pad(ctx, tmp32);
/* Write the hash. */
be32enc_vect(digest, ctx->state, 4);
}
/* Wrapper function for intermediate-values sanitization. */
void
SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx)
{
uint32_t tmp32[72];
/* Call the real function. */
_SHA256_Final(digest, ctx, tmp32);
/* Clear the context state. */
insecure_memzero(ctx, sizeof(SHA256_CTX));
/* Clean the stack. */
insecure_memzero(tmp32, 288);
}
/**
* SHA256_Buf(in, len, digest):
* Compute the SHA256 hash of ${len} bytes from ${in} and write it to ${digest}.
*/
void
SHA256_Buf(const void * in, size_t len, uint8_t digest[32])
{
SHA256_CTX ctx;
uint32_t tmp32[72];
SHA256_Init(&ctx);
_SHA256_Update(&ctx, in, len, tmp32);
_SHA256_Final(digest, &ctx, tmp32);
/* Clean the stack. */
insecure_memzero(&ctx, sizeof(SHA256_CTX));
insecure_memzero(tmp32, 288);
}
/**
* HMAC_SHA256_Init(ctx, K, Klen):
* Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from
* ${K}.
*/
static void
_HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen,
uint32_t tmp32[static restrict 72], uint8_t pad[static restrict 64],
uint8_t khash[static restrict 32])
{
const uint8_t * K = _K;
size_t i;
/* If Klen > 64, the key is really SHA256(K). */
if (Klen > 64) {
SHA256_Init(&ctx->ictx);
_SHA256_Update(&ctx->ictx, K, Klen, tmp32);
_SHA256_Final(khash, &ctx->ictx, tmp32);
K = khash;
Klen = 32;
}
/* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
SHA256_Init(&ctx->ictx);
memset(pad, 0x36, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
_SHA256_Update(&ctx->ictx, pad, 64, tmp32);
/* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
SHA256_Init(&ctx->octx);
memset(pad, 0x5c, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
_SHA256_Update(&ctx->octx, pad, 64, tmp32);
}
/* Wrapper function for intermediate-values sanitization. */
void
HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
{
uint32_t tmp32[72];
uint8_t pad[64];
uint8_t khash[32];
/* Call the real function. */
_HMAC_SHA256_Init(ctx, _K, Klen, tmp32, pad, khash);
/* Clean the stack. */
insecure_memzero(tmp32, 288);
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}.
*/
static void
_HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len,
uint32_t tmp32[static restrict 72])
{
/* Feed data to the inner SHA256 operation. */
_SHA256_Update(&ctx->ictx, in, len, tmp32);
}
/* Wrapper function for intermediate-values sanitization. */
void
HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len)
{
uint32_t tmp32[72];
/* Call the real function. */
_HMAC_SHA256_Update(ctx, in, len, tmp32);
/* Clean the stack. */
insecure_memzero(tmp32, 288);
}
/**
* HMAC_SHA256_Final(digest, ctx):
* Output the HMAC-SHA256 of the data input to the context ${ctx} into the
* buffer ${digest}.
*/
static void
_HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx,
uint32_t tmp32[static restrict 72], uint8_t ihash[static restrict 32])
{
/* Finish the inner SHA256 operation. */
_SHA256_Final(ihash, &ctx->ictx, tmp32);
/* Feed the inner hash to the outer SHA256 operation. */
_SHA256_Update(&ctx->octx, ihash, 32, tmp32);
/* Finish the outer SHA256 operation. */
_SHA256_Final(digest, &ctx->octx, tmp32);
}
/* Wrapper function for intermediate-values sanitization. */
void
HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx)
{
uint32_t tmp32[72];
uint8_t ihash[32];
/* Call the real function. */
_HMAC_SHA256_Final(digest, ctx, tmp32, ihash);
/* Clean the stack. */
insecure_memzero(tmp32, 288);
insecure_memzero(ihash, 32);
}
/**
* HMAC_SHA256_Buf(K, Klen, in, len, digest):
* Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of
* length ${Klen}, and write the result to ${digest}.
*/
void
HMAC_SHA256_Buf(const void * K, size_t Klen, const void * in, size_t len,
uint8_t digest[32])
{
HMAC_SHA256_CTX ctx;
uint32_t tmp32[72];
uint8_t tmp8[96];
_HMAC_SHA256_Init(&ctx, K, Klen, tmp32, &tmp8[0], &tmp8[64]);
_HMAC_SHA256_Update(&ctx, in, len, tmp32);
_HMAC_SHA256_Final(digest, &ctx, tmp32, &tmp8[0]);
/* Clean the stack. */
insecure_memzero(&ctx, sizeof(HMAC_SHA256_CTX));
insecure_memzero(tmp32, 288);
insecure_memzero(tmp8, 96);
}
/* Add padding and terminating bit-count, but don't invoke Transform yet. */
static int
SHA256_Pad_Almost(SHA256_CTX * ctx, uint8_t len[static restrict 8],
uint32_t tmp32[static restrict 72])
{
uint32_t r;
r = (ctx->count >> 3) & 0x3f;
if (r >= 56)
return -1;
/*
* Convert length to a vector of bytes -- we do this now rather
* than later because the length will change after we pad.
*/
be64enc(len, ctx->count);
/* Add 1--56 bytes so that the resulting length is 56 mod 64. */
_SHA256_Update(ctx, PAD, 56 - r, tmp32);
/* Add the terminating bit-count. */
ctx->buf[63] = len[7];
_SHA256_Update(ctx, len, 7, tmp32);
return 0;
}
/**
* 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 Phctx, PShctx, hctx;
uint32_t tmp32[72];
union {
uint8_t tmp8[96];
uint32_t state[8];
} u;
size_t i;
uint8_t ivec[4];
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));
if (c == 1 && (dkLen & 31) == 0 && (saltlen & 63) <= 51) {
uint32_t oldcount;
uint8_t * ivecp;
/* Compute HMAC state after processing P and S. */
_HMAC_SHA256_Init(&hctx, passwd, passwdlen,
tmp32, &u.tmp8[0], &u.tmp8[64]);
_HMAC_SHA256_Update(&hctx, salt, saltlen, tmp32);
/* Prepare ictx padding. */
oldcount = hctx.ictx.count & (0x3f << 3);
_HMAC_SHA256_Update(&hctx, "\0\0\0", 4, tmp32);
if ((hctx.ictx.count & (0x3f << 3)) < oldcount ||
SHA256_Pad_Almost(&hctx.ictx, u.tmp8, tmp32))
goto generic; /* Can't happen due to saltlen check */
ivecp = hctx.ictx.buf + (oldcount >> 3);
/* Prepare octx padding. */
hctx.octx.count += 32 << 3;
SHA256_Pad_Almost(&hctx.octx, u.tmp8, tmp32);
/* Iterate through the blocks. */
for (i = 0; i * 32 < dkLen; i++) {
/* Generate INT(i + 1). */
be32enc(ivecp, (uint32_t)(i + 1));
/* Compute U_1 = PRF(P, S || INT(i)). */
memcpy(u.state, hctx.ictx.state, sizeof(u.state));
SHA256_Transform(u.state, hctx.ictx.buf,
&tmp32[0], &tmp32[64]);
be32enc_vect(hctx.octx.buf, u.state, 4);
memcpy(u.state, hctx.octx.state, sizeof(u.state));
SHA256_Transform(u.state, hctx.octx.buf,
&tmp32[0], &tmp32[64]);
be32enc_vect(&buf[i * 32], u.state, 4);
}
goto cleanup;
}
generic:
/* Compute HMAC state after processing P. */
_HMAC_SHA256_Init(&Phctx, passwd, passwdlen,
tmp32, &u.tmp8[0], &u.tmp8[64]);
/* Compute HMAC state after processing P and S. */
memcpy(&PShctx, &Phctx, sizeof(HMAC_SHA256_CTX));
_HMAC_SHA256_Update(&PShctx, salt, saltlen, tmp32);
/* Iterate through the blocks. */
for (i = 0; i * 32 < dkLen; i++) {
/* Generate INT(i + 1). */
be32enc(ivec, (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, tmp32);
_HMAC_SHA256_Final(T, &hctx, tmp32, u.tmp8);
if (c > 1) {
/* T_i = U_1 ... */
memcpy(U, T, 32);
for (j = 2; j <= c; j++) {
/* Compute U_j. */
memcpy(&hctx, &Phctx, sizeof(HMAC_SHA256_CTX));
_HMAC_SHA256_Update(&hctx, U, 32, tmp32);
_HMAC_SHA256_Final(U, &hctx, tmp32, u.tmp8);
/* ... 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 the stack. */
insecure_memzero(&Phctx, sizeof(HMAC_SHA256_CTX));
insecure_memzero(&PShctx, sizeof(HMAC_SHA256_CTX));
insecure_memzero(U, 32);
insecure_memzero(T, 32);
cleanup:
insecure_memzero(&hctx, sizeof(HMAC_SHA256_CTX));
insecure_memzero(tmp32, 288);
insecure_memzero(&u, sizeof(u));
}

View File

@@ -0,0 +1,129 @@
/*-
* Copyright 2005-2016 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.
*/
#ifndef _SHA256_H_
#define _SHA256_H_
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Use #defines in order to avoid namespace collisions with anyone else's
* SHA256 code (e.g., the code in OpenSSL).
*/
#define SHA256_Init libcperciva_SHA256_Init
#define SHA256_Update libcperciva_SHA256_Update
#define SHA256_Final libcperciva_SHA256_Final
#define SHA256_Buf libcperciva_SHA256_Buf
#define SHA256_CTX libcperciva_SHA256_CTX
#define HMAC_SHA256_Init libcperciva_HMAC_SHA256_Init
#define HMAC_SHA256_Update libcperciva_HMAC_SHA256_Update
#define HMAC_SHA256_Final libcperciva_HMAC_SHA256_Final
#define HMAC_SHA256_Buf libcperciva_HMAC_SHA256_Buf
#define HMAC_SHA256_CTX libcperciva_HMAC_SHA256_CTX
/* Context structure for SHA256 operations. */
typedef struct {
uint32_t state[8];
uint64_t count;
uint8_t buf[64];
} SHA256_CTX;
/**
* SHA256_Init(ctx):
* Initialize the SHA256 context ${ctx}.
*/
void SHA256_Init(SHA256_CTX *);
/**
* SHA256_Update(ctx, in, len):
* Input ${len} bytes from ${in} into the SHA256 context ${ctx}.
*/
void SHA256_Update(SHA256_CTX *, const void *, size_t);
/**
* SHA256_Final(digest, ctx):
* Output the SHA256 hash of the data input to the context ${ctx} into the
* buffer ${digest}.
*/
void SHA256_Final(uint8_t[32], SHA256_CTX *);
/**
* SHA256_Buf(in, len, digest):
* Compute the SHA256 hash of ${len} bytes from ${in} and write it to ${digest}.
*/
void SHA256_Buf(const void *, size_t, uint8_t[32]);
/* Context structure for HMAC-SHA256 operations. */
typedef struct {
SHA256_CTX ictx;
SHA256_CTX 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 *);
/**
* HMAC_SHA256_Buf(K, Klen, in, len, digest):
* Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of
* length ${Klen}, and write the result to ${digest}.
*/
void HMAC_SHA256_Buf(const void *, size_t, const void *, size_t, uint8_t[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 *, size_t, const uint8_t *, size_t,
uint64_t, uint8_t *, size_t);
#ifdef __cplusplus
}
#endif
#endif /* !_SHA256_H_ */

View File

@@ -0,0 +1,122 @@
/*-
* Copyright 2007-2014 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.
*/
#ifndef _SYSENDIAN_H_
#define _SYSENDIAN_H_
#include <stdint.h>
/* Avoid namespace collisions with BSD <sys/endian.h>. */
#define be32dec libcperciva_be32dec
#define be32enc libcperciva_be32enc
#define be64enc libcperciva_be64enc
#define le32dec libcperciva_le32dec
#define le32enc libcperciva_le32enc
#define le64dec libcperciva_le64dec
#define le64enc libcperciva_le64enc
static inline uint32_t
be32dec(const void * pp)
{
const uint8_t * p = (uint8_t const *)pp;
return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
}
static inline void
be32enc(void * pp, uint32_t x)
{
uint8_t * p = (uint8_t *)pp;
p[3] = x & 0xff;
p[2] = (x >> 8) & 0xff;
p[1] = (x >> 16) & 0xff;
p[0] = (x >> 24) & 0xff;
}
static inline void
be64enc(void * pp, uint64_t x)
{
uint8_t * p = (uint8_t *)pp;
p[7] = x & 0xff;
p[6] = (x >> 8) & 0xff;
p[5] = (x >> 16) & 0xff;
p[4] = (x >> 24) & 0xff;
p[3] = (x >> 32) & 0xff;
p[2] = (x >> 40) & 0xff;
p[1] = (x >> 48) & 0xff;
p[0] = (x >> 56) & 0xff;
}
static inline uint32_t
le32dec(const void * pp)
{
const uint8_t * p = (uint8_t const *)pp;
return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) +
((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24));
}
static inline void
le32enc(void * pp, uint32_t x)
{
uint8_t * p = (uint8_t *)pp;
p[0] = x & 0xff;
p[1] = (x >> 8) & 0xff;
p[2] = (x >> 16) & 0xff;
p[3] = (x >> 24) & 0xff;
}
static inline uint64_t
le64dec(const void * pp)
{
const uint8_t * p = (uint8_t const *)pp;
return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) +
((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) +
((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) +
((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56));
}
static inline void
le64enc(void * pp, uint64_t x)
{
uint8_t * p = (uint8_t *)pp;
p[0] = x & 0xff;
p[1] = (x >> 8) & 0xff;
p[2] = (x >> 16) & 0xff;
p[3] = (x >> 24) & 0xff;
p[4] = (x >> 32) & 0xff;
p[5] = (x >> 40) & 0xff;
p[6] = (x >> 48) & 0xff;
p[7] = (x >> 56) & 0xff;
}
#endif /* !_SYSENDIAN_H_ */

View File

@@ -0,0 +1,405 @@
/*-
* Copyright 2013-2018 Alexander Peslyak
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* 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.
*/
#define YESCRYPT_FLAGS YESCRYPT_DEFAULTS
//#define YESCRYPT_FLAGS YESCRYPT_WORM
//#define YESCRYPT_FLAGS 0
#define ROM_SHM_KEY 0x7965730a
//#define DISABLE_ROM
//#define DUMP_LOCAL
#include <stdio.h>
#include <stdlib.h> /* for atoi() */
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <sys/times.h>
#include <sched.h>
#include "yescrypt.h"
#ifdef _OPENMP
#include <omp.h>
#define NSAVE 1000
static uint64_t time_us(void)
{
struct timespec t;
#ifdef CLOCK_MONOTONIC_RAW
if (clock_gettime(CLOCK_MONOTONIC_RAW, &t))
return 0;
#else
if (clock_gettime(CLOCK_MONOTONIC, &t))
return 0;
#endif
return 1 + (uint64_t)t.tv_sec * 1000000 + t.tv_nsec / 1000;
}
#endif
int main(int argc, const char * const *argv)
{
#if 0
uint64_t rom_bytes = 112 * (1024ULL*1024*1024);
uint64_t ram_bytes = 1 * (1024ULL*1024);
#else
uint64_t rom_bytes = 3 * (1024ULL*1024*1024);
uint64_t ram_bytes = 2 * (1024ULL*1024);
#endif
uint32_t r, min_r;
uint64_t NROM_log2, N_log2;
yescrypt_shared_t shared_s;
yescrypt_shared_t *shared = NULL;
#ifndef DISABLE_ROM
int shmid;
#endif
const char *rom_filename = NULL;
int rom_fd;
yescrypt_binary_t key = {.uc={
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
17,18,19,20,21,22,23,24,25,26,27,28,255,128,64,32}};
if (argc > 1)
rom_bytes = atoi(argv[1]) * (1024ULL*1024*1024);
if (argc > 2)
ram_bytes = atoi(argv[2]) * (1024ULL*1024);
if (argc > 3 && rom_bytes)
rom_filename = argv[3];
r = 16;
min_r = 9;
if (rom_filename)
min_r = 8 * 64;
NROM_log2 = 0;
if (rom_bytes) {
while (((rom_bytes >> NROM_log2) & 0xff) == 0)
NROM_log2++;
r = rom_bytes >> (7 + NROM_log2);
while (r < min_r && NROM_log2 > 0) {
r <<= 1;
NROM_log2--;
}
rom_bytes = (uint64_t)r << (7 + NROM_log2);
}
N_log2 = 0;
while (((uint64_t)r << (7 + N_log2)) < ram_bytes)
N_log2++;
ram_bytes = (uint64_t)r << (7 + N_log2);
printf("r=%u N=2^%u NROM=2^%u\n", r,
(unsigned int)N_log2, (unsigned int)NROM_log2);
#ifdef DISABLE_ROM
rom_bytes = 0;
#endif
printf("Will use %.2f KiB ROM\n", rom_bytes / 1024.0);
printf(" %.2f KiB RAM\n", ram_bytes / 1024.0);
#ifndef DISABLE_ROM
if (rom_filename) {
rom_fd = open(rom_filename, O_RDONLY);
if (rom_fd < 0) {
perror("open");
return 1;
}
int flags =
#ifdef MAP_NOCORE
MAP_NOCORE |
#endif
#ifdef MAP_HUGETLB
MAP_HUGETLB |
#endif
MAP_SHARED;
void *p = mmap(NULL, rom_bytes, PROT_READ, flags, rom_fd, 0);
#ifdef MAP_HUGETLB
if (p == MAP_FAILED)
p = mmap(NULL, rom_bytes, PROT_READ,
flags & ~MAP_HUGETLB, rom_fd, 0);
#endif
if (p == MAP_FAILED) {
perror("mmap");
close(rom_fd);
return 1;
}
close(rom_fd);
shared = &shared_s;
shared->base = shared->aligned = p;
shared->aligned_size = rom_bytes;
} else if (rom_bytes) {
shared = &shared_s;
shared->aligned_size = rom_bytes;
shmid = shmget(ROM_SHM_KEY, shared->aligned_size, 0);
if (shmid == -1) {
perror("shmget");
return 1;
}
shared->base = shared->aligned = shmat(shmid, NULL, SHM_RDONLY);
if (shared->base == (void *)-1) {
perror("shmat");
return 1;
}
}
#endif
{
yescrypt_local_t local;
const uint8_t *setting;
if (yescrypt_init_local(&local)) {
puts("yescrypt_init_local() FAILED");
return 1;
}
yescrypt_params_t params = {
.flags = YESCRYPT_FLAGS,
.N = (uint64_t)1 << N_log2,
.NROM = NROM_log2 ? ((uint64_t)1 << NROM_log2) : 0,
.r = r,
.p = 1 };
setting = yescrypt_encode_params(&params,
(const uint8_t *)"WZaPV7LSUEKMo34.", 16);
{
uint8_t hash[128];
if (!yescrypt_r(shared, &local,
(const uint8_t *)"pleaseletmein", 13, setting, NULL,
hash, sizeof(hash))) {
puts("yescrypt_r() FAILED");
return 1;
}
printf("Plaintext: '%s'\n", (char *)hash);
if (!yescrypt_r(shared, &local,
(const uint8_t *)"pleaseletmein", 13, setting, &key,
hash, sizeof(hash))) {
puts("yescrypt_r() FAILED");
return 1;
}
printf("Encrypted: '%s'\n", (char *)hash);
}
#ifdef DUMP_LOCAL
#if 0
fwrite(local.aligned, local.aligned_size, 1, stderr);
#else
/* Skip B, dump only V */
if (local.aligned_size >= ram_bytes + 128 * r)
fwrite((char *)local.aligned + 128 * r, ram_bytes,
1, stderr);
#endif
#endif
puts("Benchmarking 1 thread ...");
clock_t clk_tck = sysconf(_SC_CLK_TCK);
struct tms start_tms, end_tms;
clock_t start = times(&start_tms), end;
unsigned int i, n;
unsigned long long count;
#ifdef _OPENMP
char save[NSAVE][128];
unsigned int nsave = 0;
#endif
unsigned int seed = start * 1812433253U;
n = 1;
count = 0;
do {
for (i = 0; i < n; i++) {
unsigned int j = count + i;
char p[32];
uint8_t hash[128];
snprintf(p, sizeof(p), "%u", seed + j);
#ifdef _OPENMP
const uint8_t *h =
#endif
yescrypt_r(shared, &local,
(const uint8_t *)p, strlen(p),
setting, &key, hash, sizeof(hash));
#ifdef _OPENMP
if (j < NSAVE) {
save[j][0] = 0;
strncat(save[j], (char *)h,
sizeof(save[j]) - 1);
nsave = j;
}
#endif
}
count += n;
end = times(&end_tms);
n <<= 1;
} while (end - start < clk_tck * 2);
clock_t start_v = start_tms.tms_utime + start_tms.tms_stime +
start_tms.tms_cutime + start_tms.tms_cstime;
clock_t end_v = end_tms.tms_utime + end_tms.tms_stime +
end_tms.tms_cutime + end_tms.tms_cstime;
printf("%llu c/s real, %llu c/s virtual "
"(%llu hashes in %.2f seconds)\n",
count * clk_tck / (end - start),
count * clk_tck / (end_v - start_v),
count, (double)(end - start) / clk_tck);
#ifdef _OPENMP
unsigned int nt = omp_get_max_threads();
printf("Benchmarking %u thread%s ...\n",
nt, nt == 1 ? "" : "s");
typedef struct {
yescrypt_local_t local;
uint64_t min, max, total;
} thread_data_s;
union {
thread_data_s s;
uint8_t cachelines[2][64]; /* avoid false sharing */
} thread_data[nt]; /* tricky to align this when on stack */
unsigned int t;
for (t = 0; t < nt; t++) {
thread_data_s *td = &thread_data[t].s;
if (yescrypt_init_local(&td->local)) {
puts("yescrypt_init_local() FAILED");
return 1;
}
td->min = ~(uint64_t)0; td->max = 0; td->total = 0;
}
unsigned long long count1 = count, count_restart = 0;
if (!geteuid()) {
puts("Running as root, so trying to set SCHED_RR");
#pragma omp parallel
{
struct sched_param param = { .sched_priority = 1 };
if (sched_setscheduler(getpid(), SCHED_RR, &param))
perror("sched_setscheduler");
}
}
start = times(&start_tms);
n = count * omp_get_max_threads();
count = 0;
do {
#pragma omp parallel for default(none) private(i) shared(n, shared, thread_data, setting, seed, count, save, nsave, key)
for (i = 0; i < n; i++) {
unsigned int j = count + i;
char p[32];
uint8_t hash[128];
snprintf(p, sizeof(p), "%u", seed + j);
thread_data_s *td = &thread_data[omp_get_thread_num()].s;
uint64_t start1 = time_us();
#if 1
const char *h = (const char *)yescrypt_r(
shared, &td->local,
(const uint8_t *)p, strlen(p),
setting, &key, hash, sizeof(hash));
#else
yescrypt_local_t local;
yescrypt_init_local(&local);
const char *h = (const char *)yescrypt_r(
shared, &local,
(const uint8_t *)p, strlen(p),
setting, &key, hash, sizeof(hash));
yescrypt_free_local(&local);
#endif
uint64_t end1 = time_us();
if (end1 < start1)
end1 = start1;
uint64_t diff1 = end1 - start1;
td->total += diff1;
if (diff1 < td->min)
td->min = diff1;
if (diff1 > td->max)
td->max = diff1;
if (j < nsave && strcmp(save[j], h)) {
#pragma omp critical
printf("Mismatch at %u, %s != %s\n",
j, save[j], h);
}
}
count += n;
if ((count - n) < count1 && count >= count1) {
/* Disregard our repeat of single thread's results (could be partially cached
* by same core, but OTOH other cores not yet warmed up to full clock rate). */
start = times(&start_tms);
count_restart = count;
for (t = 0; t < nt; t++) {
thread_data_s *td = &thread_data[t].s;
td->min = ~(uint64_t)0; td->max = 0; td->total = 0;
}
} else {
n <<= 1;
}
end = times(&end_tms);
} while (end - start < clk_tck);
if (!count_restart)
puts("Didn't reach single-thread's hash count");
count -= count_restart;
start_v = start_tms.tms_utime + start_tms.tms_stime +
start_tms.tms_cutime + start_tms.tms_cstime;
end_v = end_tms.tms_utime + end_tms.tms_stime +
end_tms.tms_cutime + end_tms.tms_cstime;
printf("%llu c/s real, %llu c/s virtual "
"(%llu hashes in %.2f seconds)\n",
count * clk_tck / (end - start),
count * clk_tck / (end_v - start_v),
count, (double)(end - start) / clk_tck);
uint64_t min = ~(uint64_t)0, max = 0, total = 0;
for (t = 0; t < nt; t++) {
thread_data_s *td = &thread_data[t].s;
total += td->total;
if (td->min < min)
min = td->min;
if (td->max > max)
max = td->max;
}
printf("min %.3f ms, avg %.3f ms, max %.3f ms\n",
min / 1000.0, total / 1000.0 / count, max / 1000.0);
#endif
}
if (rom_filename && munmap(shared->base, rom_bytes)) {
perror("munmap");
return 1;
}
return 0;
}

View File

@@ -0,0 +1,703 @@
/*-
* Copyright 2013-2018 Alexander Peslyak
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* 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 <stdint.h>
#include <string.h>
#include "insecure_memzero.h"
#include "sha256.h"
#define YESCRYPT_INTERNAL
#include "yescrypt.h"
#define BYTES2CHARS(bytes) ((((bytes) * 8) + 5) / 6)
#define HASH_SIZE sizeof(yescrypt_binary_t) /* bytes */
#define HASH_LEN BYTES2CHARS(HASH_SIZE) /* base-64 chars */
/*
* "$y$", up to 8 params of up to 6 chars each, '$', salt
* Alternatively, but that's smaller:
* "$7$", 3 params encoded as 1+5+5 chars, salt
*/
#define PREFIX_LEN (3 + 8 * 6 + 1 + BYTES2CHARS(32))
static const char * const itoa64 =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static const uint8_t atoi64_partial[77] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
64, 64, 64, 64, 64, 64, 64,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
64, 64, 64, 64, 64, 64,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
};
static uint8_t *encode64_uint32(uint8_t *dst, size_t dstlen,
uint32_t src, uint32_t min)
{
uint32_t start = 0, end = 47, chars = 1, bits = 0;
if (src < min)
return NULL;
src -= min;
do {
uint32_t count = (end + 1 - start) << bits;
if (src < count)
break;
if (start >= 63)
return NULL;
start = end + 1;
end = start + (62 - end) / 2;
src -= count;
chars++;
bits += 6;
} while (1);
if (dstlen <= chars) /* require room for a NUL terminator */
return NULL;
*dst++ = itoa64[start + (src >> bits)];
while (--chars) {
bits -= 6;
*dst++ = itoa64[(src >> bits) & 0x3f];
}
*dst = 0; /* NUL terminate just in case */
return dst;
}
static inline uint32_t atoi64(uint8_t src)
{
if (src >= '.' && src <= 'z')
return atoi64_partial[src - '.'];
return 64;
}
static const uint8_t *decode64_uint32(uint32_t *dst,
const uint8_t *src, uint32_t min)
{
uint32_t start = 0, end = 47, chars = 1, bits = 0;
uint32_t c;
c = atoi64(*src++);
if (c > 63)
goto fail;
*dst = min;
while (c > end) {
*dst += (end + 1 - start) << bits;
start = end + 1;
end = start + (62 - end) / 2;
chars++;
bits += 6;
}
*dst += (c - start) << bits;
while (--chars) {
c = atoi64(*src++);
if (c > 63)
goto fail;
bits -= 6;
*dst += c << bits;
}
return src;
fail:
*dst = 0;
return NULL;
}
static uint8_t *encode64_uint32_fixed(uint8_t *dst, size_t dstlen,
uint32_t src, uint32_t srcbits)
{
uint32_t bits;
for (bits = 0; bits < srcbits; bits += 6) {
if (dstlen < 2)
return NULL;
*dst++ = itoa64[src & 0x3f];
dstlen--;
src >>= 6;
}
if (src || dstlen < 1)
return NULL;
*dst = 0; /* NUL terminate just in case */
return dst;
}
static uint8_t *encode64(uint8_t *dst, size_t dstlen,
const uint8_t *src, size_t srclen)
{
size_t i;
for (i = 0; i < srclen; ) {
uint8_t *dnext;
uint32_t value = 0, bits = 0;
do {
value |= (uint32_t)src[i++] << bits;
bits += 8;
} while (bits < 24 && i < srclen);
dnext = encode64_uint32_fixed(dst, dstlen, value, bits);
if (!dnext)
return NULL;
dstlen -= dnext - dst;
dst = dnext;
}
if (dstlen < 1)
return NULL;
*dst = 0; /* NUL terminate just in case */
return dst;
}
static const uint8_t *decode64_uint32_fixed(uint32_t *dst, uint32_t dstbits,
const uint8_t *src)
{
uint32_t bits;
*dst = 0;
for (bits = 0; bits < dstbits; bits += 6) {
uint32_t c = atoi64(*src++);
if (c > 63) {
*dst = 0;
return NULL;
}
*dst |= c << bits;
}
return src;
}
static const uint8_t *decode64(uint8_t *dst, size_t *dstlen,
const uint8_t *src, size_t srclen)
{
size_t dstpos = 0;
while (dstpos <= *dstlen && srclen) {
uint32_t value = 0, bits = 0;
while (srclen--) {
uint32_t c = atoi64(*src);
if (c > 63) {
srclen = 0;
break;
}
src++;
value |= c << bits;
bits += 6;
if (bits >= 24)
break;
}
if (!bits)
break;
if (bits < 12) /* must have at least one full byte */
goto fail;
while (dstpos++ < *dstlen) {
*dst++ = value;
value >>= 8;
bits -= 8;
if (bits < 8) { /* 2 or 4 */
if (value) /* must be 0 */
goto fail;
bits = 0;
break;
}
}
if (bits)
goto fail;
}
if (!srclen && dstpos <= *dstlen) {
*dstlen = dstpos;
return src;
}
fail:
*dstlen = 0;
return NULL;
}
typedef enum { ENC = 1, DEC = -1 } encrypt_dir_t;
static void memxor(unsigned char *dst, unsigned char *src, size_t size)
{
while (size--)
*dst++ ^= *src++;
}
static void encrypt(unsigned char *data, size_t datalen,
const yescrypt_binary_t *key, encrypt_dir_t dir)
{
SHA256_CTX ctx;
unsigned char f[32 + 4];
size_t halflen, which;
unsigned char mask, round, target;
if (!datalen)
return;
if (datalen > 64)
datalen = 64;
halflen = datalen >> 1;
which = 0; /* offset to half we are working on (0 or halflen) */
mask = 0x0f; /* current half's extra nibble mask if datalen is odd */
round = 0;
target = 5; /* 6 rounds due to Jacques Patarin's CRYPTO 2004 paper */
if (dir == DEC) {
which = halflen; /* even round count, so swap the halves */
mask ^= 0xff;
round = target;
target = 0;
}
f[32] = 0;
f[33] = sizeof(*key);
f[34] = datalen;
do {
SHA256_Init(&ctx);
f[35] = round;
SHA256_Update(&ctx, &f[32], 4);
SHA256_Update(&ctx, key, sizeof(*key));
SHA256_Update(&ctx, &data[which], halflen);
if (datalen & 1) {
f[0] = data[datalen - 1] & mask;
SHA256_Update(&ctx, f, 1);
}
SHA256_Final(f, &ctx);
which ^= halflen;
memxor(&data[which], f, halflen);
if (datalen & 1) {
mask ^= 0xff;
data[datalen - 1] ^= f[halflen] & mask;
}
if (round == target)
break;
round += dir;
} while (1);
/* ctx is presumably zeroized by SHA256_Final() */
insecure_memzero(f, sizeof(f));
}
uint8_t *yescrypt_r(const yescrypt_shared_t *shared, yescrypt_local_t *local,
const uint8_t *passwd, size_t passwdlen,
const uint8_t *setting,
const yescrypt_binary_t *key,
uint8_t *buf, size_t buflen)
{
unsigned char saltbin[64], hashbin[32];
const uint8_t *src, *saltstr, *salt;
uint8_t *dst;
size_t need, prefixlen, saltstrlen, saltlen;
yescrypt_params_t params = { .p = 1 };
if (setting[0] != '$' ||
(setting[1] != '7' && setting[1] != 'y') ||
setting[2] != '$')
return NULL;
src = setting + 3;
if (setting[1] == '7') {
uint32_t N_log2 = atoi64(*src++);
if (N_log2 < 1 || N_log2 > 63)
return NULL;
params.N = (uint64_t)1 << N_log2;
src = decode64_uint32_fixed(&params.r, 30, src);
if (!src)
return NULL;
src = decode64_uint32_fixed(&params.p, 30, src);
if (!src)
return NULL;
if (key)
return NULL;
} else {
uint32_t flavor, N_log2;
src = decode64_uint32(&flavor, src, 0);
if (!src)
return NULL;
if (flavor < YESCRYPT_RW) {
params.flags = flavor;
} else if (flavor <= YESCRYPT_RW + (YESCRYPT_RW_FLAVOR_MASK >> 2)) {
params.flags = YESCRYPT_RW + ((flavor - YESCRYPT_RW) << 2);
} else {
return NULL;
}
src = decode64_uint32(&N_log2, src, 1);
if (!src || N_log2 > 63)
return NULL;
params.N = (uint64_t)1 << N_log2;
src = decode64_uint32(&params.r, src, 1);
if (!src)
return NULL;
if (*src != '$') {
uint32_t have;
src = decode64_uint32(&have, src, 1);
if (!src)
return NULL;
if (have & 1) {
src = decode64_uint32(&params.p, src, 2);
if (!src)
return NULL;
}
if (have & 2) {
src = decode64_uint32(&params.t, src, 1);
if (!src)
return NULL;
}
if (have & 4) {
src = decode64_uint32(&params.g, src, 1);
if (!src)
return NULL;
}
if (have & 8) {
uint32_t NROM_log2;
src = decode64_uint32(&NROM_log2, src, 1);
if (!src || NROM_log2 > 63)
return NULL;
params.NROM = (uint64_t)1 << NROM_log2;
}
}
if (*src++ != '$')
return NULL;
}
prefixlen = src - setting;
saltstr = src;
src = (uint8_t *)strrchr((char *)saltstr, '$');
if (src)
saltstrlen = src - saltstr;
else
saltstrlen = strlen((char *)saltstr);
if (setting[1] == '7') {
salt = saltstr;
saltlen = saltstrlen;
} else {
const uint8_t *saltend;
saltlen = sizeof(saltbin);
saltend = decode64(saltbin, &saltlen, saltstr, saltstrlen);
if (!saltend || (size_t)(saltend - saltstr) != saltstrlen)
goto fail;
salt = saltbin;
if (key)
encrypt(saltbin, saltlen, key, ENC);
}
need = prefixlen + saltstrlen + 1 + HASH_LEN + 1;
if (need > buflen || need < saltstrlen)
goto fail;
if (yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen,
&params, hashbin, sizeof(hashbin)))
goto fail;
if (key) {
insecure_memzero(saltbin, sizeof(saltbin));
encrypt(hashbin, sizeof(hashbin), key, ENC);
}
dst = buf;
memcpy(dst, setting, prefixlen + saltstrlen);
dst += prefixlen + saltstrlen;
*dst++ = '$';
dst = encode64(dst, buflen - (dst - buf), hashbin, sizeof(hashbin));
insecure_memzero(hashbin, sizeof(hashbin));
if (!dst || dst >= buf + buflen)
return NULL;
*dst = 0; /* NUL termination */
return buf;
fail:
insecure_memzero(saltbin, sizeof(saltbin));
insecure_memzero(hashbin, sizeof(hashbin));
return NULL;
}
uint8_t *yescrypt(const uint8_t *passwd, const uint8_t *setting)
{
/* prefix, '$', hash, NUL */
static uint8_t buf[PREFIX_LEN + 1 + HASH_LEN + 1];
yescrypt_local_t local;
uint8_t *retval;
if (yescrypt_init_local(&local))
return NULL;
retval = yescrypt_r(NULL, &local,
passwd, strlen((char *)passwd), setting, NULL, buf, sizeof(buf));
if (yescrypt_free_local(&local))
return NULL;
return retval;
}
uint8_t *yescrypt_reencrypt(uint8_t *hash,
const yescrypt_binary_t *from_key,
const yescrypt_binary_t *to_key)
{
uint8_t *retval = NULL, *saltstart, *hashstart;
const uint8_t *hashend;
unsigned char saltbin[64], hashbin[32];
size_t saltstrlen, saltlen = 0, hashlen;
if (strncmp((char *)hash, "$y$", 3))
return NULL;
saltstart = NULL;
hashstart = (uint8_t *)strrchr((char *)hash, '$');
if (hashstart) {
if (hashstart > (uint8_t *)hash) {
saltstart = hashstart - 1;
while (*saltstart != '$' && saltstart > hash)
saltstart--;
if (*saltstart == '$')
saltstart++;
}
hashstart++;
} else {
hashstart = hash;
}
saltstrlen = saltstart ? (hashstart - 1 - saltstart) : 0;
if (saltstrlen > BYTES2CHARS(64) ||
strlen((char *)hashstart) != HASH_LEN)
return NULL;
if (saltstrlen) {
const uint8_t *saltend;
saltlen = sizeof(saltbin);
saltend = decode64(saltbin, &saltlen, saltstart, saltstrlen);
if (!saltend || *saltend != '$' || saltlen < 1 || saltlen > 64)
goto out;
if (from_key)
encrypt(saltbin, saltlen, from_key, ENC);
if (to_key)
encrypt(saltbin, saltlen, to_key, DEC);
}
hashlen = sizeof(hashbin);
hashend = decode64(hashbin, &hashlen, hashstart, HASH_LEN);
if (!hashend || *hashend || hashlen != sizeof(hashbin))
goto out;
if (from_key)
encrypt(hashbin, hashlen, from_key, DEC);
if (to_key)
encrypt(hashbin, hashlen, to_key, ENC);
if (saltstrlen) {
if (!encode64(saltstart, saltstrlen + 1, saltbin, saltlen))
goto out; /* can't happen */
*(saltstart + saltstrlen) = '$';
}
if (!encode64(hashstart, HASH_LEN + 1, hashbin, hashlen))
goto out; /* can't happen */
retval = hash;
out:
insecure_memzero(saltbin, sizeof(saltbin));
insecure_memzero(hashbin, sizeof(hashbin));
return retval;
}
static uint32_t N2log2(uint64_t N)
{
uint32_t N_log2;
if (N < 2)
return 0;
N_log2 = 2;
while (N >> N_log2 != 0)
N_log2++;
N_log2--;
if (N >> N_log2 != 1)
return 0;
return N_log2;
}
uint8_t *yescrypt_encode_params_r(const yescrypt_params_t *params,
const uint8_t *src, size_t srclen,
uint8_t *buf, size_t buflen)
{
uint32_t flavor, N_log2, NROM_log2, have;
uint8_t *dst;
if (srclen > SIZE_MAX / 16)
return NULL;
if (params->flags < YESCRYPT_RW) {
flavor = params->flags;
} else if ((params->flags & YESCRYPT_MODE_MASK) == YESCRYPT_RW &&
params->flags <= (YESCRYPT_RW | YESCRYPT_RW_FLAVOR_MASK)) {
flavor = YESCRYPT_RW + (params->flags >> 2);
} else {
return NULL;
}
N_log2 = N2log2(params->N);
if (!N_log2)
return NULL;
NROM_log2 = N2log2(params->NROM);
if (params->NROM && !NROM_log2)
return NULL;
if ((uint64_t)params->r * (uint64_t)params->p >= (1U << 30))
return NULL;
dst = buf;
*dst++ = '$';
*dst++ = 'y';
*dst++ = '$';
dst = encode64_uint32(dst, buflen - (dst - buf), flavor, 0);
if (!dst)
return NULL;
dst = encode64_uint32(dst, buflen - (dst - buf), N_log2, 1);
if (!dst)
return NULL;
dst = encode64_uint32(dst, buflen - (dst - buf), params->r, 1);
if (!dst)
return NULL;
have = 0;
if (params->p != 1)
have |= 1;
if (params->t)
have |= 2;
if (params->g)
have |= 4;
if (NROM_log2)
have |= 8;
if (have) {
dst = encode64_uint32(dst, buflen - (dst - buf), have, 1);
if (!dst)
return NULL;
}
if (params->p != 1) {
dst = encode64_uint32(dst, buflen - (dst - buf), params->p, 2);
if (!dst)
return NULL;
}
if (params->t) {
dst = encode64_uint32(dst, buflen - (dst - buf), params->t, 1);
if (!dst)
return NULL;
}
if (params->g) {
dst = encode64_uint32(dst, buflen - (dst - buf), params->g, 1);
if (!dst)
return NULL;
}
if (NROM_log2) {
dst = encode64_uint32(dst, buflen - (dst - buf), NROM_log2, 1);
if (!dst)
return NULL;
}
if (dst >= buf + buflen)
return NULL;
*dst++ = '$';
dst = encode64(dst, buflen - (dst - buf), src, srclen);
if (!dst || dst >= buf + buflen)
return NULL;
*dst = 0; /* NUL termination */
return buf;
}
uint8_t *yescrypt_encode_params(const yescrypt_params_t *params,
const uint8_t *src, size_t srclen)
{
/* prefix, NUL */
static uint8_t buf[PREFIX_LEN + 1];
return yescrypt_encode_params_r(params, src, srclen, buf, sizeof(buf));
}
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)
{
yescrypt_local_t local;
yescrypt_params_t params = { .flags = 0, .N = N, .r = r, .p = p };
int retval;
if (yescrypt_init_local(&local))
return -1;
retval = yescrypt_kdf(NULL, &local,
passwd, passwdlen, salt, saltlen, &params, buf, buflen);
if (yescrypt_free_local(&local))
return -1;
return retval;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,110 @@
/*-
* Copyright 2013-2018,2022 Alexander Peslyak
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* 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.
*/
#ifdef __unix__
#include <sys/mman.h>
#endif
#ifdef __linux__
#include <linux/mman.h> /* for MAP_HUGE_2MB */
#endif
#define HUGEPAGE_THRESHOLD (32 * 1024 * 1024)
#ifdef __x86_64__
#define HUGEPAGE_SIZE (2 * 1024 * 1024)
#else
#undef HUGEPAGE_SIZE
#endif
static void *alloc_region(yescrypt_region_t *region, size_t size)
{
size_t base_size = size;
uint8_t *base, *aligned;
#ifdef MAP_ANON
int flags =
#ifdef MAP_NOCORE
MAP_NOCORE |
#endif
MAP_ANON | MAP_PRIVATE;
#if defined(MAP_HUGETLB) && defined(MAP_HUGE_2MB) && defined(HUGEPAGE_SIZE)
size_t new_size = size;
const size_t hugepage_mask = (size_t)HUGEPAGE_SIZE - 1;
if (size >= HUGEPAGE_THRESHOLD && size + hugepage_mask >= size) {
flags |= MAP_HUGETLB | MAP_HUGE_2MB;
/*
* Linux's munmap() fails on MAP_HUGETLB mappings if size is not a multiple of
* huge page size, so let's round up to huge page size here.
*/
new_size = size + hugepage_mask;
new_size &= ~hugepage_mask;
}
base = mmap(NULL, new_size, PROT_READ | PROT_WRITE, flags, -1, 0);
if (base != MAP_FAILED) {
base_size = new_size;
} else if (flags & MAP_HUGETLB) {
flags &= ~(MAP_HUGETLB | MAP_HUGE_2MB);
base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
}
#else
base = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
#endif
if (base == MAP_FAILED)
base = NULL;
aligned = base;
#elif defined(HAVE_POSIX_MEMALIGN)
if ((errno = posix_memalign((void **)&base, 64, size)) != 0)
base = NULL;
aligned = base;
#else
base = aligned = NULL;
if (size + 63 < size) {
errno = ENOMEM;
} else if ((base = malloc(size + 63)) != NULL) {
aligned = base + 63;
aligned -= (uintptr_t)aligned & 63;
}
#endif
region->base = base;
region->aligned = aligned;
region->base_size = base ? base_size : 0;
region->aligned_size = base ? size : 0;
return aligned;
}
static inline void init_region(yescrypt_region_t *region)
{
region->base = region->aligned = NULL;
region->base_size = region->aligned_size = 0;
}
static int free_region(yescrypt_region_t *region)
{
if (region->base) {
#ifdef MAP_ANON
if (munmap(region->base, region->base_size))
return -1;
#else
free(region->base);
#endif
}
init_region(region);
return 0;
}

View File

@@ -0,0 +1,925 @@
/*-
* Copyright 2009 Colin Percival
* Copyright 2013-2018 Alexander Peslyak
* 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.
*
* This is the reference implementation. Its purpose is to provide a simple
* human- and machine-readable specification that implementations intended
* for actual use should be tested against. It is deliberately mostly not
* optimized, and it is not meant to be used in production. Instead, use
* yescrypt-opt.c.
*/
#ifdef __GNUC__
#warning "This reference implementation is deliberately mostly not optimized, nor does it make any attempt not to leave sensitive data in memory. Use yescrypt-opt.c instead unless you're testing (against) the reference implementation on purpose."
#endif
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "sha256.h"
#include "sysendian.h"
#define YESCRYPT_INTERNAL
#include "yescrypt.h"
static void blkcpy(uint32_t *dst, const uint32_t *src, size_t count)
{
do {
*dst++ = *src++;
} while (--count);
}
static void blkxor(uint32_t *dst, const uint32_t *src, size_t count)
{
do {
*dst++ ^= *src++;
} while (--count);
}
/**
* salsa20(B):
* Apply the Salsa20 core to the provided block.
*/
static void salsa20(uint32_t B[16], uint32_t rounds)
{
uint32_t x[16];
size_t i;
/* SIMD unshuffle */
for (i = 0; i < 16; i++)
x[i * 5 % 16] = B[i];
for (i = 0; i < rounds; 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
}
/* SIMD shuffle */
for (i = 0; i < 16; i++)
B[i] += x[i * 5 % 16];
}
/**
* blockmix_salsa8(B, Y, r):
* Compute B = BlockMix_{salsa20/8, r}(B). The input B must be 128r bytes in
* length; the temporary space Y must also be the same size.
*/
static void blockmix_salsa8(uint32_t *B, uint32_t *Y, size_t r)
{
uint32_t X[16];
size_t i;
/* 1: X <-- B_{2r - 1} */
blkcpy(X, &B[(2 * r - 1) * 16], 16);
/* 2: for i = 0 to 2r - 1 do */
for (i = 0; i < 2 * r; i++) {
/* 3: X <-- H(X xor B_i) */
blkxor(X, &B[i * 16], 16);
salsa20(X, 8);
/* 4: Y_i <-- X */
blkcpy(&Y[i * 16], X, 16);
}
/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
for (i = 0; i < r; i++)
blkcpy(&B[i * 16], &Y[(i * 2) * 16], 16);
for (i = 0; i < r; i++)
blkcpy(&B[(i + r) * 16], &Y[(i * 2 + 1) * 16], 16);
}
/* These are tunable, but they must meet certain constraints */
#define PWXsimple 2
#define PWXgather 4
#define PWXrounds 6
#define Swidth 8
/* Derived values. Not tunable on their own. */
#define PWXbytes (PWXgather * PWXsimple * 8)
#define PWXwords (PWXbytes / sizeof(uint32_t))
#define Sbytes (3 * (1 << Swidth) * PWXsimple * 8)
#define Swords (Sbytes / sizeof(uint32_t))
#define Smask (((1 << Swidth) - 1) * PWXsimple * 8)
#define rmin ((PWXbytes + 127) / 128)
typedef struct {
uint32_t *S;
uint32_t (*S0)[2], (*S1)[2], (*S2)[2];
size_t w;
} pwxform_ctx_t;
/**
* pwxform(B):
* Transform the provided block using the provided S-boxes.
*/
static void pwxform(uint32_t *B, pwxform_ctx_t *ctx)
{
uint32_t (*X)[PWXsimple][2] = (uint32_t (*)[PWXsimple][2])B;
uint32_t (*S0)[2] = ctx->S0, (*S1)[2] = ctx->S1, (*S2)[2] = ctx->S2;
size_t w = ctx->w;
size_t i, j, k;
/* 1: for i = 0 to PWXrounds - 1 do */
for (i = 0; i < PWXrounds; i++) {
/* 2: for j = 0 to PWXgather - 1 do */
for (j = 0; j < PWXgather; j++) {
uint32_t xl = X[j][0][0];
uint32_t xh = X[j][0][1];
uint32_t (*p0)[2], (*p1)[2];
/* 3: p0 <-- (lo(B_{j,0}) & Smask) / (PWXsimple * 8) */
p0 = S0 + (xl & Smask) / sizeof(*S0);
/* 4: p1 <-- (hi(B_{j,0}) & Smask) / (PWXsimple * 8) */
p1 = S1 + (xh & Smask) / sizeof(*S1);
/* 5: for k = 0 to PWXsimple - 1 do */
for (k = 0; k < PWXsimple; k++) {
uint64_t x, s0, s1;
/* 6: B_{j,k} <-- (hi(B_{j,k}) * lo(B_{j,k}) + S0_{p0,k}) xor S1_{p1,k} */
s0 = ((uint64_t)p0[k][1] << 32) + p0[k][0];
s1 = ((uint64_t)p1[k][1] << 32) + p1[k][0];
xl = X[j][k][0];
xh = X[j][k][1];
x = (uint64_t)xh * xl;
x += s0;
x ^= s1;
X[j][k][0] = x;
X[j][k][1] = x >> 32;
/* 8: if (i != 0) and (i != PWXrounds - 1) */
if (i != 0 && i != PWXrounds - 1) {
/* 9: S2_w <-- B_j */
S2[w][0] = x;
S2[w][1] = x >> 32;
/* 10: w <-- w + 1 */
w++;
}
}
}
}
/* 14: (S0, S1, S2) <-- (S2, S0, S1) */
ctx->S0 = S2;
ctx->S1 = S0;
ctx->S2 = S1;
/* 15: w <-- w mod 2^Swidth */
ctx->w = w & ((1 << Swidth) * PWXsimple - 1);
}
/**
* blockmix_pwxform(B, ctx, r):
* Compute B = BlockMix_pwxform{salsa20/2, ctx, r}(B). The input B must be
* 128r bytes in length.
*/
static void blockmix_pwxform(uint32_t *B, pwxform_ctx_t *ctx, size_t r)
{
uint32_t X[PWXwords];
size_t r1, i;
/* Convert 128-byte blocks to PWXbytes blocks */
/* 1: r_1 <-- 128r / PWXbytes */
r1 = 128 * r / PWXbytes;
/* 2: X <-- B'_{r_1 - 1} */
blkcpy(X, &B[(r1 - 1) * PWXwords], PWXwords);
/* 3: for i = 0 to r_1 - 1 do */
for (i = 0; i < r1; i++) {
/* 4: if r_1 > 1 */
if (r1 > 1) {
/* 5: X <-- X xor B'_i */
blkxor(X, &B[i * PWXwords], PWXwords);
}
/* 7: X <-- pwxform(X) */
pwxform(X, ctx);
/* 8: B'_i <-- X */
blkcpy(&B[i * PWXwords], X, PWXwords);
}
/* 10: i <-- floor((r_1 - 1) * PWXbytes / 64) */
i = (r1 - 1) * PWXbytes / 64;
/* 11: B_i <-- H(B_i) */
salsa20(&B[i * 16], 2);
#if 1 /* No-op with our current pwxform settings, but do it to make sure */
/* 12: for i = i + 1 to 2r - 1 do */
for (i++; i < 2 * r; i++) {
/* 13: B_i <-- H(B_i xor B_{i-1}) */
blkxor(&B[i * 16], &B[(i - 1) * 16], 16);
salsa20(&B[i * 16], 2);
}
#endif
}
/**
* integerify(B, r):
* Return the result of parsing B_{2r-1} as a little-endian integer.
*/
static uint64_t integerify(const uint32_t *B, size_t r)
{
/*
* Our 32-bit words are in host byte order, and word 13 is the second word of
* B_{2r-1} due to SIMD shuffling. The 64-bit value we return is also in host
* byte order, as it should be.
*/
const uint32_t *X = &B[(2 * r - 1) * 16];
return ((uint64_t)X[13] << 32) + X[0];
}
/**
* p2floor(x):
* Largest power of 2 not greater than argument.
*/
static uint64_t p2floor(uint64_t x)
{
uint64_t y;
while ((y = x & (x - 1)))
x = y;
return x;
}
/**
* wrap(x, i):
* Wrap x to the range 0 to i-1.
*/
static uint64_t wrap(uint64_t x, uint64_t i)
{
uint64_t n = p2floor(i);
return (x & (n - 1)) + (i - n);
}
/**
* smix1(B, r, N, flags, V, NROM, VROM, XY, ctx):
* Compute first loop of 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 bytes in length.
*/
static void smix1(uint32_t *B, size_t r, uint64_t N, yescrypt_flags_t flags,
uint32_t *V, uint64_t NROM, const uint32_t *VROM,
uint32_t *XY, pwxform_ctx_t *ctx)
{
size_t s = 32 * r;
uint32_t *X = XY;
uint32_t *Y = &XY[s];
uint64_t i, j;
size_t k;
/* 1: X <-- B */
for (k = 0; k < 2 * r; k++)
for (i = 0; i < 16; i++)
X[k * 16 + i] = le32dec(&B[k * 16 + (i * 5 % 16)]);
/* 2: for i = 0 to N - 1 do */
for (i = 0; i < N; i++) {
/* 3: V_i <-- X */
blkcpy(&V[i * s], X, s);
if (VROM && i == 0) {
/* X <-- X xor VROM_{NROM-1} */
blkxor(X, &VROM[(NROM - 1) * s], s);
} else if (VROM && (i & 1)) {
/* j <-- Integerify(X) mod NROM */
j = integerify(X, r) & (NROM - 1);
/* X <-- X xor VROM_j */
blkxor(X, &VROM[j * s], s);
} else if ((flags & YESCRYPT_RW) && i > 1) {
/* j <-- Wrap(Integerify(X), i) */
j = wrap(integerify(X, r), i);
/* X <-- X xor V_j */
blkxor(X, &V[j * s], s);
}
/* 4: X <-- H(X) */
if (ctx)
blockmix_pwxform(X, ctx, r);
else
blockmix_salsa8(X, Y, r);
}
/* B' <-- X */
for (k = 0; k < 2 * r; k++)
for (i = 0; i < 16; i++)
le32enc(&B[k * 16 + (i * 5 % 16)], X[k * 16 + i]);
}
/**
* smix2(B, r, N, Nloop, flags, V, NROM, VROM, XY, ctx):
* Compute second loop of 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 bytes in length. The value N must be a power of 2
* greater than 1.
*/
static void smix2(uint32_t *B, size_t r, uint64_t N, uint64_t Nloop,
yescrypt_flags_t flags, uint32_t *V, uint64_t NROM,
const uint32_t *VROM, uint32_t *XY, pwxform_ctx_t *ctx)
{
size_t s = 32 * r;
uint32_t *X = XY;
uint32_t *Y = &XY[s];
uint64_t i, j;
size_t k;
/* X <-- B */
for (k = 0; k < 2 * r; k++)
for (i = 0; i < 16; i++)
X[k * 16 + i] = le32dec(&B[k * 16 + (i * 5 % 16)]);
/* 6: for i = 0 to N - 1 do */
for (i = 0; i < Nloop; i++) {
if (VROM && (i & 1)) {
/* j <-- Integerify(X) mod NROM */
j = integerify(X, r) & (NROM - 1);
/* X <-- H(X xor VROM_j) */
blkxor(X, &VROM[j * s], s);
} else {
/* 7: j <-- Integerify(X) mod N */
j = integerify(X, r) & (N - 1);
/* 8.1: X <-- X xor V_j */
blkxor(X, &V[j * s], s);
/* V_j <-- X */
if (flags & YESCRYPT_RW)
blkcpy(&V[j * s], X, s);
}
/* 8.2: X <-- H(X) */
if (ctx)
blockmix_pwxform(X, ctx, r);
else
blockmix_salsa8(X, Y, r);
}
/* 10: B' <-- X */
for (k = 0; k < 2 * r; k++)
for (i = 0; i < 16; i++)
le32enc(&B[k * 16 + (i * 5 % 16)], X[k * 16 + i]);
}
/**
* smix(B, r, N, p, t, flags, V, NROM, VROM, XY, ctx, passwd):
* Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the
* temporary storage V must be 128rN bytes in length; the temporary storage
* XY must be 256r bytes in length. The value N must be a power of 2 greater
* than 1.
*/
static void smix(uint32_t *B, size_t r, uint64_t N, uint32_t p, uint32_t t,
yescrypt_flags_t flags,
uint32_t *V, uint64_t NROM, const uint32_t *VROM,
uint32_t *XY, pwxform_ctx_t *ctx, uint8_t *passwd)
{
size_t s = 32 * r;
uint64_t Nchunk, Nloop_all, Nloop_rw, Vchunk;
uint32_t i;
/* 1: n <-- N / p */
Nchunk = N / p;
/* 2: Nloop_all <-- fNloop(n, t, flags) */
Nloop_all = Nchunk;
if (flags & YESCRYPT_RW) {
if (t <= 1) {
if (t)
Nloop_all *= 2; /* 2/3 */
Nloop_all = (Nloop_all + 2) / 3; /* 1/3, round up */
} else {
Nloop_all *= t - 1;
}
} else if (t) {
if (t == 1)
Nloop_all += (Nloop_all + 1) / 2; /* 1.5, round up */
Nloop_all *= t;
}
/* 6: Nloop_rw <-- 0 */
Nloop_rw = 0;
if (flags & YESCRYPT_INIT_SHARED) {
Nloop_rw = Nloop_all;
} else {
/* 3: if YESCRYPT_RW flag is set */
if (flags & YESCRYPT_RW) {
/* 4: Nloop_rw <-- Nloop_all / p */
Nloop_rw = Nloop_all / p;
}
}
/* 8: n <-- n - (n mod 2) */
Nchunk &= ~(uint64_t)1; /* round down to even */
/* 9: Nloop_all <-- Nloop_all + (Nloop_all mod 2) */
Nloop_all++; Nloop_all &= ~(uint64_t)1; /* round up to even */
/* 10: Nloop_rw <-- Nloop_rw + (Nloop_rw mod 2) */
Nloop_rw++; Nloop_rw &= ~(uint64_t)1; /* round up to even */
/* 11: for i = 0 to p - 1 do */
/* 12: u <-- in */
for (i = 0, Vchunk = 0; i < p; i++, Vchunk += Nchunk) {
/* 13: if i = p - 1 */
/* 14: n <-- N - u */
/* 15: end if */
/* 16: v <-- u + n - 1 */
uint64_t Np = (i < p - 1) ? Nchunk : (N - Vchunk);
uint32_t *Bp = &B[i * s];
uint32_t *Vp = &V[Vchunk * s];
pwxform_ctx_t *ctx_i = NULL;
/* 17: if YESCRYPT_RW flag is set */
if (flags & YESCRYPT_RW) {
ctx_i = &ctx[i];
/* 18: SMix1_1(B_i, Sbytes / 128, S_i, no flags) */
smix1(Bp, 1, Sbytes / 128, 0 /* no flags */,
ctx_i->S, 0, NULL, XY, NULL);
/* 19: S2_i <-- S_{i,0...2^Swidth-1} */
ctx_i->S2 = (uint32_t (*)[2])ctx_i->S;
/* 20: S1_i <-- S_{i,2^Swidth...2*2^Swidth-1} */
ctx_i->S1 = ctx_i->S2 + (1 << Swidth) * PWXsimple;
/* 21: S0_i <-- S_{i,2*2^Swidth...3*2^Swidth-1} */
ctx_i->S0 = ctx_i->S1 + (1 << Swidth) * PWXsimple;
/* 22: w_i <-- 0 */
ctx_i->w = 0;
/* 23: if i = 0 */
if (i == 0) {
/* 24: passwd <-- HMAC-SHA256(B_{0,2r-1}, passwd) */
HMAC_SHA256_Buf(Bp + (s - 16), 64,
passwd, 32, passwd);
}
}
/* 27: SMix1_r(B_i, n, V_{u..v}, flags) */
smix1(Bp, r, Np, flags, Vp, NROM, VROM, XY, ctx_i);
/* 28: SMix2_r(B_i, p2floor(n), Nloop_rw, V_{u..v}, flags) */
smix2(Bp, r, p2floor(Np), Nloop_rw, flags, Vp,
NROM, VROM, XY, ctx_i);
}
/* 30: for i = 0 to p - 1 do */
for (i = 0; i < p; i++) {
uint32_t *Bp = &B[i * s];
/* 31: SMix2_r(B_i, N, Nloop_all - Nloop_rw, V, flags excluding YESCRYPT_RW) */
smix2(Bp, r, N, Nloop_all - Nloop_rw, flags & ~YESCRYPT_RW,
V, NROM, VROM, XY, (flags & YESCRYPT_RW) ? &ctx[i] : NULL);
}
}
/**
* yescrypt_kdf_body(shared, local, passwd, passwdlen, salt, saltlen,
* flags, N, r, p, t, NROM, buf, buflen):
* Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
* p, buflen), or a revision of scrypt as requested by flags and shared, and
* write the result into buf.
*
* shared and flags may request special modes as described in yescrypt.h.
*
* local is the thread-local data structure, allowing optimized implementations
* to preserve and reuse a memory allocation across calls, thereby reducing its
* overhead (this reference implementation does not make that optimization).
*
* t controls computation time while not affecting peak memory usage.
*
* Return 0 on success; or -1 on error.
*/
static int yescrypt_kdf_body(const yescrypt_shared_t *shared,
yescrypt_local_t *local,
const uint8_t *passwd, size_t passwdlen,
const uint8_t *salt, size_t saltlen,
yescrypt_flags_t flags, uint64_t N, uint32_t r, uint32_t p, uint32_t t,
uint64_t NROM,
uint8_t *buf, size_t buflen)
{
int retval = -1;
const uint32_t *VROM;
size_t B_size, V_size;
uint32_t *B, *V, *XY, *S;
pwxform_ctx_t *pwxform_ctx;
uint32_t sha256[8];
uint8_t dk[sizeof(sha256)], *dkp = buf;
uint32_t i;
/* Sanity-check parameters */
switch (flags & YESCRYPT_MODE_MASK) {
case 0: /* classic scrypt - can't have anything non-standard */
if (flags || t || NROM)
goto out_EINVAL;
break;
case YESCRYPT_WORM:
if (flags != YESCRYPT_WORM || NROM)
goto out_EINVAL;
break;
case YESCRYPT_RW:
if (flags != (flags & YESCRYPT_KNOWN_FLAGS))
goto out_EINVAL;
#if PWXsimple == 2 && PWXgather == 4 && PWXrounds == 6 && Sbytes == 12288
if ((flags & YESCRYPT_RW_FLAVOR_MASK) ==
(YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 |
YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K))
break;
#else
#error "Unsupported pwxform settings"
#endif
/* FALLTHRU */
default:
goto out_EINVAL;
}
#if SIZE_MAX > UINT32_MAX
if (buflen > (((uint64_t)1 << 32) - 1) * 32)
goto out_EINVAL;
#endif
if ((uint64_t)r * (uint64_t)p >= 1 << 30)
goto out_EINVAL;
if ((N & (N - 1)) != 0 || N <= 1 || r < 1 || p < 1)
goto out_EINVAL;
if (r > SIZE_MAX / 128 / p ||
#if SIZE_MAX / 256 <= UINT32_MAX
r > SIZE_MAX / 256 ||
#endif
N > SIZE_MAX / 128 / r)
goto out_EINVAL;
if (N > UINT64_MAX / ((uint64_t)t + 1))
goto out_EINVAL;
if (flags & YESCRYPT_RW) {
if (N / p <= 1 || r < rmin ||
p > SIZE_MAX / Sbytes ||
p > SIZE_MAX / sizeof(*pwxform_ctx))
goto out_EINVAL;
}
VROM = NULL;
if (shared) {
uint64_t expected_size = (size_t)128 * r * NROM;
if ((NROM & (NROM - 1)) != 0 || NROM <= 1 ||
shared->aligned_size < expected_size)
goto out_EINVAL;
if (!(flags & YESCRYPT_INIT_SHARED)) {
uint32_t *tag = (uint32_t *)
((uint8_t *)shared->aligned + expected_size - 48);
uint64_t tag1 = ((uint64_t)tag[1] << 32) + tag[0];
uint64_t tag2 = ((uint64_t)tag[3] << 32) + tag[2];
if (tag1 != YESCRYPT_ROM_TAG1 || tag2 != YESCRYPT_ROM_TAG2)
goto out_EINVAL;
}
VROM = shared->aligned;
} else {
if (NROM)
goto out_EINVAL;
}
/* Allocate memory */
V_size = (size_t)128 * r * N;
if (flags & YESCRYPT_INIT_SHARED) {
V = (uint32_t *)local->aligned;
if (local->aligned_size < V_size) {
if (local->base || local->aligned ||
local->base_size || local->aligned_size)
goto out_EINVAL;
if ((V = malloc(V_size)) == NULL)
return -1;
local->base = local->aligned = V;
local->base_size = local->aligned_size = V_size;
}
if (flags & YESCRYPT_ALLOC_ONLY)
return -2; /* expected "failure" */
} else {
if ((V = malloc(V_size)) == NULL)
return -1;
}
B_size = (size_t)128 * r * p;
if ((B = malloc(B_size)) == NULL)
goto free_V;
if ((XY = malloc((size_t)256 * r)) == NULL)
goto free_B;
S = NULL;
pwxform_ctx = NULL;
if (flags & YESCRYPT_RW) {
if ((S = malloc((size_t)Sbytes * p)) == NULL)
goto free_XY;
if ((pwxform_ctx = malloc(sizeof(*pwxform_ctx) * p)) == NULL)
goto free_S;
}
if (flags) {
HMAC_SHA256_Buf("yescrypt-prehash",
(flags & YESCRYPT_PREHASH) ? 16 : 8,
passwd, passwdlen, (uint8_t *)sha256);
passwd = (uint8_t *)sha256;
passwdlen = sizeof(sha256);
}
/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1,
(uint8_t *)B, B_size);
if (flags)
blkcpy(sha256, B, sizeof(sha256) / sizeof(sha256[0]));
if (flags & YESCRYPT_RW) {
for (i = 0; i < p; i++)
pwxform_ctx[i].S = &S[i * Swords];
smix(B, r, N, p, t, flags, V, NROM, VROM, XY, pwxform_ctx,
(uint8_t *)sha256);
} else {
/* 2: for i = 0 to p - 1 do */
for (i = 0; i < p; i++) {
/* 3: B_i <-- MF(B_i, N) */
smix(&B[(size_t)32 * r * i], r, N, 1, t, flags, V,
NROM, VROM, XY, NULL, NULL);
}
}
dkp = buf;
if (flags && buflen < sizeof(dk)) {
PBKDF2_SHA256(passwd, passwdlen, (uint8_t *)B, B_size, 1,
dk, sizeof(dk));
dkp = dk;
}
/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
PBKDF2_SHA256(passwd, passwdlen, (uint8_t *)B, B_size, 1, buf, buflen);
/*
* Except when computing classic scrypt, allow all computation so far
* to be performed on the client. The final steps below match those of
* SCRAM (RFC 5802), so that an extension of SCRAM (with the steps so
* far in place of SCRAM's use of PBKDF2 and with SHA-256 in place of
* SCRAM's use of SHA-1) would be usable with yescrypt hashes.
*/
if (flags && !(flags & YESCRYPT_PREHASH)) {
/* Compute ClientKey */
HMAC_SHA256_Buf(dkp, sizeof(dk), "Client Key", 10,
(uint8_t *)sha256);
/* Compute StoredKey */
{
size_t clen = buflen;
if (clen > sizeof(dk))
clen = sizeof(dk);
SHA256_Buf((uint8_t *)sha256, sizeof(sha256), dk);
memcpy(buf, dk, clen);
}
}
/* Success! */
retval = 0;
/* Free memory */
free(pwxform_ctx);
free_S:
free(S);
free_XY:
free(XY);
free_B:
free(B);
free_V:
if (!(flags & YESCRYPT_INIT_SHARED))
free(V);
return retval;
out_EINVAL:
errno = EINVAL;
return -1;
}
/**
* yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, params,
* buf, buflen):
* Compute scrypt or its revision as requested by the parameters. The inputs
* to this function are the same as those for yescrypt_kdf_body() above, with
* the addition of g, which controls hash upgrades (0 for no upgrades so far).
*/
int yescrypt_kdf(const yescrypt_shared_t *shared, yescrypt_local_t *local,
const uint8_t *passwd, size_t passwdlen,
const uint8_t *salt, size_t saltlen,
const yescrypt_params_t *params,
uint8_t *buf, size_t buflen)
{
yescrypt_flags_t flags = params->flags;
uint64_t N = params->N;
uint32_t r = params->r;
uint32_t p = params->p;
uint32_t t = params->t;
uint32_t g = params->g;
uint64_t NROM = params->NROM;
uint8_t dk[32];
/* Support for hash upgrades has been temporarily removed */
if (g) {
errno = EINVAL;
return -1;
}
if ((flags & YESCRYPT_RW) &&
p >= 1 && N / p >= 0x100 && N / p * r >= 0x20000) {
/*
* This reference implementation's yescrypt_kdf_body()
* (de)allocates memory on each call, which defeats the purpose
* of this pre-hashing. The optimized implementations, which
* you should actually use, make the larger allocation first
* and then reuse it. Thus, this implementation doing things
* differently serves as a test that the computation result is
* unaffected by such differences.
*/
int retval = yescrypt_kdf_body(shared, local,
passwd, passwdlen, salt, saltlen,
flags | YESCRYPT_PREHASH, N >> 6, r, p, 0, NROM,
dk, sizeof(dk));
if (retval)
return retval;
passwd = dk;
passwdlen = sizeof(dk);
}
return yescrypt_kdf_body(shared, local,
passwd, passwdlen, salt, saltlen,
flags, N, r, p, t, NROM, buf, buflen);
}
int yescrypt_init_shared(yescrypt_shared_t *shared,
const uint8_t *seed, size_t seedlen,
const yescrypt_params_t *params)
{
yescrypt_flags_t flags = params->flags;
uint64_t N = params->NROM;
uint32_t r = params->r;
uint32_t p = params->p;
uint32_t t = params->t;
yescrypt_shared_t half1, half2;
uint8_t salt[32];
uint32_t *tag;
if (!(params->flags & YESCRYPT_RW) || params->N || params->g)
return -1;
if (flags & YESCRYPT_SHARED_PREALLOCATED) {
if (!shared->aligned || !shared->aligned_size)
return -1;
/* Overwrite a possible old ROM tag before we overwrite the rest */
tag = (uint32_t *)
((uint8_t *)shared->aligned + shared->aligned_size - 48);
memset(tag, 0, 48);
} else {
shared->base = shared->aligned = NULL;
shared->base_size = shared->aligned_size = 0;
if (yescrypt_kdf_body(NULL, shared, NULL, 0, NULL, 0,
flags | YESCRYPT_INIT_SHARED | YESCRYPT_ALLOC_ONLY,
N, r, p, t, 0, NULL, 0) != -2 || !shared->aligned)
goto fail;
}
half1 = half2 = *shared;
half1.aligned_size /= 2;
half2.aligned = (uint8_t *)half2.aligned + half1.aligned_size;
half2.aligned_size = half1.aligned_size;
N /= 2;
if (yescrypt_kdf_body(NULL, &half1,
seed, seedlen, (const uint8_t *)"yescrypt-ROMhash", 16,
flags | YESCRYPT_INIT_SHARED, N, r, p, t, 0,
salt, sizeof(salt)))
goto fail;
if (yescrypt_kdf_body(&half1, &half2,
seed, seedlen, salt, sizeof(salt),
flags | YESCRYPT_INIT_SHARED, N, r, p, t, N,
salt, sizeof(salt)))
goto fail;
if (yescrypt_kdf_body(&half2, &half1,
seed, seedlen, salt, sizeof(salt),
flags | YESCRYPT_INIT_SHARED, N, r, p, t, N,
salt, sizeof(salt)))
goto fail;
tag = (uint32_t *)
((uint8_t *)shared->aligned + shared->aligned_size - 48);
tag[0] = YESCRYPT_ROM_TAG1 & 0xffffffffU;
tag[1] = YESCRYPT_ROM_TAG1 >> 32;
tag[2] = YESCRYPT_ROM_TAG2 & 0xffffffffU;
tag[3] = YESCRYPT_ROM_TAG2 >> 32;
tag[4] = le32dec(salt);
tag[5] = le32dec(salt + 4);
tag[6] = le32dec(salt + 8);
tag[7] = le32dec(salt + 12);
tag[8] = le32dec(salt + 16);
tag[9] = le32dec(salt + 20);
tag[10] = le32dec(salt + 24);
tag[11] = le32dec(salt + 28);
return 0;
fail:
if (!(flags & YESCRYPT_SHARED_PREALLOCATED))
free(shared->base);
return -1;
}
yescrypt_binary_t *yescrypt_digest_shared(yescrypt_shared_t *shared)
{
static yescrypt_binary_t digest;
uint32_t *tag;
uint64_t tag1, tag2;
if (shared->aligned_size < 48)
return NULL;
tag = (uint32_t *)
((uint8_t *)shared->aligned + shared->aligned_size - 48);
tag1 = ((uint64_t)tag[1] << 32) + tag[0];
tag2 = ((uint64_t)tag[3] << 32) + tag[2];
if (tag1 != YESCRYPT_ROM_TAG1 || tag2 != YESCRYPT_ROM_TAG2)
return NULL;
le32enc(digest.uc, tag[4]);
le32enc(digest.uc + 4, tag[5]);
le32enc(digest.uc + 8, tag[6]);
le32enc(digest.uc + 12, tag[7]);
le32enc(digest.uc + 16, tag[8]);
le32enc(digest.uc + 20, tag[9]);
le32enc(digest.uc + 24, tag[10]);
le32enc(digest.uc + 28, tag[11]);
return &digest;
}
int yescrypt_free_shared(yescrypt_shared_t *shared)
{
free(shared->base);
shared->base = shared->aligned = NULL;
shared->base_size = shared->aligned_size = 0;
return 0;
}
int yescrypt_init_local(yescrypt_local_t *local)
{
/* The reference implementation doesn't use the local structure */
local->base = local->aligned = NULL;
local->base_size = local->aligned_size = 0;
return 0;
}
int yescrypt_free_local(yescrypt_local_t *local)
{
/* The reference implementation frees its memory in yescrypt_kdf() */
(void)local; /* unused */
return 0;
}

View File

@@ -0,0 +1,346 @@
/*-
* Copyright 2009 Colin Percival
* Copyright 2013-2018 Alexander Peslyak
* 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 _YESCRYPT_H_
#define _YESCRYPT_H_
#include <stdint.h>
#include <stdlib.h> /* for size_t */
#ifdef __cplusplus
extern "C" {
#endif
/**
* 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.
*
* MT-safe as long as buf is local to the thread.
*/
extern 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);
/**
* Internal type used by the memory allocator. Please do not use it directly.
* Use yescrypt_shared_t and yescrypt_local_t as appropriate instead, since
* they might differ from each other in a future version.
*/
typedef struct {
void *base, *aligned;
size_t base_size, aligned_size;
} yescrypt_region_t;
/**
* Types for shared (ROM) and thread-local (RAM) data structures.
*/
typedef yescrypt_region_t yescrypt_shared_t;
typedef yescrypt_region_t yescrypt_local_t;
/**
* Two 64-bit tags placed 48 bytes to the end of a ROM in host byte endianness
* (and followed by 32 bytes of the ROM digest).
*/
#define YESCRYPT_ROM_TAG1 0x7470797263736579ULL /* "yescrypt" */
#define YESCRYPT_ROM_TAG2 0x687361684d4f522dULL /* "-ROMhash" */
/**
* Type and possible values for the flags argument of yescrypt_kdf(),
* yescrypt_encode_params_r(), yescrypt_encode_params(). Most of these may be
* OR'ed together, except that YESCRYPT_WORM stands on its own.
* Please refer to the description of yescrypt_kdf() below for the meaning of
* these flags.
*/
typedef uint32_t yescrypt_flags_t;
/* Public */
#define YESCRYPT_WORM 1
#define YESCRYPT_RW 0x002
#define YESCRYPT_ROUNDS_3 0x000
#define YESCRYPT_ROUNDS_6 0x004
#define YESCRYPT_GATHER_1 0x000
#define YESCRYPT_GATHER_2 0x008
#define YESCRYPT_GATHER_4 0x010
#define YESCRYPT_GATHER_8 0x018
#define YESCRYPT_SIMPLE_1 0x000
#define YESCRYPT_SIMPLE_2 0x020
#define YESCRYPT_SIMPLE_4 0x040
#define YESCRYPT_SIMPLE_8 0x060
#define YESCRYPT_SBOX_6K 0x000
#define YESCRYPT_SBOX_12K 0x080
#define YESCRYPT_SBOX_24K 0x100
#define YESCRYPT_SBOX_48K 0x180
#define YESCRYPT_SBOX_96K 0x200
#define YESCRYPT_SBOX_192K 0x280
#define YESCRYPT_SBOX_384K 0x300
#define YESCRYPT_SBOX_768K 0x380
/* Only valid for yescrypt_init_shared() */
#define YESCRYPT_SHARED_PREALLOCATED 0x10000
#ifdef YESCRYPT_INTERNAL
/* Private */
#define YESCRYPT_MODE_MASK 0x003
#define YESCRYPT_RW_FLAVOR_MASK 0x3fc
#define YESCRYPT_INIT_SHARED 0x01000000
#define YESCRYPT_ALLOC_ONLY 0x08000000
#define YESCRYPT_PREHASH 0x10000000
#endif
#define YESCRYPT_RW_DEFAULTS \
(YESCRYPT_RW | \
YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | \
YESCRYPT_SBOX_12K)
#define YESCRYPT_DEFAULTS YESCRYPT_RW_DEFAULTS
#ifdef YESCRYPT_INTERNAL
#define YESCRYPT_KNOWN_FLAGS \
(YESCRYPT_MODE_MASK | YESCRYPT_RW_FLAVOR_MASK | \
YESCRYPT_SHARED_PREALLOCATED | \
YESCRYPT_INIT_SHARED | YESCRYPT_ALLOC_ONLY | YESCRYPT_PREHASH)
#endif
/**
* yescrypt parameters combined into one struct. N, r, p are the same as in
* classic scrypt, except that the meaning of p changes when YESCRYPT_RW is
* set. flags, t, g, NROM are special to yescrypt.
*/
typedef struct {
yescrypt_flags_t flags;
uint64_t N;
uint32_t r, p, t, g;
uint64_t NROM;
} yescrypt_params_t;
/**
* A 256-bit yescrypt hash, or a hash encryption key (which may itself have
* been derived as a yescrypt hash of a human-specified key string).
*/
typedef union {
unsigned char uc[32];
uint64_t u64[4];
} yescrypt_binary_t;
/**
* yescrypt_init_shared(shared, seed, seedlen, params):
* Optionally allocate memory for and initialize the shared (ROM) data
* structure. The parameters flags, NROM, r, p, and t specify how the ROM is
* to be initialized, and seed and seedlen specify the initial seed affecting
* the data with which the ROM is filled.
*
* Return 0 on success; or -1 on error.
*
* If bit YESCRYPT_SHARED_PREALLOCATED in flags is set, then memory for the
* ROM is assumed to have been preallocated by the caller, with shared->aligned
* being the start address of the ROM and shared->aligned_size being its size
* (which must be sufficient for NROM, r, p). This may be used e.g. when the
* ROM is to be placed in a SysV shared memory segment allocated by the caller.
*
* MT-safe as long as shared is local to the thread.
*/
extern int yescrypt_init_shared(yescrypt_shared_t *shared,
const uint8_t *seed, size_t seedlen, const yescrypt_params_t *params);
/**
* yescrypt_digest_shared(shared):
* Extract the previously stored message digest of the provided yescrypt ROM.
*
* Return pointer to the message digest on success; or NULL on error.
*
* MT-unsafe.
*/
extern yescrypt_binary_t *yescrypt_digest_shared(yescrypt_shared_t *shared);
/**
* yescrypt_free_shared(shared):
* Free memory that had been allocated with yescrypt_init_shared().
*
* Return 0 on success; or -1 on error.
*
* MT-safe as long as shared is local to the thread.
*/
extern int yescrypt_free_shared(yescrypt_shared_t *shared);
/**
* yescrypt_init_local(local):
* Initialize the thread-local (RAM) data structure. Actual memory allocation
* is currently fully postponed until a call to yescrypt_kdf() or yescrypt_r().
*
* Return 0 on success; or -1 on error.
*
* MT-safe as long as local is local to the thread.
*/
extern int yescrypt_init_local(yescrypt_local_t *local);
/**
* yescrypt_free_local(local):
* Free memory that may have been allocated for an initialized thread-local
* (RAM) data structure.
*
* Return 0 on success; or -1 on error.
*
* MT-safe as long as local is local to the thread.
*/
extern int yescrypt_free_local(yescrypt_local_t *local);
/**
* yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, params,
* buf, buflen):
* Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
* p, buflen), or a revision of scrypt as requested by flags and shared, and
* write the result into buf. The parameters N, r, p, and buflen must satisfy
* the same conditions as with crypto_scrypt(). t controls computation time
* while not affecting peak memory usage (t = 0 is optimal unless higher N*r
* is not affordable while higher t is). g controls hash upgrades (g = 0 for
* no upgrades so far). shared and flags may request special modes. local is
* the thread-local data structure, allowing to preserve and reuse a memory
* allocation across calls, thereby reducing processing overhead.
*
* Return 0 on success; or -1 on error.
*
* Classic scrypt is available by setting shared = NULL, flags = 0, and t = 0.
*
* Setting YESCRYPT_WORM enables only minimal deviations from classic scrypt:
* support for the t parameter, and pre- and post-hashing.
*
* Setting YESCRYPT_RW fully enables yescrypt. As a side effect of differences
* between the algorithms, it also prevents p > 1 from growing the threads'
* combined processing time and memory allocation (like it did with classic
* scrypt and YESCRYPT_WORM), treating p as a divider rather than a multiplier.
*
* Passing a shared structure, with ROM contents previously computed by
* yescrypt_init_shared(), enables the use of ROM and requires YESCRYPT_RW.
*
* In order to allow for initialization of the ROM to be split into a separate
* program (or separate invocation of the same program), the shared->aligned
* and shared->aligned_size fields may optionally be set by the caller directly
* (e.g., to a mapped SysV shm segment), without using yescrypt_init_shared().
*
* local must be initialized with yescrypt_init_local().
*
* MT-safe as long as local and buf are local to the thread.
*/
extern int yescrypt_kdf(const yescrypt_shared_t *shared,
yescrypt_local_t *local,
const uint8_t *passwd, size_t passwdlen,
const uint8_t *salt, size_t saltlen,
const yescrypt_params_t *params,
uint8_t *buf, size_t buflen);
/**
* yescrypt_r(shared, local, passwd, passwdlen, setting, key, buf, buflen):
* Compute and encode an scrypt or enhanced scrypt hash of passwd given the
* parameters and salt value encoded in setting. If shared is not NULL, a ROM
* is used and YESCRYPT_RW is required. Otherwise, whether to compute classic
* scrypt, YESCRYPT_WORM (a slight deviation from classic scrypt), or
* YESCRYPT_RW (time-memory tradeoff discouraging modification) is determined
* by the setting string. shared (if not NULL) and local must be initialized
* as described above for yescrypt_kdf(). buf must be large enough (as
* indicated by buflen) to hold the encoded hash string.
*
* Return the encoded hash string on success; or NULL on error.
*
* MT-safe as long as local and buf are local to the thread.
*/
extern uint8_t *yescrypt_r(const yescrypt_shared_t *shared,
yescrypt_local_t *local,
const uint8_t *passwd, size_t passwdlen,
const uint8_t *setting,
const yescrypt_binary_t *key,
uint8_t *buf, size_t buflen);
/**
* yescrypt(passwd, setting):
* Compute and encode an scrypt or enhanced scrypt hash of passwd given the
* parameters and salt value encoded in setting. Whether to compute classic
* scrypt, YESCRYPT_WORM (a slight deviation from classic scrypt), or
* YESCRYPT_RW (time-memory tradeoff discouraging modification) is determined
* by the setting string.
*
* Return the encoded hash string on success; or NULL on error.
*
* This is a crypt(3)-like interface, which is simpler to use than
* yescrypt_r(), but it is not MT-safe, it does not allow for the use of a ROM,
* and it is slower than yescrypt_r() for repeated calls because it allocates
* and frees memory on each call.
*
* MT-unsafe.
*/
extern uint8_t *yescrypt(const uint8_t *passwd, const uint8_t *setting);
/**
* yescrypt_reencrypt(hash, from_key, to_key):
* Re-encrypt a yescrypt hash from one key to another. Either key may be NULL
* to indicate unencrypted hash. The encoded hash string is modified in-place.
*
* Return the hash pointer on success; or NULL on error (in which case the hash
* string is left unmodified).
*
* MT-safe as long as hash is local to the thread.
*/
extern uint8_t *yescrypt_reencrypt(uint8_t *hash,
const yescrypt_binary_t *from_key,
const yescrypt_binary_t *to_key);
/**
* yescrypt_encode_params_r(params, src, srclen, buf, buflen):
* Generate a setting string for use with yescrypt_r() and yescrypt() by
* encoding into it the parameters flags, N, r, p, t, g, and a salt given by
* src (of srclen bytes). buf must be large enough (as indicated by buflen)
* to hold the setting string.
*
* Return the setting string on success; or NULL on error.
*
* MT-safe as long as buf is local to the thread.
*/
extern uint8_t *yescrypt_encode_params_r(const yescrypt_params_t *params,
const uint8_t *src, size_t srclen,
uint8_t *buf, size_t buflen);
/**
* yescrypt_encode_params(params, src, srclen):
* Generate a setting string for use with yescrypt_r() and yescrypt(). This
* function is the same as yescrypt_encode_params_r() except that it uses a
* static buffer and thus is not MT-safe.
*
* Return the setting string on success; or NULL on error.
*
* MT-unsafe.
*/
extern uint8_t *yescrypt_encode_params(const yescrypt_params_t *params,
const uint8_t *src, size_t srclen);
#ifdef __cplusplus
}
#endif
#endif /* !_YESCRYPT_H_ */