test: add test_hchacha

This commit is contained in:
d0p1 🏳️‍⚧️ 2024-06-15 17:03:51 +00:00
parent 2a79e08343
commit 2e5886303d
13 changed files with 304 additions and 17 deletions

4
.gitignore vendored
View file

@ -33,3 +33,7 @@ html/
mkfs.stpd mkfs.stpd
*.gz *.gz
*.pdf *.pdf
test_lzp
test_base64
*.trs
stpdfs-fuse

View file

@ -45,6 +45,7 @@ AC_CHECK_FUNCS(m4_normalize([
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile
lib/Makefile lib/Makefile
tools/Makefile tools/Makefile
tests/Makefile
linux/Makefile linux/Makefile
fuse/Makefile]) fuse/Makefile])

View file

@ -1,5 +1,5 @@
AM_CFLAGS = $(FUSE_CFLAGS) AM_CFLAGS = $(FUSE_CFLAGS) -I$(top_srcdir)/lib -I$(top_srcdir)
LDADD = $(FUSE_LIBS) LDADD = $(FUSE_LIBS) ../lib/libstpdfs.a
bin_PROGRAMS = stpdfs-fuse bin_PROGRAMS = stpdfs-fuse

View file

@ -1,19 +1,79 @@
#include "stpdfs.h"
#include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#define FUSE_USE_VERSION 31 #define FUSE_USE_VERSION 31
#include <fuse.h> #include <fuse.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
#ifdef HAVE_LIBGEN_H
# include <libgen.h>
#endif /* HAVE_LIBGEN_H */
static const char *prg_name;
static int fd = -1;
static struct options {
const char *filename;
int show_help;
int show_version;
} options;
#define OPTION(t, p) { t, offsetof(struct options, p), 1 }
static const struct fuse_opt option_spec[] = {
OPTION("--image=%s", filename),
OPTION("-h", show_help),
OPTION("--help", show_help),
OPTION("-V", show_version),
OPTION("--version", show_version),
FUSE_OPT_END
};
static void * static void *
stpdfs_init(struct fuse_conn_info *conn, fuse_stpdfs_init(struct fuse_conn_info *conn,
struct fuse_config *config) struct fuse_config *config)
{ {
(void)conn; struct stpdfs_sb sb;
(void)conn;
(void)config;
fd = open(options.filename, O_RDWR);
if (fd < 0)
{
perror(options.filename);
exit(EXIT_FAILURE);
}
stpdfs_read(fd, 1, &sb, sizeof(struct stpdfs_sb));
printf("StupidFS last opened: %s\n", asctime(localtime(&sb.time)));
return (NULL); return (NULL);
} }
static void
fuse_stpdfs_destroy(void *data)
{
struct stpdfs_sb sb;
stpdfs_read(fd, 1, &sb, sizeof(struct stpdfs_sb)),
sb.state = STPDFS_CLEANLY_UNMOUNTED;
sb.time = time(NULL);
stpdfs_write(fd, 1, &sb, sizeof(struct stpdfs_sb));
close(fd);
}
static int static int
stpdfs_getattr(const char *path, struct stat *stbuf, fuse_stpdfs_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi) struct fuse_file_info *fi)
{ {
return (0); return (0);
@ -21,7 +81,7 @@ stpdfs_getattr(const char *path, struct stat *stbuf,
static int static int
stpdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fuse_stpdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi, off_t offset, struct fuse_file_info *fi,
enum fuse_readdir_flags flags) enum fuse_readdir_flags flags)
{ {
@ -29,32 +89,64 @@ stpdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
} }
static int static int
stpdfs_open(const char *path, struct fuse_file_info *fi) fuse_stpdfs_open(const char *path, struct fuse_file_info *fi)
{ {
return (0); return (0);
} }
static int static int
stpdfs_read(const char *path, char *buf, size_t size, off_t offset, fuse_stpdfs_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi) struct fuse_file_info *fi)
{ {
return (size); return (size);
} }
static const struct fuse_operations stpdfs_oper = { static const struct fuse_operations stpdfs_oper = {
.init = stpdfs_init, .init = fuse_stpdfs_init,
.getattr = stpdfs_getattr, .destroy = fuse_stpdfs_destroy,
.readdir = stpdfs_readdir, .getattr = fuse_stpdfs_getattr,
.open = stpdfs_open, .readdir = fuse_stpdfs_readdir,
.read = stpdfs_read .open = fuse_stpdfs_open,
.read = fuse_stpdfs_read
}; };
static void
show_version(void)
{
printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
exit(EXIT_SUCCESS);
}
static void
show_help(void)
{
printf("Usage: %s --image=<filename> <mountpoint>\n", prg_name);
exit(EXIT_SUCCESS);
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int ret; int ret;
struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
#ifdef HAVE_LIBGEN_H
prg_name = basename(argv[0]);
#else
prg_name = argv[0];
#endif /* HAVE_LIBGEN_H */
if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
{
return (EXIT_FAILURE);
}
if (options.show_version) show_version();
if (options.show_help) show_help();
if (options.filename == NULL) show_help();
ret = fuse_main(args.argc, args.argv, &stpdfs_oper, NULL); ret = fuse_main(args.argc, args.argv, &stpdfs_oper, NULL);
fuse_opt_free_args(&args); fuse_opt_free_args(&args);
return (ret); return (ret);

View file

@ -1,2 +1,2 @@
noinst_LIBRARIES = libstpdfs.a noinst_LIBRARIES = libstpdfs.a
libstpdfs_a_SOURCES = block.c superblock.c codec/base64.c compression/lzp.c libstpdfs_a_SOURCES = block.c superblock.c codec/base64.c compression/lzp.c crypto/hchacha.c

24
lib/crypto/chacha.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef STPDFS_CRYPTO_CHACHA_H
# define STPDFS_CRYPTO_CHACHA_H 1
# define CHACHA_CONST1 "expa"
# define CHACHA_CONST2 "nd 3"
# define CHACHA_CONST3 "2-by"
# define CHACHA_CONST4 "te k"
#define CHACHA_ROT_L(x, n) (((x) << (n))|((x) >> (32 - (n))))
#define CHACHA_QUARTERROUND(a, b, c, d) do { \
a += b; d ^= a; d = CHACHA_ROT_L(d, 16); \
c += d; b ^= c; b = CHACHA_ROT_L(b, 12); \
a += b; d ^= a; d = CHACHA_ROT_L(d, 8); \
c += d; b ^= c; b = CHACHA_ROT_L(b, 7); \
} while (0)
# define HCHACHA_KEY_BYTES 32
# define HCHACHA_NONCE_BYTES 16
# define HCHACHA_OUT_BYTES 32
# define HCHACHA_CONST_BYTES 16
# define TO_LE_32(x) ((x)[0]) | ((x)[1] << 8) | ((x)[2] << 16) | ((x)[3] << 24)
#endif /* STPDFS_CRYPTO_CHACHA_H */

