From 3240af28b2f1e9fd43fdf97ab7a060502a08c294 Mon Sep 17 00:00:00 2001 From: Vlad Pruteanu Date: Thu, 26 Mar 2026 00:12:49 +0200 Subject: [PATCH] testing/crypto: Add pbkdf2 test app This adds support for testing PBKDF2 implementation. Test vectors for SHA1 are taken from RFC6070. SHA256 vectors were extrapolated using an online PBKDF2 generator which was checked against RFC6070. Signed-off-by: Vlad Pruteanu --- testing/drivers/crypto/CMakeLists.txt | 14 ++ testing/drivers/crypto/Kconfig | 4 + testing/drivers/crypto/Makefile | 5 + testing/drivers/crypto/pbkdf2.c | 278 ++++++++++++++++++++++++++ 4 files changed, 301 insertions(+) create mode 100644 testing/drivers/crypto/pbkdf2.c diff --git a/testing/drivers/crypto/CMakeLists.txt b/testing/drivers/crypto/CMakeLists.txt index 3918043a134..6e7fb369f3d 100644 --- a/testing/drivers/crypto/CMakeLists.txt +++ b/testing/drivers/crypto/CMakeLists.txt @@ -175,4 +175,18 @@ if(CONFIG_TESTING_CRYPTO) rsa.c) endif() + if(CONFIG_TESTING_CRYPTO_PBKDF2) + nuttx_add_application( + NAME + pbkdf2 + PRIORITY + ${CONFIG_TESTING_CRYPTO_PRIORITY} + STACKSIZE + ${CONFIG_TESTING_CRYPTO_STACKSIZE} + MODULE + ${CONFIG_TESTING_CRYPTO} + SRCS + pbkdf2.c) + endif() + endif() diff --git a/testing/drivers/crypto/Kconfig b/testing/drivers/crypto/Kconfig index 8eca7f72802..fe8ae58baaa 100644 --- a/testing/drivers/crypto/Kconfig +++ b/testing/drivers/crypto/Kconfig @@ -58,6 +58,10 @@ config TESTING_CRYPTO_RSA bool "rsa crypto test" default n +config TESTING_CRYPTO_PBKDF2 + bool "pbkdf2 crypto test" + default n + config TESTING_CRYPTO_PRIORITY int "crypto test task priority" default 100 diff --git a/testing/drivers/crypto/Makefile b/testing/drivers/crypto/Makefile index 64c6dfac744..82aeebef0a5 100644 --- a/testing/drivers/crypto/Makefile +++ b/testing/drivers/crypto/Makefile @@ -78,6 +78,11 @@ PROGNAME += rsa MAINSRC += rsa.c endif +ifeq ($(CONFIG_TESTING_CRYPTO_PBKDF2),y) +PROGNAME += pbkdf2 +MAINSRC += pbkdf2.c +endif + PRIORITY = $(CONFIG_TESTING_CRYPTO_PRIORITY) STACKSIZE = $(CONFIG_TESTING_CRYPTO_STACKSIZE) MODULE = $(CONFIG_TESTING_CRYPTO) diff --git a/testing/drivers/crypto/pbkdf2.c b/testing/drivers/crypto/pbkdf2.c new file mode 100644 index 00000000000..10e7174efe6 --- /dev/null +++ b/testing/drivers/crypto/pbkdf2.c @@ -0,0 +1,278 @@ +/**************************************************************************** + * apps/testing/drivers/crypto/pbkdf2.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct tb +{ + FAR char *key; + int keylen; + FAR char *data; + int datalen; + int iterations; + int dklen; +} +pbkdf2_testcases[] = +{ + { + "password", + 8, + "salt", + 4, + 1, + 20, + }, + { + "password", + 8, + "salt", + 4, + 2, + 20, + }, + { + "password", + 8, + "salt", + 4, + 4096, + 20, + }, + { + "password", + 8, + "salt", + 4, + 16777216, + 20, + }, + { + "passwordPASSWORDpassword", + 24, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + 36, + 4096, + 25, + }, + { + "pass\0word", + 9, + "sa\0lt", + 5, + 4096, + 16, + }, +}; + +FAR char *pbkdf2_sha1_result[] = +{ + "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24\xaf\x60\x12\x06" + "\x2f\xe0\x37\xa6", + "\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a\xce\x1d\x41\xf0" + "\xd8\xde\x89\x57", + "\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26\xf7\x21\xd0" + "\x65\xa4\x29\xc1", + "\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94\x5b\x3d\x6b\xa2\x15\x8c" + "\x26\x34\xe9\x84", + "\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62\xc0\xe4\x4a" + "\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38", + "\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34\x25\xe0\xc3", +}; + +FAR char *pbkdf2_sha256_result[] = +{ + "\x12\x0f\xb6\xcf\xfc\xf8\xb3\x2c\x43\xe7\x22\x52\x56\xc4\xf8\x37" + "\xa8\x65\x48\xc9", + "\xae\x4d\x0c\x95\xaf\x6b\x46\xd3\x2d\x0a\xdf\xf9\x28\xf0\x6d\xd0" + "\x2a\x30\x3f\x8e", + "\xc5\xe4\x78\xd5\x92\x88\xc8\x41\xaa\x53\x0d\xb6\x84\x5c\x4c\x8d" + "\x96\x28\x93\xa0", + "\xcf\x81\xc6\x6f\xe8\xcf\xc0\x4d\x1f\x31\xec\xb6\x5d\xab\x40\x89" + "\xf7\xf1\x79\xe8", + "\x34\x8c\x89\xdb\xcb\xd3\x2b\x2f\x32\xd8\x14\xb8\x11\x6e\x84\xcf" + "\x2b\x17\x34\x7e\xbc\x18\x00\x18\x1c", + "\x89\xb6\x9d\x05\x16\xf8\x29\x89\x3c\x69\x62\x26\x65\x0a\x86\x87", +}; + +int syspbkdf2(int mac, FAR const char *key, size_t keylen, + FAR const char *s, size_t len, int iterations, + size_t dklen, FAR char *out) +{ + struct session_op session; + struct crypt_op cryp; + int cryptodev_fd = -1; + int fd = -1; + + if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) + { + warn("/dev/crypto"); + goto err; + } + + if (ioctl(fd, CRIOGET, &cryptodev_fd) == -1) + { + warn("CRIOGET"); + goto err; + } + + memset(&session, 0, sizeof(session)); + session.cipher = 0; + session.mac = mac; + session.mackey = (caddr_t)key; + session.mackeylen = keylen; + if (ioctl(cryptodev_fd, CIOCGSESSION, &session) == -1) + { + warn("CIOCGSESSION"); + goto err; + } + memset(&cryp, 0, sizeof(cryp)); + cryp.ses = session.ses; + cryp.flags = 0; + cryp.src = (caddr_t)s; + cryp.len = len; + cryp.dst = 0; + cryp.mac = (caddr_t) out; + cryp.iv = 0; + cryp.iterations = iterations; + cryp.olen = dklen; + + if (ioctl(cryptodev_fd, CIOCCRYPT, &cryp) == -1) + { + warn("CIOCCRYPT"); + goto err; + } + + close(cryptodev_fd); + close(fd); + + return 0; +err: + if (cryptodev_fd != -1) + { + close(cryptodev_fd); + } + + if (fd != -1) + { + close(fd); + } + + return 1; +} + +static int match(unsigned char *a, unsigned char *b, size_t len) +{ + int i; + + if (memcmp(a, b, len) == 0) + return (0); + + warnx("pbkdf2 mismatch\n"); + + for (i = 0; i < len; i++) + { + printf("%02x", a[i]); + } + + printf("\n"); + for (i = 0; i < len; i++) + { + printf("%02x", b[i]); + } + + printf("\n"); + + return (1); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(void) +{ + char output[40]; + int ret = 0; + for (int i = 0; i < 6; i++) + { + ret = syspbkdf2(CRYPTO_PBKDF2_HMAC_SHA1, pbkdf2_testcases[i].key, + pbkdf2_testcases[i].keylen, + pbkdf2_testcases[i].data, + pbkdf2_testcases[i].datalen, + pbkdf2_testcases[i].iterations, + pbkdf2_testcases[i].dklen, output); + if (ret) + { + printf("PBKDF2 SHA1 failed\n"); + } + + ret += match((unsigned char *)pbkdf2_sha1_result[i], + (unsigned char *)output, + pbkdf2_testcases[i].dklen); + if (ret) + { + printf("match PBKDF2 SHA1 failed\n"); + } + else + { + printf("hmac PBKDF2 SHA1 success\n"); + } + } + + for (int i = 0; i < 6; i++) + { + ret = syspbkdf2(CRYPTO_PBKDF2_HMAC_SHA256, pbkdf2_testcases[i].key, + pbkdf2_testcases[i].keylen, + pbkdf2_testcases[i].data, + pbkdf2_testcases[i].datalen, + pbkdf2_testcases[i].iterations, + pbkdf2_testcases[i].dklen, output); + if (ret) + { + printf("PBKDF2 SHA256 failed\n"); + } + + ret += match((unsigned char *)pbkdf2_sha256_result[i], + (unsigned char *)output, + pbkdf2_testcases[i].dklen); + if (ret) + { + printf("match PBKDF2 SHA256 failed\n"); + } + else + { + printf("hmac PBKDF2 SHA256 success\n"); + } + } + + return 0; +}