Skip to content

Commit

Permalink
Merge pull request #18941 from maribu/backport/2022.10/sys/hashes/pbkdf2
Browse files Browse the repository at this point in the history
tests/pbkdf2: de-flaky-fy test [backport 2022.10]
  • Loading branch information
maribu authored Nov 22, 2022
2 parents c33e91b + 2f6dd98 commit 70495b1
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 291 deletions.
4 changes: 2 additions & 2 deletions sys/hashes/pbkdf2.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ static void inplace_xor_digests(uint8_t *d1, const uint8_t *d2)
}
}

void pbkdf2_sha256(const uint8_t *password, size_t password_len,
const uint8_t *salt, size_t salt_len,
void pbkdf2_sha256(const void *password, size_t password_len,
const void *salt, size_t salt_len,
int iterations,
uint8_t *output)
{
Expand Down
4 changes: 2 additions & 2 deletions sys/include/hashes/pbkdf2.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ extern "C" {
* recommended 10000
* @param[out] output array of size PBKDF2_KEY_SIZE
*/
void pbkdf2_sha256(const uint8_t *password, size_t password_len,
const uint8_t *salt, size_t salt_len,
void pbkdf2_sha256(const void *password, size_t password_len,
const void *salt, size_t salt_len,
int iterations,
uint8_t *output);

Expand Down
15 changes: 1 addition & 14 deletions tests/pbkdf2/Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
include ../Makefile.tests_common

# This application uses getchar and thus expects input from stdio
USEMODULE += stdin
USEMODULE += hashes
USEMODULE += base64

# Use a terminal that does not introduce extra characters into the stream.
RIOT_TERMINAL ?= socat

#ensure the rx buffer has some room even with large test patterns
CFLAGS += -DSTDIO_UART_RX_BUFSIZE=128
USEMODULE += fmt

include $(RIOTBASE)/Makefile.include

# Increase Stack size for AVR
ifneq (,$(filter avr8_common,$(USEMODULE)))
CFLAGS += -DTHREAD_STACKSIZE_MAIN=THREAD_STACKSIZE_LARGE
endif
186 changes: 79 additions & 107 deletions tests/pbkdf2/main.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2019 Freie Universität Berlin.
* 2022 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
Expand All @@ -13,132 +14,103 @@
* @brief Test PBKDF2-sha256 implementation.
*
* @author Juan Carrano <j.carrano@fu-berlin.de>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* This application reads (password, salt, iterations) tuples from the
* standard input and outputs the derived key.
*
* The salt must be base64 encoded. The key is printed as base64.
* @}
*/

#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "base64.h"
#include "fmt.h"
#include "hashes/pbkdf2.h"
#include "hashes/sha256.h"
#include "kernel_defines.h"

const char error_message[] = "{error}";
const char input_message[] = "{ready}";

#define LINEBUF_SZ (128)
static uint8_t key[SHA256_DIGEST_LENGTH];

enum TEST_STATE {
TEST_READ_PASS,
TEST_READ_SALT,
TEST_READ_ITERS,
TEST_COMPUTE,
TEST_ERROR
struct testcase {
const char *password;
const char *salt;
uint16_t iterations;
const uint8_t digest[sizeof(key)];
};

static void _clear_input(void)
{
/* clear input buffer */
int c;
while ( (c = getchar()) != '\n' && c != EOF ) { }
}
struct testcase testcases[] = {
{
.password = "passwd",
.salt = "salt",
.iterations = 1,
/* dig = hashlib.pbkdf2_hmac("sha256", "passwd".encode("utf-8"),
* "salt".encode("utf-8"), 1)
* "".join("0x{:02x}, ".format(b) for b in dig)
*/
.digest = {
0x55, 0xac, 0x04, 0x6e, 0x56, 0xe3, 0x08, 0x9f,
0xec, 0x16, 0x91, 0xc2, 0x25, 0x44, 0xb6, 0x05,
0xf9, 0x41, 0x85, 0x21, 0x6d, 0xde, 0x04, 0x65,
0xe6, 0x8b, 0x9d, 0x57, 0xc2, 0x0d, 0xac, 0xbc,
}
},
{
.password = "RIOT",
.salt = "rocks",
.iterations = 16,
/* dig = hashlib.pbkdf2_hmac("sha256", "RIOT".encode("utf-8"),
* "rocks".encode("utf-8"), 16)
* "".join("0x{:02x}, ".format(b) for b in dig)
*/
.digest = {
0x72, 0xa6, 0x06, 0xbb, 0x5c, 0xbe, 0x92, 0x4a,
0xd2, 0x0a, 0xee, 0xc2, 0x4e, 0xa5, 0x17, 0xc4,
0xd7, 0xb1, 0x1d, 0x04, 0x9d, 0x84, 0xbb, 0x29,
0x6b, 0x36, 0xad, 0x90, 0x4d, 0x6f, 0x79, 0xdf,
}
},
{
.password = "This is a secure password", /* <-- no it is NOT! */
.salt = "and this salt is even more secure",
.iterations = 13,
/* dig = hashlib.pbkdf2_hmac("sha256",
* "This is a secure password".encode("utf-8"),
* "and this salt is even more secure".encode("utf-8"),
* 13)
* "".join("0x{:02x}, ".format(b) for b in dig)
*/
.digest = {
0x9a, 0x41, 0x83, 0x2b, 0x77, 0xc4, 0x61, 0x64,
0x06, 0xd3, 0x2e, 0x97, 0x06, 0x5e, 0xc5, 0xc7,
0xe1, 0xa0, 0x18, 0x75, 0x01, 0xfe, 0xb8, 0xc8,
0x70, 0x92, 0x28, 0x0e, 0x1d, 0x1a, 0x00, 0xb6,
}
},
};

int main(void)
{
static char linebuf[LINEBUF_SZ];

/* There will be a few bytes wasted here */
static char password[LINEBUF_SZ];
static uint8_t salt[LINEBUF_SZ];
static uint8_t key[PBKDF2_KEY_SIZE];

size_t passwd_len = 0, salt_len = 0;
int iterations = 0;

enum TEST_STATE state = TEST_READ_PASS;

_clear_input();

while ((puts(input_message), fgets(linebuf, LINEBUF_SZ, stdin) != NULL)) {
char *s_end;
int conversion_status, line_len = strlen(linebuf)-1;
size_t b64_buff_size;

linebuf[line_len] = '\0';

switch (state) {
case TEST_READ_PASS:
strcpy(password, linebuf);
passwd_len = line_len;
state++;

break;
case TEST_READ_SALT:
/* work around bug in base64_decode */
if (line_len == 0) {
salt_len = 0;
conversion_status = BASE64_SUCCESS;
} else {
salt_len = sizeof(salt);
conversion_status = base64_decode((uint8_t*)linebuf,
line_len+1,
salt, &salt_len);
}

if (conversion_status == BASE64_SUCCESS) {
state++;
} else {
state = TEST_ERROR;
}

break;
case TEST_READ_ITERS:
iterations = strtol(linebuf, &s_end, 10);

if (*s_end != '\0') {
state = TEST_ERROR;
} else {
state++;
}

break;
default:
assert(1);
break;
bool failed = false;
for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) {
struct testcase *tc = &testcases[i];
size_t password_len = strlen(tc->password);
size_t salt_len = strlen(tc->salt);
memset(key, 0x00, sizeof(key));
pbkdf2_sha256(tc->password, password_len, tc->salt, salt_len,
tc->iterations, key);

if (memcmp(tc->digest, key, sizeof(key)) != 0) {
failed = true;
print_str("Test vector ");
print_u32_dec((uint32_t)i);
print_str(": FAILED\n");
}

switch (state) {
case TEST_COMPUTE:
pbkdf2_sha256((uint8_t*)password, passwd_len, salt, salt_len,
iterations, key);

b64_buff_size = sizeof(linebuf);
conversion_status = base64_encode(key, sizeof(key),
(uint8_t*)linebuf,
&b64_buff_size);

if (conversion_status == BASE64_SUCCESS) {
linebuf[b64_buff_size] = 0;
puts(linebuf);
} else {
puts(error_message);
}
}

state = TEST_READ_PASS;
break;
case TEST_ERROR:
puts(error_message);
state = TEST_READ_PASS;
break;
default:
break;
}
if (!failed) {
print_str("TEST PASSED\n");
}

return 0;
Expand Down
42 changes: 0 additions & 42 deletions tests/pbkdf2/tests/01-rfc.py

This file was deleted.

20 changes: 20 additions & 0 deletions tests/pbkdf2/tests/01-run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env python3

# Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.

# @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>

import sys
from testrunner import run


def testfunc(child):
child.expect("TEST PASSED")


if __name__ == "__main__":
sys.exit(run(testfunc))
Loading

0 comments on commit 70495b1

Please sign in to comment.