67
lib/crypto/hchacha.c Normal file
View file

@ -0,0 +1,67 @@
#include <string.h>
#include <endian.h>
#include <stdint.h>
#include <string.h>
#include "chacha.h"
void
hchacha(uint8_t out[HCHACHA_OUT_BYTES],
const uint8_t key[HCHACHA_KEY_BYTES],
const uint8_t nonce[HCHACHA_NONCE_BYTES],
int round)
{
int idx;
uint32_t state[4][4];
state[0][0] = TO_LE_32(CHACHA_CONST1);
state[0][1] = TO_LE_32(CHACHA_CONST2);
state[0][2] = TO_LE_32(CHACHA_CONST3);
state[0][3] = TO_LE_32(CHACHA_CONST4);
state[1][0] = TO_LE_32(key);
state[1][1] = TO_LE_32(key + 4);
state[1][2] = TO_LE_32(key + 4 * 2);
state[1][3] = TO_LE_32(key + 4 * 3);
state[2][0] = TO_LE_32(key + 16);
state[2][1] = TO_LE_32(key + 16 + 4);
state[2][2] = TO_LE_32(key + 16 + 4 * 2);
state[2][3] = TO_LE_32(key + 16 + 4 * 3);
state[3][0] = TO_LE_32(nonce);
state[3][1] = TO_LE_32(nonce + 4);
state[3][2] = TO_LE_32(nonce + 8);
state[3][3] = TO_LE_32(nonce + 12);
for (idx = 0; idx < round/2; idx++)
{
CHACHA_QUARTERROUND(state[0][0], state[1][0], state[2][0], state[3][0]);
CHACHA_QUARTERROUND(state[0][1], state[1][1], state[2][1], state[3][1]);
CHACHA_QUARTERROUND(state[0][2], state[1][2], state[2][2], state[3][2]);
CHACHA_QUARTERROUND(state[0][3], state[1][3], state[2][3], state[3][3]);
CHACHA_QUARTERROUND(state[0][0], state[1][1], state[2][2], state[3][3]);
CHACHA_QUARTERROUND(state[0][1], state[1][2], state[2][3], state[3][0]);
CHACHA_QUARTERROUND(state[0][2], state[1][3], state[2][0], state[3][1]);
CHACHA_QUARTERROUND(state[0][3], state[1][0], state[2][1], state[3][2]);
}
*(uint32_t *)(out + 0) = htole32(state[0][0]);
*(uint32_t *)(out + 4) = htole32(state[0][1]);
*(uint32_t *)(out + 8) = htole32(state[0][2]);
*(uint32_t *)(out + 12) = htole32(state[0][3]);
*(uint32_t *)(out + 16) = htole32(state[3][0]);
*(uint32_t *)(out + 20) = htole32(state[3][1]);
*(uint32_t *)(out + 24) = htole32(state[3][2]);
*(uint32_t *)(out + 28) = htole32(state[3][3]);
}
void
hchacha12(uint8_t out[HCHACHA_OUT_BYTES],
const uint8_t key[HCHACHA_KEY_BYTES],
const uint8_t nonce[HCHACHA_NONCE_BYTES])
{
return (hchacha(out, key, nonce, 12));
}

