From 5e141e336c3a2cb8921edcd7af6f14a29ff63942 Mon Sep 17 00:00:00 2001 From: bigfoot547 Date: Wed, 27 Dec 2023 06:51:29 -0600 Subject: add cheap SHA1 implementation --- src/cmd-instance.c | 2 +- src/cmd-version.c | 20 +++++ src/command.c | 42 +++++++++ src/config.h.in | 3 + src/digest/digest.h | 32 +++++++ src/digest/sha1.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/endian.c | 28 ++++++ src/endian.h | 43 +++++++++ src/instance.c | 4 +- src/meson.build | 2 +- src/uuid/uuid.c | 6 +- src/uuid/uuid.h | 1 + src/version.h | 11 +++ 13 files changed, 442 insertions(+), 5 deletions(-) create mode 100644 src/cmd-version.c create mode 100644 src/digest/digest.h create mode 100644 src/digest/sha1.c create mode 100644 src/endian.c create mode 100644 src/endian.h create mode 100644 src/version.h (limited to 'src') diff --git a/src/cmd-instance.c b/src/cmd-instance.c index c81eb7c..7a569e8 100644 --- a/src/cmd-instance.c +++ b/src/cmd-instance.c @@ -139,7 +139,7 @@ unsigned cmd_instance_add(struct l2_context_node *ctx, char **args) struct l2_instance inst; - inst.uuid = uuid; + l2_uuid_copy(&inst.uuid, &uuid); inst.name = name; inst.path = path; diff --git a/src/cmd-version.c b/src/cmd-version.c new file mode 100644 index 0000000..873108a --- /dev/null +++ b/src/cmd-version.c @@ -0,0 +1,20 @@ +#include "command.h" +#include "commands.h" +#include "digest/digest.h" + +#include + +unsigned cmd_version_list_remote(struct l2_context_node *ctx, char **args) +{ + return CMD_RESULT_SUCCESS; +} + +unsigned cmd_version_list_local(struct l2_context_node *ctx, char **args) +{ + return CMD_RESULT_SUCCESS; +} + +unsigned cmd_version_install(struct l2_context_node *ctx, char **args) +{ + return CMD_RESULT_SUCCESS; +} diff --git a/src/command.c b/src/command.c index 2f91db0..55e7970 100644 --- a/src/command.c +++ b/src/command.c @@ -99,6 +99,48 @@ struct l2_command_node l2_cmd_root = { { 0 } } }, + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "version", + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "list", + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "local", + + .cmd_proc = &cmd_version_list_local + }, + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "remote", + + .cmd_proc = &cmd_version_list_remote + }, + { 0 } + } + }, + { + .type = CMD_NODE_TYPE_LITERAL, + .name = "install", + + .children = (struct l2_command_node []) { + { + .type = CMD_NODE_TYPE_ARGUMENT, + .name = "remotever", + + .cmd_proc = &cmd_version_install + }, + { 0 } + } + }, + { 0 } + } + }, { 0 } } }; diff --git a/src/config.h.in b/src/config.h.in index 05e3045..df91d35 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -4,4 +4,7 @@ #mesondefine PROJECT_NAME #mesondefine PROJECT_NAME_UPPER +#mesondefine L2SU_ENDIAN_LITTLE +#mesondefine L2SU_ENDIAN_BIG + #endif /* include guard */ diff --git a/src/digest/digest.h b/src/digest/digest.h new file mode 100644 index 0000000..d047b8e --- /dev/null +++ b/src/digest/digest.h @@ -0,0 +1,32 @@ +#ifndef L2SU_DIGEST_H_INCLUDED +#define L2SU_DIGEST_H_INCLUDED + +#include +#include + +#define L2_SHA1_BLOCKLEN (64) /* 512 / 8 = 64 */ +#define L2_SHA1_DIGESTLEN (5) /* 160 / 32 = 5 */ +#define L2_SHA1_HEX_STRLEN (40) + +typedef struct tag_l2_sha1_state { + /* struct members are internal do not use directly */ + uint32_t state[L2_SHA1_DIGESTLEN]; + uint8_t chunk[L2_SHA1_BLOCKLEN]; + size_t nchunk; + uint64_t totallen; +} l2_sha1_state_t; + +typedef struct tag_l2_sha1_digest { + uint32_t state[L2_SHA1_DIGESTLEN]; +} l2_sha1_digest_t; + +void l2_sha1_init(l2_sha1_state_t *st); +void l2_sha1_update(l2_sha1_state_t *st, const void *data, size_t sz); +void l2_sha1_finalize(l2_sha1_state_t *st, l2_sha1_digest_t *digest); + +int l2_sha1_digest_compare(const l2_sha1_digest_t *d1, const l2_sha1_digest_t *d2); +void l2_sha1_digest_copy(l2_sha1_digest_t *restrict dest, const l2_sha1_digest_t *restrict src); +void l2_sha1_digest_to_hex(const l2_sha1_digest_t *dg, char *out); +int l2_sha1_digest_from_hex(l2_sha1_digest_t *dg, const char *in); + +#endif /* include guard */ diff --git a/src/digest/sha1.c b/src/digest/sha1.c new file mode 100644 index 0000000..6601961 --- /dev/null +++ b/src/digest/sha1.c @@ -0,0 +1,253 @@ +#include "digest.h" +#include "endian.h" + +#include +#include +#include + +#define L2_SHA1_H0 UINT32_C(0x67452301) +#define L2_SHA1_H1 UINT32_C(0xEFCDAB89) +#define L2_SHA1_H2 UINT32_C(0x98BADCFE) +#define L2_SHA1_H3 UINT32_C(0x10325476) +#define L2_SHA1_H4 UINT32_C(0xC3D2E1F0) + +#define L2_SHA1_K0 UINT32_C(0x5A827999) +#define L2_SHA1_K1 UINT32_C(0x6ED9EBA1) +#define L2_SHA1_K2 UINT32_C(0x8F1BBCDC) +#define L2_SHA1_K3 UINT32_C(0xCA62C1D6) + +void l2_sha1_init(l2_sha1_state_t *st) +{ + st->state[0] = L2_SHA1_H0; + st->state[1] = L2_SHA1_H1; + st->state[2] = L2_SHA1_H2; + st->state[3] = L2_SHA1_H3; + st->state[4] = L2_SHA1_H4; + + memset(st->chunk, 0, L2_SHA1_BLOCKLEN); + st->nchunk = 0; + st->totallen = 0; +} + +uint32_t l2_sha1__rol(uint32_t in, uint32_t v) +{ + return (in << v) | (in >> (32 - v)); +} + +void l2_sha1__update_int(l2_sha1_state_t *st) +{ + uint32_t w[80]; + + for (int i = 0; i < 16; ++i) { + memcpy(w + i, st->chunk + (i * 4), 4); + w[i] = l2_betoh32(w[i]); + } + + for (unsigned i = 16; i < 80; ++i) { + w[i] = l2_sha1__rol((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1); + } + + uint32_t a, b, c, d, e, f, k, temp; + a = st->state[0]; + b = st->state[1]; + c = st->state[2]; + d = st->state[3]; + e = st->state[4]; + + for (unsigned i = 0; i < 80; ++i) { + if (i < 20) { + f = (b & c) ^ ((~b) & d); + k = L2_SHA1_K0; + } else if (i < 40) { + f = b ^ c ^ d; + k = L2_SHA1_K1; + } else if (i < 60) { + f = (b & c) ^ (b & d) ^ (c & d); + k = L2_SHA1_K2; + } else { + f = b ^ c ^ d; + k = L2_SHA1_K3; + } + + temp = l2_sha1__rol(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = l2_sha1__rol(b, 30); + b = a; + a = temp; + } + + st->state[0] += a; + st->state[1] += b; + st->state[2] += c; + st->state[3] += d; + st->state[4] += e; +} + +void l2_sha1_update(l2_sha1_state_t *st, const void *data, size_t sz) +{ + const uint8_t *dbytes = data; + size_t rem; + st->totallen += sz; + + if (sz < L2_SHA1_BLOCKLEN - st->nchunk) { + memcpy(st->chunk + st->nchunk, dbytes, sz); + st->nchunk += sz; + return; + } + + while (sz >= (rem = (L2_SHA1_BLOCKLEN - st->nchunk))) { + memcpy(st->chunk, dbytes, rem); + l2_sha1__update_int(st); + + st->nchunk = 0; + dbytes += rem; + sz -= rem; + } + + if (sz > 0) { + memcpy(st->chunk, dbytes, sz); + st->nchunk = sz; + } +} + +void l2_sha1_finalize(l2_sha1_state_t *st, l2_sha1_digest_t *digest) +{ + st->chunk[st->nchunk] = UINT8_C(0x80); + ++st->nchunk; + if (st->nchunk > (L2_SHA1_BLOCKLEN - 8)) { + /* must pad the rest of the way */ + memset(st->chunk + st->nchunk, 0, L2_SHA1_BLOCKLEN - st->nchunk); + l2_sha1__update_int(st); + st->nchunk = 0; + } + + size_t rem = (L2_SHA1_BLOCKLEN - st->nchunk) - 8; + uint64_t len = l2_htobe64(st->totallen * 8); + memset(st->chunk + st->nchunk, 0, rem); + st->nchunk += rem; + + memcpy(st->chunk + st->nchunk, (uint8_t *)&len, 8); + l2_sha1__update_int(st); + + digest->state[0] = st->state[0]; + digest->state[1] = st->state[1]; + digest->state[2] = st->state[2]; + digest->state[3] = st->state[3]; + digest->state[4] = st->state[4]; +} + +int l2_sha1_digest_compare(const l2_sha1_digest_t *d1, const l2_sha1_digest_t *d2) +{ + return memcmp(d1, d2, sizeof(l2_sha1_digest_t)); +} + +void l2_sha1_digest_copy(l2_sha1_digest_t *restrict dest, const l2_sha1_digest_t *restrict src) +{ + memcpy(dest, src, sizeof(l2_sha1_digest_t)); +} + +void l2_sha1_digest_to_hex(const l2_sha1_digest_t *dg, char *out) +{ + snprintf(out, L2_SHA1_HEX_STRLEN + 1, + "%08" PRIx32 "%08" PRIx32 "%08" PRIx32 "%08" PRIx32 "%08" PRIx32, + dg->state[0], dg->state[1], dg->state[2], dg->state[3], dg->state[4]); +} + +int l2_sha1__hex_to_uint32(const char *in, uint32_t *out); + +int l2_sha1_digest_from_hex(l2_sha1_digest_t *dg, const char *in) +{ + size_t len = strlen(in); + l2_sha1_digest_t dg1; + + if (len != L2_SHA1_HEX_STRLEN) return -1; + + for (unsigned i = 0; i < 5; ++i) { + if (l2_sha1__hex_to_uint32(in + (i * 8), dg1.state + i) < 0) return -1; + } + + l2_sha1_digest_copy(dg, &dg1); + return 0; +} + +int l2_sha1__hex_to_uint32(const char *in, uint32_t *out) +{ + uint32_t ret = 0; + + for (unsigned i = 0; i < 8; ++i) { + switch (in[i]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ret |= (in[i] - '0') << ((7 - i) << 2); + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + ret |= (in[i] - 'a' + 0xa) << ((7 - i) << 2); + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + ret |= (in[i] - 'A' + 0xA) << ((7 - i) << 2); + break; + default: + return -1; + } + } + + *out = ret; + + return 0; +} + +#if 0 +int main(int argc, char **argv) +{ + if (argc < 2) return 1; + + FILE *fp = fopen(argv[1], "rb"); + if (!fp) { + fputs("oh no\n", stderr); + return 1; + } + + char b[1024]; + size_t nread = 0; + l2_sha1_state_t st; + l2_sha1_digest_t dg; + + l2_sha1_init(&st); + + while ((nread = fread(b, 1, 1024, fp))) { + printf("%zu\n", nread); + l2_sha1_update(&st, b, nread); + } + + l2_sha1_finalize(&st, &dg); + + char hex[L2_SHA1_HEX_STRLEN + 1]; + l2_sha1_digest_to_hex(&dg, hex); + printf("%s\n", hex); + + printf("%d\n", l2_sha1_digest_from_hex(&dg, "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12")); + l2_sha1_digest_to_hex(&dg, hex); + printf("%s\n", hex); + + return 0; +} +#endif diff --git a/src/endian.c b/src/endian.c new file mode 100644 index 0000000..0229c57 --- /dev/null +++ b/src/endian.c @@ -0,0 +1,28 @@ +#include "endian.h" + +#include + +uint64_t l2__bswap_64_int(uint64_t in) +{ + return (in << 56) + | ((in & UINT64_C(0x000000000000FF00)) << 40) + | ((in & UINT64_C(0x0000000000FF0000)) << 24) + | ((in & UINT64_C(0x00000000FF000000)) << 8) + | ((in & UINT64_C(0x000000FF00000000)) >> 8) + | ((in & UINT64_C(0x0000FF0000000000)) >> 24) + | ((in & UINT64_C(0x00FF000000000000)) >> 40) + | (in >> 56); +} + +uint32_t l2__bswap_32_int(uint32_t in) +{ + return (in << 24) + | ((in & UINT32_C(0x0000FF00)) << 8) + | ((in & UINT32_C(0x00FF0000)) >> 8) + | (in >> 24); +} + +uint16_t l2__bswap_16_int(uint16_t in) +{ + return (in >> 8) | (in << 8); +} diff --git a/src/endian.h b/src/endian.h new file mode 100644 index 0000000..a486223 --- /dev/null +++ b/src/endian.h @@ -0,0 +1,43 @@ +#ifndef L2SU_ENDIAN_H_INCLUDED +#define L2SU_ENDIAN_H_INCLUDED + +#include +#include "config.h" + +uint64_t l2__bswap_64_int(uint64_t in); +uint32_t l2__bswap_32_int(uint32_t in); +uint16_t l2__bswap_16_int(uint16_t in); + +#ifdef __GNUC__ +#define l2__bswap_64 __builtin_bswap64 +#define l2__bswap_32 __builtin_bswap32 +#define l2__bswap_16 __builtin_bswap16 +#else +#define l2__bswap_64 l2__bswap_64_int +#define l2__bswap_32 l2__bswap_32_int +#define l2__bswap_16 l2__bswap_16_int +#endif + +#if defined(L2SU_ENDIAN_LITTLE) + +#define l2_htobe64 l2__bswap_64 +#define l2_betoh64 l2__bswap_64 +#define l2_htobe32 l2__bswap_32 +#define l2_betoh32 l2__bswap_32 +#define l2_htobe16 l2__bswap_16 +#define l2_betoh16 l2__bswap_16 + +#elif defined(L2SU_ENDIAN_BIG) + +#define l2_htobe64 +#define l2_betoh64 +#define l2_htobe32 +#define l2_betoh32 +#define l2_htobe16 +#define l2_betoh16 + +#else +#error "middle endian unsupported" +#endif + +#endif /* include guard */ diff --git a/src/instance.c b/src/instance.c index 8d62e1e..b8c70fd 100644 --- a/src/instance.c +++ b/src/instance.c @@ -95,7 +95,7 @@ int l2_instance_add_instance(const struct l2_instance *inst) return INSTANCE_ERRNO; } - newinst->uuid = inst->uuid; + l2_uuid_copy(&newinst->uuid, &inst->uuid); newinst->path = path; newinst->name = name; @@ -144,7 +144,7 @@ int l2_instance_rename_instance(struct l2_instance *inst, const char *newname) struct l2_instance *l2_instance_find_by_uuid(const uuid_t *id) { for (struct l2_instance *inst = l2_state.instance_head; inst; inst = inst->next) { - if (!memcmp(id, &inst->uuid, sizeof(uuid_t))) { + if (!l2_uuid_compare(id, &inst->uuid)) { return inst; } } diff --git a/src/meson.build b/src/meson.build index 000bf6b..261148a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,4 +1,4 @@ -launcher_srcs = files('l2su.c', 'command.c', 'cmd-instance.c', 'uuid/uuid.c', 'launcherutil.c', 'instance.c') +launcher_srcs = files('l2su.c', 'command.c', 'cmd-instance.c', 'uuid/uuid.c', 'launcherutil.c', 'instance.c', 'cmd-version.c', 'digest/sha1.c') configure_file(input : 'config.h.in', output : 'config.h', configuration : config_data) config_include_dir = include_directories('.') diff --git a/src/uuid/uuid.c b/src/uuid/uuid.c index 0dfcfbd..e1498fc 100644 --- a/src/uuid/uuid.c +++ b/src/uuid/uuid.c @@ -74,7 +74,7 @@ bool l2_uuid_from_string_short(uuid_t *id, const char *str) if (!l2__str_to_uint64(outid.halves + 1, str)) return false; if (!l2__str_to_uint64(outid.halves, str + 16)) return false; - memcpy(id, &outid, sizeof(uuid_t)); + l2_uuid_copy(id, &outid); return true; } @@ -83,6 +83,10 @@ int l2_uuid_compare(const uuid_t *c1, const uuid_t *c2) return memcmp(c1, c2, sizeof(uuid_t)); } +void l2_uuid_copy(uuid_t *restrict dest, const uuid_t *restrict in) { + memcpy(dest, in, sizeof(uuid_t)); +} + /* This function exists because there's not a portable way to do this. * Don't suggest strtoull, because uint64_t may not be a ulonglong. */ bool l2__str_to_uint64(uint64_t *out, const char *str) diff --git a/src/uuid/uuid.h b/src/uuid/uuid.h index 7ddeeb4..eb1d41e 100644 --- a/src/uuid/uuid.h +++ b/src/uuid/uuid.h @@ -28,5 +28,6 @@ bool l2_uuid_from_string(uuid_t *id, const char *str); bool l2_uuid_from_string_short(uuid_t *id, const char *str); int l2_uuid_compare(const uuid_t *c1, const uuid_t *c2); +void l2_uuid_copy(uuid_t *restrict dest, const uuid_t *restrict src); #endif /* include guard */ diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..b3f640f --- /dev/null +++ b/src/version.h @@ -0,0 +1,11 @@ +#ifndef L2SU_VERSION_H_INCLUDED +#define L2SU_VERSION_H_INCLUDED + +struct l2_version_remote { + +}; + +unsigned l2_version_load_remote(void); +unsigned l2_version_load_local(void); + +#endif /* include guard */ -- cgit v1.2.3-70-g09d2