View file

View file

@ -1,10 +1,12 @@
AM_CPPFLAGS = -I$(top_srcdir)/lib AM_CPPFLAGS = -I$(top_srcdir)/lib
TESTS = test_lzp test_base64 TESTS = test_lzp test_base64 test_hchacha
check_PROGRAMS = test_lzp test_base64 check_PROGRAMS = test_lzp test_base64 test_hchacha
LDADD = -lcmocka ../lib/libstpdfs.a LDADD = -lcmocka ../lib/libstpdfs.a
test_lzp_SOURCES = test_lzp.c test_lzp_SOURCES = test_lzp.c
test_base64_SOURCES = test_base64.c test_base64_SOURCES = test_base64.c
test_hchacha_SOURCES = test_hchacha.c

48
tests/test_hchacha.c Normal file
View file

@ -0,0 +1,48 @@
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <setjmp.h>
#include <cmocka.h>
#include <crypto/chacha.h>
/* test from https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03#section-2.2 */
void
hchacha(uint8_t out[HCHACHA_OUT_BYTES],
const uint8_t key[HCHACHA_KEY_BYTES],
const uint8_t nonce[HCHACHA_NONCE_BYTES],
int round);
uint8_t key[HCHACHA_KEY_BYTES] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
};
uint8_t nonce[HCHACHA_NONCE_BYTES] = {
0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x31, 0x41, 0x59, 0x27
};
static void
test_hchacha20(void **state)
{
uint8_t out[HCHACHA_OUT_BYTES];
uint8_t expected[HCHACHA_OUT_BYTES] = {
0x82, 0x41, 0x3b, 0x42, 0x27, 0xb2, 0x7b, 0xfe, 0xd3, 0x0e, 0x42, 0x50, 0x8a, 0x87, 0x7d, 0x73,
0xa0, 0xf9, 0xe4, 0xd5, 0x8a, 0x74, 0xa8, 0x53, 0xc1, 0x2e, 0xc4, 0x13, 0x26, 0xd3, 0xec, 0xdc
};
hchacha(out, key, nonce, 20);
assert_memory_equal(expected, out, HCHACHA_OUT_BYTES);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_hchacha20),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}

View file

@ -10,6 +10,7 @@ void lzp_decompress(uint8_t *out, size_t *outsz, const uint8_t *in, size_t insz)
static const char uncompress_data[298] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" static const char uncompress_data[298] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
"abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc" "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc"
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccabcabcabcabcabcabcabcabcabcabcabcabcabcabc"; "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccabcabcabcabcabcabcabcabcabcabcabcabcabcabc";
static void static void
test_lzp(void **state) test_lzp(void **state)
{ {
@ -18,6 +19,8 @@ test_lzp(void **state)
size_t outsz; size_t outsz;
lzp_compress(compressed, &outsz, (uint8_t *)uncompress_data, 298); lzp_compress(compressed, &outsz, (uint8_t *)uncompress_data, 298);
assert_true(outsz < 298);
lzp_decompress((uint8_t *)result, &outsz, compressed, outsz); lzp_decompress((uint8_t *)result, &outsz, compressed, outsz);
assert_int_equal(298, outsz); assert_int_equal(298, outsz);

46
tests/test_xchacha.c Normal file
View file

@ -0,0 +1,46 @@
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <setjmp.h>
#include <cmocka.h>
#include <crypto/chacha.h>
void
hchacha(uint8_t out[HCHACHA_OUT_BYTES],
const uint8_t key[HCHACHA_KEY_BYTES],
const uint8_t nonce[HCHACHA_NONCE_BYTES],
int round);
uint8_t key[HCHACHA_KEY_BYTES] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
};
uint8_t nonce[HCHACHA_NONCE_BYTES] = {
0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x31, 0x41, 0x59, 0x27
};
static void
test_xchacha20(void **state)
{
uint8_t out[HCHACHA_OUT_BYTES];
uint8_t expected[HCHACHA_OUT_BYTES] = {
0x82, 0x41, 0x3b, 0x42, 0x27, 0xb2, 0x7b, 0xfe, 0xd3, 0x0e, 0x42, 0x50, 0x8a, 0x87, 0x7d, 0x73,
0xa0, 0xf9, 0xe4, 0xd5, 0x8a, 0x74, 0xa8, 0x53, 0xc1, 0x2e, 0xc4, 0x13, 0x26, 0xd3, 0xec, 0xdc
};
hchacha(out, key, nonce, 20);
assert_memory_equal(expected, out, HCHACHA_OUT_BYTES);
}
int
main(void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_xchacha20),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}