From 39e055619e08ae60448e2d7425da3e6ad6bb1223 Mon Sep 17 00:00:00 2001 From: mar77i Date: Thu, 25 Jun 2026 14:02:57 +0200 Subject: [PATCH] get it working fine --- .gitignore | 1 + build.sh | 10 +- decrypt.c | 184 +++++++++++++++++++++++++ decrypt.h | 15 ++ encoding.h | 122 +++++++++++++++++ encrypt_secrets_to_header.py | 72 ---------- main.c | 219 ++++++++++++++++++------------ manage_secrets.py | 256 +++++++++++++++++++++++++++++++++++ repl.py | 214 +++++++++++++++-------------- sha1.c | 30 ++-- sha1.h | 19 +-- totp.c | 231 ------------------------------- totp.h | 14 -- uart.c | 29 ++-- uart.h | 12 +- 15 files changed, 878 insertions(+), 550 deletions(-) create mode 100644 decrypt.c create mode 100644 decrypt.h create mode 100644 encoding.h delete mode 100755 encrypt_secrets_to_header.py create mode 100755 manage_secrets.py delete mode 100644 totp.c delete mode 100644 totp.h diff --git a/.gitignore b/.gitignore index fe4f21d..0a3ef68 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ *.elf *.hex .idea +__pycache__/ secrets.h diff --git a/build.sh b/build.sh index 560399c..481aabb 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash tmpdir="$(mktemp -d -p/dev/shm)" + cleanup() { rm -rf "${tmpdir}" } @@ -16,10 +17,15 @@ extra_args=( while (( $# )); do case "${1}" in -u|--upload) - extra_args+=(-u -p /dev/ttyUSB0) + if [[ -c "${2}" ]]; then + dev_path="${2}" + shift + else + dev_path=/dev/ttyUSB0 + fi + extra_args+=(-u -p "${dev_path}") ;; esac shift done arduino-cli compile "${extra_args[@]}" . -#rm -r "${tmpdir}" diff --git a/decrypt.c b/decrypt.c new file mode 100644 index 0000000..bf47543 --- /dev/null +++ b/decrypt.c @@ -0,0 +1,184 @@ + +// decrypt.c + +#include "decrypt.h" +#include "encoding.h" +#include "sha1.h" +#include "secrets.h" +#include "uart.h" + +static struct { + struct sha1_ctx ipad_opad_ctx[2]; + struct sha1_buf indices, round_key, mac; + uint8_t chunk[32], status; +} decrypt_buffers; + +uint8_t init_decrypt_buffers(uint8_t *password, uint8_t password_len) { + int result; + uint16_t pick_accu = 0; + uint8_t i, j, pick, tmp; + memcpy_P(&decrypt_buffers.round_key, &iv, sizeof iv); + sha1_hmac( + &decrypt_buffers.round_key, + sizeof decrypt_buffers.round_key, + password, + password_len, + &decrypt_buffers.mac + ); + if (memcmp_P(&decrypt_buffers.mac, &pw_mac, sizeof pw_mac) != 0) + return 1; + sha1_hmac_ipad_opad_init(password, password_len, decrypt_buffers.ipad_opad_ctx); + sha1_hmac_ipad_opad_digest( + decrypt_buffers.ipad_opad_ctx, + &decrypt_buffers.round_key, + sizeof decrypt_buffers.round_key, + &decrypt_buffers.mac + ); + for (i = 0; i < 20; i++) + decrypt_buffers.indices.b[i] = i; + for (i = 20, j = i - 1; i > 0; i = j--) { + pick_accu += decrypt_buffers.mac.b[j]; + pick = pick_accu % i; + pick_accu /= i; + if (j == pick) + continue; + tmp = decrypt_buffers.indices.b[j]; + decrypt_buffers.indices.b[j] = decrypt_buffers.indices.b[pick]; + decrypt_buffers.indices.b[pick] = tmp; + } + decrypt_buffers.status = 1; + return 0; +} + +static inline void advance_round_key(void) { + uint8_t i, j, tmp; + for (i = 0, tmp = 1; i < 20; i++) { + j = decrypt_buffers.indices.b[i]; + decrypt_buffers.round_key.b[j] += tmp; + tmp &= decrypt_buffers.round_key.b[j] == 0; + } + sha1_hmac_ipad_opad_digest( + decrypt_buffers.ipad_opad_ctx, + &decrypt_buffers.round_key, + sizeof decrypt_buffers.round_key, + &decrypt_buffers.mac + ); +} + +static inline uint8_t get_byte_from_decrypt_buffers(size_t i) { + if (i % sizeof decrypt_buffers.chunk == 0) { + if (i + sizeof decrypt_buffers.chunk <= sizeof secret) + memcpy_P(decrypt_buffers.chunk, secret + i, sizeof decrypt_buffers.chunk); + else { + memcpy_P(decrypt_buffers.chunk, secret + i, sizeof secret - i); + memset( + decrypt_buffers.chunk + sizeof secret - i, + 0, + sizeof decrypt_buffers.chunk - (sizeof secret - i) + ); + } + } + if (i % (sizeof decrypt_buffers.mac >> 1) == 0) { + if (i == 0 && decrypt_buffers.status == 2) + memcpy_P(&decrypt_buffers.round_key, &iv, sizeof iv); + advance_round_key(); + } + return ( + decrypt_buffers.chunk[i % sizeof decrypt_buffers.chunk] + ^ decrypt_buffers.mac.b[i % (sizeof decrypt_buffers.mac / 2)] + ); +} + +uint8_t password_is_ready(void) { + return decrypt_buffers.status > 0; +} + +int8_t list_secrets(void) { + size_t i; + uint8_t c, colon_found = 0; + for (i = 0; i < sizeof secret; i++) { + c = get_byte_from_decrypt_buffers(i); + if (c == ':') + colon_found = 1; + else if (c == '\n') + colon_found = 0; + if (colon_found == 0) + UART_write_byte(c); + } + decrypt_buffers.status = 2; + return 0; +} + +static inline int8_t get_secret_and_totp_line( + uint8_t time_msg[8], + uint8_t *line, + uint8_t line_len, + uint8_t colon_offset +) { + struct sha1_buf mac; + uint32_t result; + ssize_t len; + uint8_t *ptr, i, decimal[7]; + ptr = line + colon_offset; + if ((len = from_b32_inplace(ptr)) <= 0) + return -1; + sha1_hmac(ptr, len, time_msg, 8, &mac); + i = mac.b[sizeof mac - 1] & 0xf; + UART_write_string_partial(line, colon_offset); + UART_write_byte(' '); + to_decimal( + ( + ((uint32_t)(mac.b[i] & 0x7f) << 24) + | ((uint32_t)mac.b[i + 1] << 16) + | ((uint32_t)mac.b[i + 2] << 8) + | mac.b[i + 3] + ) % 1000000, + decimal, + sizeof decimal + ); + UART_write_string(decimal); + UART_write_byte('\n'); + return 0; +} + +static inline search_matches(uint8_t *search, uint8_t *line, uint8_t colon_offset) { + uint8_t *ptr; + // no search was specified + return ( + search == NULL || *search == '\0' || ( + // or a match was made excluding the : + (ptr = strstr(line, search)) != NULL + && ptr + strlen(search) < line + colon_offset + ) + ); +} + +int8_t get_secrets_and_totp(uint8_t time_msg[8], uint8_t *search) { + size_t i; + uint8_t line[80], line_len = 0, c, colon_offset = 255; + for (i = 0; i < sizeof secret; i++) + if ((c = get_byte_from_decrypt_buffers(i)) == '\n') { + line[line_len] = '\0'; + if ( + // a : was found + colon_offset != 255 + && search_matches(search, line, colon_offset) + && get_secret_and_totp_line( + time_msg, line, line_len, colon_offset + 1 + ) < 0 + ) + return -1; + line_len = 0; + colon_offset = 255; + } else if (c == ':') { + colon_offset = line_len; + line[line_len++] = c; + } else if (line_len < sizeof line - 1) + line[line_len++] = c; + decrypt_buffers.status = 2; + return 0; +} + +void clear_decrypt_buffers(void) { + memset(&decrypt_buffers, 0, sizeof decrypt_buffers); +} diff --git a/decrypt.h b/decrypt.h new file mode 100644 index 0000000..39a3f56 --- /dev/null +++ b/decrypt.h @@ -0,0 +1,15 @@ + +// decrypt.h + +#ifndef DECRYPT_H +#define DECRYPT_H + +#include + +uint8_t init_decrypt_buffers(uint8_t *password, uint8_t password_len); +uint8_t password_is_ready(void); +int8_t list_secrets(void); +int8_t get_secrets_and_totp(uint8_t time_msg[8], uint8_t *search); +void clear_decrypt_buffers(void); + +#endif // DECRYPT_H diff --git a/encoding.h b/encoding.h new file mode 100644 index 0000000..a288c52 --- /dev/null +++ b/encoding.h @@ -0,0 +1,122 @@ + +// encoding.h + +#ifndef ENCODING_H +#define ENCODING_H + +#include +#include +#include + +typedef int16_t ssize_t; + +#include "uart.h" + +static inline char from_hex8(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + switch (c) { + case 'A': + case 'a': + return 10; + case 'B': + case 'b': + return 11; + case 'C': + case 'c': + return 12; + case 'D': + case 'd': + return 13; + case 'E': + case 'e': + return 14; + case 'F': + case 'f': + return 15; + } + return -1; +} + +static inline ssize_t from_hex_inplace(char *s, const char *end_chars) { + char *ptr = s; + ssize_t ret = 0; + int8_t nib; + while (*ptr != '\0' && strchr(end_chars, *ptr) == NULL) { + if ((nib = from_hex8(*ptr++)) == -1) + return -1; + if (ret & 1) + s[ret >> 1] |= nib; + else + s[ret >> 1] = nib << 4; + ret++; + } + if (ret & 1) + return -1; + return ret >> 1; +} + +static inline void to_hex(char c, char *s) { + const char hexdigits[] = "0123456789abcdef"; + s[0] = hexdigits[c >> 4]; + s[1] = hexdigits[c & 15]; +} + +static inline ssize_t from_b32_inplace(char *s) { + static const char base32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + uint8_t accu = 0, bits, count; + char *ptr = s, *found; + size_t pos; + for (pos = count = 0; s[pos] != '\n' && s[pos] != '\0' && s[pos] != '='; pos++) { + if (s[pos] == ' ' || s[pos] == '\t') + continue; + if ((found = strchr(base32_alphabet, toupper(s[pos]))) == NULL) { + UART_write_string("ERROR:INVALIDB32\n"); + return -1; + } + bits = found - base32_alphabet; + switch (count++ % 8) { + case 0: + accu = bits << 3; + break; + case 1: + *ptr++ = accu | (bits >> 2); + accu = bits << 6; + break; + case 2: + accu |= bits << 1; + break; + case 3: + *ptr++ = accu | (bits >> 4); + accu = bits << 4; + break; + case 4: + *ptr++ = accu | (bits >> 1); + accu = bits << 7; + break; + case 5: + accu |= bits << 2; + break; + case 6: + *ptr++ = accu | (bits >> 3); + accu = bits << 5; + break; + case 7: + *ptr++ = accu | bits; + break; + } + } + return ptr - s; +} + +static inline void to_decimal(uint32_t n, char *out, size_t out_len) { + if (out == NULL || out_len == 0) + return; + out[--out_len] = '\0'; + while (out_len > 0) { + out[--out_len] = '0' + (n % 10); + n /= 10; + } +} + +#endif // ENCODING_H diff --git a/encrypt_secrets_to_header.py b/encrypt_secrets_to_header.py deleted file mode 100755 index 14e8575..0000000 --- a/encrypt_secrets_to_header.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 - -import hmac -import sys -from getpass import getpass -from hashlib import sha1 -from io import BytesIO -from secrets import randbelow, randbits - - -def advance_round_key(orig_iv, iv): - for i in range(len(iv)): - j = orig_iv[i] & 31 - iv[j] = (iv[j] + 1) & 255 - if iv[j] != 0: - break - - -def scramble(iv_bytes, password, data): - assert not any(len(line) > 79 for line in data.split(b"\n")) - iv_list = list(iv_bytes) - round_key = iv_list[:] - bio = BytesIO() - derived = b"" - for i in range(len(data)): - if i % 10 == 0: - if i > 0: - advance_round_key(iv_list, round_key) - derived = hmac.new(password, bytes(round_key), sha1).digest() - print("derived:", derived.hex(), file=sys.stderr) - bio.write(bytes((data[i] ^ derived[i % 10],))) - return bio.getvalue() - - -def print_as_const(varname, data): - print(f"static const uint8_t {varname}[] PROGMEM = {{") - print(" ", end="") - for i, b in enumerate(data): - print(f"0x{b:02x}", end=",") - if i == len(data) - 1: - print() - elif i % 12 == 11: - print("\n ", end="") - else: - print(end=" ") - print("};") - - -def main(): - indices = list(range(20)) - key = bytes( - [ - indices.pop(randbelow(len(indices))) | (randbits(3) << 5) - for _ in range(len(indices)) - ] - ) - password = getpass().encode() - with open(sys.argv[1], "rb") as fh: - scrambled_data = scramble(key, password, fh.read()) - print("\n// secrets.h\n") - print("#ifndef SECRETS_H") - print("#define SECRETS_H\n") - print("#include ") - print("#include \n") - print_as_const("key", key) - print_as_const("pw_mac", hmac.new(key, password, sha1).digest()) - print_as_const("secret", scrambled_data) - print("\n#endif // SECRETS_H") - - -if __name__ == "__main__": - main() diff --git a/main.c b/main.c index c977868..6c35c17 100644 --- a/main.c +++ b/main.c @@ -1,11 +1,12 @@ // main.c +#include #include -#include +#include -#include "totp.h" -#include "sha1.h" +#include "decrypt.h" +#include "encoding.h" #include "uart.h" static uint8_t password[64]; @@ -26,108 +27,160 @@ static inline void wait_for_input(void) { TCCR1B = 0; // Turn off Timer 1 } -/* -static inline void process_sha1(uint8_t *payload) { - struct sha1_ctx_type ctx; - uint8_t digest[20], i; - sha1_init(&ctx); - sha1_update(&ctx, payload, strlen(payload)); - sha1_final(&ctx, digest); - for (i = 0; i < sizeof digest * 2; i++) - UART_write_byte( - "0123456789abcdef"[digest[i >> 1] >> (!(i & 1) << 2) & 15] - ); +/* serial comms protocol: + * + * BYE -> EYB ends session X + * PW -> OK if hmac matches else NOK X + * OTP LS -> list all secrets and OK X + * OTP GET -> show totp digits for matches of filter + * OTP GET -> show all (unfiltered) totp digits + * KO -> OK (ping) X + * anything else -> NOK X + * + * checksum is now 16 bits, transmitted in hex + */ + +int8_t process_otp_get(uint8_t *payload) { + uint64_t time; + ssize_t len; + int8_t i; + uint8_t time_msg[8]; + if ((len = from_hex_inplace(payload, " ")) <= 0) + return -1; + time = 0; + for (i = 0; i < len; i++) + time = (time << CHAR_BIT) | payload[i]; + time /= 30; + for (i = 0; i < sizeof time_msg; i++) + time_msg[i] = time >> ((sizeof time_msg - 1 - i) * CHAR_BIT); + payload += 2 * len; + if (*payload == ' ') { + payload++; + if ((len = from_hex_inplace(payload, "")) <= 0) + return -1; + payload[len] = '\0'; + } else if (*payload != '\0') + return -1; + return get_secrets_and_totp(time_msg, payload); } -*/ -static inline uint8_t process_payload(uint8_t *payload) { - size_t password_len; - const char *reply = "NOK\n"; - uint8_t ret = 0; - if (strcmp(payload, "bye") == 0) +int8_t process_payload(uint8_t *payload) { + size_t payload_len; + if (strcmp(payload, "BYE") == 0) return 1; - else if (strncmp(payload, "password ", 9) == 0) { - payload += 9; - password_len = strlen(payload); - if (password_len + 1 > sizeof password) - UART_write_string("ERROR:PASSWORDTOOLONG\n"); - else if (check_password(payload, password_len) == 0) { - memcpy(password, payload, strlen(payload) + 1); - reply = "OK\n"; + else if (strcmp(payload, "KO") == 0) + return 0; + else if (strncmp(payload, "PW ", 3) == 0) { + payload += 3; + payload_len = strlen(payload) / 2; + if ( + from_hex_inplace(payload, "") > 0 + && payload_len + 1 <= sizeof password + && init_decrypt_buffers(payload, payload_len) == 0 + ) { + memcpy(password, payload, payload_len + 1); + return 0; } - } else if (strncmp(payload, "gettoken ", 9) == 0) { - if (decrypt_secrets(password, payload + 9) == 0) - reply = "OK\n"; - } else if (strncmp(payload, "dumpsecret", 9) == 0) { - if (dump_secrets(password) == 0) - reply = "OK\n"; - } else - UART_write_string("ERROR:UNKNOWNCOMMAND\n"); - UART_write_string(reply); - return ret; + } else if (strncmp(payload, "OTP ", 4) == 0) { + payload += 4; + if (!password_is_ready()) + return -1; + if (strcmp(payload, "LS") == 0) + return list_secrets(); + else if (strncmp(payload, "GET ", 4) == 0) + return process_otp_get(payload + 4); + } + return -1; } -void parse_serial_frame(void) { - enum { STATE_IDLE, STATE_PAYLOAD, STATE_CHECKSUM } state = STATE_IDLE; - uint8_t payload[64], payload_idx, calculated_xor, received_xor, c, esc = 0; - payload_idx = calculated_xor = received_xor = 0; - while (c = UART_read_byte_blocking()) { - if (state != STATE_CHECKSUM && esc == 0 && c == '\\') { - esc = 1; - continue; +#define STARTMSG '$' +#define STARTCHK '*' +#define ENDMSG '\n' + +struct { + enum { STATE_IDLE, STATE_PAYLOAD, STATE_CHECKSUM } state; + uint16_t chksum, rchksum; + uint8_t payload[64], payload_idx; +} serial_frame; + +void parse_serial_frame_idle(uint8_t c) { + if (c != STARTMSG) + return; + serial_frame.state = STATE_PAYLOAD; + serial_frame.payload_idx = 0; + serial_frame.chksum = 0; +} + +void parse_serial_frame_payload(uint8_t c) { + if (c == STARTCHK) { + serial_frame.payload[serial_frame.payload_idx] = '\0'; + serial_frame.state = STATE_CHECKSUM; + serial_frame.rchksum = 0; + } else if (serial_frame.payload_idx < (sizeof serial_frame.payload - 1)) { + serial_frame.payload[serial_frame.payload_idx++] = c; + serial_frame.chksum = serial_frame.chksum * 33 ^ c; + } else { + serial_frame.state = STATE_IDLE; + UART_write_string("ERROR:PAYLOAD_OVERFLOW\n"); + } +} + +uint8_t parse_serial_frame_checksum(uint8_t c) { + uint16_t tmp; + int8_t nib = from_hex8(c); + if (nib >= 0) { + tmp = (serial_frame.rchksum << 4) | nib; + if (tmp >> 4 == serial_frame.rchksum) + serial_frame.rchksum = tmp; + else + UART_write_string("ERROR:CHECKSUM_OVERFLOW\n"); + return 0; + } + serial_frame.state = STATE_IDLE; + if (c == ENDMSG && serial_frame.chksum == serial_frame.rchksum) + switch (process_payload(serial_frame.payload)) { + case -1: + UART_write_string("NOK\n"); + break; + case 0: + UART_write_string("OK\n"); + break; + case 1: + return 1; } - switch (state) { + else { + UART_write_string("ERROR:CHECKSUM_ERROR\n"); + UART_write_string("NOK\n"); + } + return 0; +} + +void parse_serial_frame(void) { + uint8_t c; + serial_frame.state = STATE_IDLE; + while (c = UART_read_byte_blocking()) + switch (serial_frame.state) { case STATE_IDLE: - if (esc == 0 && c == '$') { - state = STATE_PAYLOAD; - payload_idx = calculated_xor = 0; - } + parse_serial_frame_idle(c); break; - case STATE_PAYLOAD: - if (esc == 0 && c == '*') { - payload[payload_idx] = '\0'; - state = STATE_CHECKSUM; - received_xor = 0; - } else if (payload_idx < (sizeof payload - 1)) { - payload[payload_idx++] = c; - calculated_xor = calculated_xor * 33 ^ c; - } else { - state = STATE_IDLE; - UART_write_string("ERROR:PAYLOAD_OVERFLOW\n"); - } + parse_serial_frame_payload(c); break; - case STATE_CHECKSUM: - if (c >= '0' && c <= '9') { - c = received_xor * 10 + (c - '0'); - if (c / 10 != received_xor) - goto checksum_error; - received_xor = c; - break; - } else if (c == '\n' && calculated_xor == received_xor) { - if (process_payload(payload)) - return; - } else { -checksum_error: - UART_write_string("ERROR:CHECKSUM_ERROR\n"); - } - state = STATE_IDLE; // Reset parser state machine + if (parse_serial_frame_checksum(c) == 1) + return; break; } - if (esc == 1) - esc = 0; - } } int main(void) { UART_init(); - sei(); for (;;) { wait_for_input(); parse_serial_frame(); + clear_decrypt_buffers(); memset(password, 0, sizeof password); - UART_flush(); + UART_read_buffer_flush(); UART_write_string("EYB\n"); } } diff --git a/manage_secrets.py b/manage_secrets.py new file mode 100755 index 0000000..5320c3a --- /dev/null +++ b/manage_secrets.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python3 + +import hmac +from argparse import ArgumentParser +from getpass import getpass +from hashlib import sha1 +from io import BytesIO +from pathlib import Path +from secrets import token_bytes + + +class CryptoManager: + @staticmethod + def get_hash(key, data): + return hmac.new(key, data, sha1).digest() + + def advance_round_key(self, round_key: bytearray | bytes) -> bytearray: + if isinstance(round_key, bytes): + round_key = bytearray(round_key) + tmp = 1 + for i in range(len(round_key)): + j = self.indices[i] + round_key[j] = (round_key[j] + tmp) & 255 + tmp &= round_key[j] == 0 + return round_key + + def __init__(self, iv: bytes, password: bytes): + self.iv = iv + self.password = password + self.indices = self.init_indices(self.get_hash(self.password, self.iv)) + + def init_indices(self, first_key) -> list[int]: + indices = list(range(20)) + pick_accu = 0 + i = 20 + while i > 0: + j = i - 1 + pick_accu = (pick_accu + first_key[j]) & 0xffff + pick_accu, pick = divmod(pick_accu, i) + if j != pick: + indices[j], indices[pick] = indices[pick], indices[j] + i = j + return indices + + def prepare_ipad_opad(self): + pad_len = 64 + ipad_ba = bytearray(b"\x36" * pad_len) + opad_ba = bytearray(b"\x5c" * pad_len) + if len(self.password) > pad_len: + password = sha1(self.password).digest() + else: + password = self.password + for i, c in enumerate(password): + ipad_ba[i] ^= c + opad_ba[i] ^= c + return sha1(ipad_ba), sha1(opad_ba) + + def scramble(self, data): + bio = BytesIO() + round_key = self.iv + ipad_template, opad_template = self.prepare_ipad_opad() + for i in range(0, len(data), 10): + #derived = self.get_hash( + # self.password, round_key := self.advance_round_key(round_key) + #) + round_key = self.advance_round_key(round_key) + ipad, opad = ipad_template.copy(), opad_template.copy() + ipad.update(round_key) + opad.update(ipad.digest()) + block = data[i:i + 10] + bio.write(bytes(a ^ b for a, b in zip(block, opad.digest()[:len(block)]))) + return bio.getvalue() + + +class HeaderReader: + def __init__(self): + self.iv_bio = BytesIO() + self.pw_mac_bio = BytesIO() + self.secret_bio = BytesIO() + self.current_bio = None + self.brace_level = 0 + + def find_header(self, line): + assert self.brace_level == 0 + parts = line.rsplit(maxsplit=4) + if parts[2:] != ["PROGMEM", "=", "{"]: + return + self.brace_level = line.count("{") + current_key = parts[1] + if (pos := current_key.find("[")) >= 0: + assert current_key[pos:] == "[]", current_key + current_key = current_key[:pos] + current_attr = f"{current_key}_bio" + assert current_key != "current" + self.current_bio = getattr(self, current_attr) + + def add_bytes(self, line): + pos = line.find(";") + done = pos >= 0 + if done: + line = line[:pos].rstrip() + for part in line.split(","): + part = part.strip() + while part.startswith("{"): + part = part[1:].lstrip() + self.brace_level += 1 + while part.endswith("}"): + self.brace_level -= 1 + part = part[:-1].rstrip() + if not part: + continue + assert part.startswith("0x"), part + self.current_bio.write(bytes((int(part, 16),))) + if done: + self.current_bio = None + + def parse(self, fh): + for line in fh: + line = line.strip() + if self.current_bio is None: + self.find_header(line) + else: + self.add_bytes(line) + + @property + def iv(self): + iv = self.iv_bio.getvalue() + assert len(iv) == 20 + return iv + + @property + def pw_mac(self): + pw_mac = self.pw_mac_bio.getvalue() + assert len(pw_mac) == 20 + return pw_mac + + @property + def secret(self): + secret = self.secret_bio.getvalue() + assert len(secret) > 0 + return secret + + +def cleanup_secret(infh): + return infh.read() + bio = BytesIO() + for line in infh: + line = line.strip() + if not line: + continue + assert len(line) < 79 and b":" in line + bio.write(line) + bio.write(b"\n") + return bio.getvalue() + + +class HeaderWriter: + @staticmethod + def indent(i): + return " " * i + + def __init__(self, fh, password): + self.fh = fh + self.iv = token_bytes(20) + self.password = password + + def print_as_const_sha_buf(self, varname, data): + print(f"static const struct sha1_buf {varname} PROGMEM = {{", file=self.fh) + print(f"{self.indent(4)}{{\n{self.indent(8)}", end="", file=self.fh) + last = len(data) - 1 + for i, b in enumerate(data): + print(f"0x{b:02x}", end=",", file=self.fh) + if i == last: + print(f"\n{self.indent(4)}}}", file=self.fh) + elif i % 12 == 11: + print(f"\n{self.indent(8)}", end="", file=self.fh) + else: + print(end=" ", file=self.fh) + print("};\n", file=self.fh) + + def print_as_const(self, varname, data): + print(f"static const uint8_t {varname}[] PROGMEM = {{", file=self.fh) + print(f"{self.indent(4)}", end="", file=self.fh) + last = len(data) - 1 + for i, b in enumerate(data): + print(f"0x{b:02x}", end=",", file=self.fh) + if i == last: + print(file=self.fh) + elif i % 12 == 11: + print(f"\n{self.indent(4)}", end="", file=self.fh) + else: + print(end=" ", file=self.fh) + print("};\n", file=self.fh) + + def write(self, secret): + print("\n// secrets.h\n", file=self.fh) + print("#ifndef SECRETS_H", file=self.fh) + print("#define SECRETS_H\n", file=self.fh) + print("#include ", file=self.fh) + print("#include \n", file=self.fh) + print('#include "sha1.h"\n', file=self.fh) + self.print_as_const_sha_buf("iv", self.iv) + self.print_as_const_sha_buf( + "pw_mac", CryptoManager.get_hash(self.iv, self.password) + ) + self.print_as_const( + "secret", + CryptoManager(self.iv, self.password).scramble(secret), + ) + print("#endif // SECRETS_H", file=self.fh) + + +def encrypt_secrets(project_dir, infile, new_password): + password = getpass().encode() + secrets_h = project_dir / "secrets.h" + if not new_password and secrets_h.exists(): + header = HeaderReader() + with secrets_h.open("rt") as fh: + header.parse(fh) + assert CryptoManager.get_hash(header.iv, password) == header.pw_mac + else: + other = getpass("Confirm password: ").encode() + assert password == other + with Path(infile).open("rb") as infh, secrets_h.open("wt") as outfh: + HeaderWriter(outfh, password).write(cleanup_secret(infh)) + +def decrypt_secrets(project_dir, outfile): + password = getpass().encode() + secrets_h = project_dir / "secrets.h" + assert secrets_h.exists() + header = HeaderReader() + with secrets_h.open("rt") as fh: + header.parse(fh) + assert CryptoManager.get_hash(header.iv, password) == header.pw_mac + with Path(outfile).open("wb") as fh: + fh.write(CryptoManager(header.iv, password).scramble(header.secret)) + + +def main(): + ap = ArgumentParser() + sp = ap.add_subparsers(dest="action", required=True, help="Actions") + ep = sp.add_parser("encrypt") + ep.add_argument("infile") + ep.add_argument("--new-password", action="store_true") + dp = sp.add_parser("decrypt") + dp.add_argument("outfile") + args = ap.parse_args() + project_dir = Path(__file__).parent.absolute() + if args.action == "encrypt": + encrypt_secrets(project_dir, args.infile, args.new_password) + elif args.action == "decrypt": + decrypt_secrets(project_dir, args.outfile) + + +if __name__ == "__main__": + main() diff --git a/repl.py b/repl.py index 440aa46..288bed9 100755 --- a/repl.py +++ b/repl.py @@ -29,116 +29,124 @@ from time import sleep, time from traceback import print_exc -def configure_port(fd): - """Configures the raw file descriptor to 115200 baud, 8N1, non-blocking.""" - # Get the current OS configuration attributes for the port file descriptor - attrs = tcgetattr(fd) - # Disable software flow control and mapping formatting - attrs[0] &= ~(IXON | IXOFF | IXANY | ICRNL) - # Pure raw output formatting - attrs[1] &= ~(OPOST | ONLCR) - # 8 data bits, enable receiver, ignore control lines - attrs[2] &= ~(PARENB | CSTOPB | CSIZE) # No Parity, 1 Stop Bit - attrs[2] |= (CS8 | CLOCAL | CREAD) # 8 Data Bits - # Raw input mode (Disable echo, erase, kill, interrupts) - attrs[3] &= ~(ICANON | ECHO | ECHOE | ISIG) - attrs[4] = B115200 # ospeed - attrs[5] = B115200 # ispeed - tcsetattr(fd, TCSANOW, attrs) - - -def send(fd, payload): - checksum = 0 - for char in payload: - checksum = checksum * 33 ^ ord(char) - for char, *rest in (("\\",), ("*",), ("$",), ("\n", "n")): - payload = payload.replace(char, (*rest, f"\\{char}")[0]) - os.write(fd, f"${payload}*{checksum & 0xff}\n".encode('ascii')) - - -def print_line(line): - try: - response = line.decode('ascii').strip() - except UnicodeDecodeError: - print("decoding failed.") - response = str(line) - print(response) - - -def await_some_reply(fd, wait_for_ok=False, timeout=5): - ba = bytearray() - stop_time = time() + (timeout if wait_for_ok else 0.3) - while True: - sleep(0.1) +def big_endian_hex(i): + return i.to_bytes((i.bit_length() + 7) >> 3 or 1, "big").hex() + + +class ReplManager: + def configure_port(self): + """Configures the raw file descriptor to 115200 baud, 8N1, non-blocking.""" + # Get the current OS configuration attributes for the port file descriptor + attrs = tcgetattr(self.fd) + # Disable software flow control and mapping formatting + attrs[0] &= ~(IXON | IXOFF | IXANY | ICRNL) + # Pure raw output formatting + attrs[1] &= ~(OPOST | ONLCR) + # 8 data bits, enable receiver, ignore control lines + attrs[2] &= ~(PARENB | CSTOPB | CSIZE) # No Parity, 1 Stop Bit + attrs[2] |= (CS8 | CLOCAL | CREAD) # 8 Data Bits + # Raw input mode (Disable echo, erase, kill, interrupts) + attrs[3] &= ~(ICANON | ECHO | ECHOE | ISIG) + attrs[4] = B115200 # ospeed + attrs[5] = B115200 # ispeed + tcsetattr(self.fd, TCSANOW, attrs) + + def __init__(self, dev_path): + self.dev_path = dev_path + self.fd = -1 + self.last_cmd = None + + def __enter__(self): + self.fd = os.open(self.dev_path, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK) + self.configure_port() + return self + + def send(self, payload): + checksum = 0 + for char in payload: + checksum = checksum * 33 ^ ord(char) + assert char not in "$*\n" + os.write(self.fd, f"${payload}*{checksum & 0xffff:x}\n".encode('ascii')) + + def get_cmd(self): try: - received = os.read(fd, 256) - except BlockingIOError: - if wait_for_ok and time() < stop_time: + cmd = input("> ") + except (EOFError, KeyboardInterrupt): + print() + return "QUIT" + return cmd.strip() + + def print_reply(self, line): + try: + response = line.decode('ascii').strip() + except UnicodeDecodeError: + print("decoding failed.") + response = str(line) + print(response) + + def await_some_reply(self, wait_for_ok=False, timeout=0.3): + ba = bytearray() + stop_time = time() + timeout + done = False + while not done: + sleep(0.1) + t = time() + try: + received = os.read(self.fd, 256) + except BlockingIOError: + received = b"" + done |= t >= stop_time + if not received or done: continue - break - if received: ba += received - stop_time = time() + (timeout if wait_for_ok else 0.3) - elif time() >= stop_time: - if wait_for_ok: + stop_time = t + (timeout if wait_for_ok else 0.3) + while b"\n" in ba: + line, rest = ba.split(b"\n", 1) + self.print_reply(line) + ba = rest + if wait_for_ok and line in (b"OK", b"NOK", b"EYB"): + done = True + break + if len(ba) > 0: + self.print_reply(ba) + + def __exit__(self, exc_type, exc_val, exc_tb): + if self.last_cmd != "BYE": + try: + self.send("BYE") + except OSError: + print_exc() + finally: + self.await_some_reply() + os.close(self.fd) + self.fd = -1 + + def run(self): + while (cmd := self.get_cmd()) != "QUIT": + if not cmd: + self.await_some_reply(False) continue - break - while b"\n" in ba: - line, *rest = ba.split(b"\n", 1) - print_line(line) - if len(rest) and len(rest[0]): - ba = rest[0] - elif wait_for_ok and line in (b"OK", b"NOK"): - return - else: - ba = bytearray() - break - - -sent_bye = False - - -def one_read_eval_print(fd): - global sent_bye - try: - cmd = input("> ") - except EOFError: - print() - return False - if cmd == "quit": - return False - elif cmd: - if cmd == "password": - cmd = f"password {getpass()}" - elif cmd.startswith("gettoken "): - cmd = f"gettoken {int(time()) + 1} {cmd[9:]}" - elif cmd == "dumpsecrets": - print("This command is not supported by repl.") - return False - send(fd, cmd) - sent_bye = cmd == "bye" - await_some_reply(fd, True) - else: - await_some_reply(fd, False) - return True + elif cmd == "PW": + cmd = f"PW {getpass().encode().hex()}" + elif cmd == "OTP GET" or cmd.startswith("OTP GET "): + rest = cmd[8:] + if rest: + rest = f" {rest.encode().hex()}" + cmd = f"OTP GET {big_endian_hex(int(time() + 1))}{rest}" + self.send(cmd) + self.last_cmd = cmd + self.await_some_reply(True, 5) def main(): - configure_port( - # Open fd with r/w, preventing controlling tty and non-blocking - fd := os.open(sys.argv[1], os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK) - ) - try: - while one_read_eval_print(fd): - pass - finally: - if not sent_bye: - try: - send(fd, "bye") - except OSError: - print_exc() - await_some_reply(fd) - os.close(fd) + if len(sys.argv) == 1: + dev_path = "/dev/ttyUSB0" + elif len(sys.argv) == 2: + dev_path = sys.argv[1] + else: + raise ValueError("Invalid arguments") + with ReplManager(dev_path) as repl: + repl.run() if __name__ == "__main__": diff --git a/sha1.c b/sha1.c index 2125c3a..eab857f 100644 --- a/sha1.c +++ b/sha1.c @@ -7,8 +7,8 @@ #define ARRAY_LENGTH(arr) (sizeof (arr) / sizeof (arr)[0]) #define ROTLEFT(a, b) ((a << b) | (a >> (32 - b))) -void sha1_init(struct sha1_ctx_type *ctx) { - *ctx = (struct sha1_ctx_type){ +void sha1_init(struct sha1_ctx *ctx) { + *ctx = (struct sha1_ctx){ .state = { .i = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }, }, @@ -18,7 +18,7 @@ void sha1_init(struct sha1_ctx_type *ctx) { static const uint32_t k[] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; -static void sha1_transform(struct sha1_ctx_type *ctx) { +static void sha1_transform(struct sha1_ctx *ctx) { struct sha1_ctx_state st; uint32_t f, t, m[80]; uint8_t i; @@ -55,7 +55,7 @@ static void sha1_transform(struct sha1_ctx_type *ctx) { ctx->state.i[i] += st.i[i]; } -void sha1_update(struct sha1_ctx_type *ctx, const uint8_t *data, size_t len) { +void sha1_update(struct sha1_ctx *ctx, const uint8_t *data, size_t len) { size_t i; uint8_t di; for (i = 0, di = ctx->bytelen & 63; i < len; i++) { @@ -68,7 +68,7 @@ void sha1_update(struct sha1_ctx_type *ctx, const uint8_t *data, size_t len) { ctx->bytelen += len; } -void sha1_final(struct sha1_ctx_type *ctx, uint8_t *hash) { +void sha1_final(struct sha1_ctx *ctx, struct sha1_buf *hash) { uint8_t di = ctx->bytelen & 63, i; ctx->data.b[di++] = 128; if (di > 56) { @@ -87,7 +87,7 @@ void sha1_final(struct sha1_ctx_type *ctx, uint8_t *hash) { ctx->data.b[63] = ctx->bytelen << 3; sha1_transform(ctx); for (i = 0; i < 20; i++) - hash[i] = ctx->state.i[i >> 2] >> (24 - ((i & 3) << 3)); + hash->b[i] = ctx->state.i[i >> 2] >> (24 - ((i & 3) << 3)); } void sha1_hmac( @@ -95,9 +95,9 @@ void sha1_hmac( size_t key_len, const uint8_t *data, size_t data_len, - uint8_t *mac + struct sha1_buf *mac ) { - struct sha1_ctx_type ctx; + struct sha1_ctx ctx; uint8_t k_ipad[64], k_opad[64], tk[20], i; if (key_len > 64) { sha1_init(&ctx); @@ -125,9 +125,9 @@ void sha1_hmac( void sha1_hmac_ipad_opad_init( const uint8_t *key, size_t key_len, - struct sha1_ctx_type ipad_opad_ctx[2] + struct sha1_ctx ipad_opad_ctx[2] ) { - struct sha1_ctx_type ctx; + struct sha1_ctx ctx; uint8_t k_ipad[64], k_opad[64], tk[20], i; if (key_len > 64) { sha1_init(&ctx); @@ -143,18 +143,18 @@ void sha1_hmac_ipad_opad_init( memset(k_ipad + key_len, 0x36, sizeof k_ipad - key_len); memset(k_opad + key_len, 0x5c, sizeof k_opad - key_len); sha1_init(ipad_opad_ctx); - sha1_update(ipad_opad_ctx, k_ipad, 64); + sha1_update(ipad_opad_ctx, k_ipad, sizeof k_ipad); sha1_init(&ipad_opad_ctx[1]); - sha1_update(&ipad_opad_ctx[1], k_opad, 64); + sha1_update(&ipad_opad_ctx[1], k_opad, sizeof k_opad); } void sha1_hmac_ipad_opad_digest( - struct sha1_ctx_type ipad_opad_ctx[2], + struct sha1_ctx ipad_opad_ctx[2], const uint8_t *data, size_t data_len, - uint8_t *mac + struct sha1_buf *mac ) { - struct sha1_ctx_type ipad_ctx = ipad_opad_ctx[0], opad_ctx = ipad_opad_ctx[1]; + struct sha1_ctx ipad_ctx = ipad_opad_ctx[0], opad_ctx = ipad_opad_ctx[1]; sha1_update(&ipad_ctx, data, data_len); sha1_final(&ipad_ctx, mac); sha1_update(&opad_ctx, mac, 20); diff --git a/sha1.h b/sha1.h index abc8219..b1a1eb6 100644 --- a/sha1.h +++ b/sha1.h @@ -7,7 +7,7 @@ #include #include -struct sha1_ctx_type { +struct sha1_ctx { struct sha1_ctx_data { uint8_t b[64]; } data; @@ -16,27 +16,30 @@ struct sha1_ctx_type { } state; uint64_t bytelen; }; +struct sha1_buf { + uint8_t b[20]; +}; -void sha1_init(struct sha1_ctx_type *ctx); -void sha1_update(struct sha1_ctx_type *ctx, const uint8_t *data, size_t len); -void sha1_final(struct sha1_ctx_type *ctx, uint8_t *hash); +void sha1_init(struct sha1_ctx *ctx); +void sha1_update(struct sha1_ctx *ctx, const uint8_t *data, size_t len); +void sha1_final(struct sha1_ctx *ctx, struct sha1_buf *hash); void sha1_hmac( const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, - uint8_t *mac + struct sha1_buf *mac ); void sha1_hmac_ipad_opad_init( const uint8_t *key, size_t key_len, - struct sha1_ctx_type ipad_opad_ctx[2] + struct sha1_ctx ipad_opad_ctx[2] ); void sha1_hmac_ipad_opad_digest( - struct sha1_ctx_type ipad_opad_ctx[2], + struct sha1_ctx ipad_opad_ctx[2], const uint8_t *data, size_t data_len, - uint8_t *mac + struct sha1_buf *mac ); #endif // SHA1_H diff --git a/totp.c b/totp.c deleted file mode 100644 index eb3ecd1..0000000 --- a/totp.c +++ /dev/null @@ -1,231 +0,0 @@ - -// totp.c - -#include -#include - -#include "secrets.h" -#include "sha1.h" -#include "uart.h" - -struct decrypt_buffers { - struct sha1_ctx_type ipad_opad_ctx[2]; - uint8_t orig_key[20], round_key[20], mac[20], chunk[32]; -}; - -int check_password(uint8_t *password, size_t password_len) { - const uint8_t mac[20], key_copy[sizeof key], pw_mac_copy[sizeof pw_mac]; - memcpy_P(key_copy, key, sizeof key); - memcpy_P(pw_mac_copy, pw_mac, sizeof pw_mac); - sha1_hmac(key_copy, sizeof key, password, password_len, mac); - return memcmp(mac, pw_mac_copy, sizeof mac); -} - -static inline uint8_t b32_decode(uint8_t *buf) { - static const uint8_t alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; - uint8_t bits, *outptr, *inptr, *found_in_alphabet; - int8_t shift = 3; - /* Cycle through {-4..3} in intervals of 3 (== -5): - * { 3, -2, 1, -4, -1, 2, -3, 0 } - * This corresponds to how the shift offsets for decoded bits unfold. - */ - for ( - outptr = inptr = buf; - *inptr != '\n' && *inptr != '\0' && *inptr != '='; - inptr++ - ) { - if (*inptr == ' ' || *inptr == '\t') - continue; - found_in_alphabet = strchr(alphabet, toupper(*inptr)); - if (found_in_alphabet == NULL) { - UART_write_string("ERROR:INVALIDB32\n"); - return 0; - } - bits = found_in_alphabet - alphabet; - switch (shift) { - case 0: - *outptr++ |= bits; - break; - case 1: - case 2: - *outptr |= bits << shift; - break; - case 3: - *outptr = bits << 3; - break; - default: - *outptr |= bits >> -shift; - *++outptr = bits << (shift + 8); - break; - } - shift += 3 - (shift > 0) * 8; - } - return outptr - buf; -} - -void process_line( - const uint8_t *password, - uint8_t password_len, - const uint8_t *line, - const uint8_t *search, - int64_t time -) { - uint32_t result; - uint8_t *colon = strrchr(line, ':'), *find, time_msg[sizeof time], md[20], i, len; - if ( - colon == NULL - || search == NULL - || (*search && (find = strstr(line, search)) == NULL) - ) - return; - if (!*search) { - UART_write_string_partial(line, colon - line); - UART_write_byte('\n'); - return; - } - time /= 30; - for (i = 0; i < sizeof time; i++) - time_msg[i] = time >> ((sizeof time - 1 - i) * 8); - colon++; - if ((len = b32_decode(colon)) == 0) - return 1; - sha1_hmac(colon, len, time_msg, sizeof time_msg, md); - i = md[sizeof md - 1] & 0xf; - result = ( - ((uint32_t)(md[i] & 0x7f) << 24) - | ((uint32_t)md[i + 1] << 16) - | ((uint32_t)md[i + 2] << 8) - | md[i + 3] - ) % 1000000; - UART_write_string_partial(line, colon - line); -/* - UART_write_byte(' '); - for (i = 0; i < sizeof md * 2; i++) - UART_write_byte( - "0123456789abcdef"[md[i >> 1] >> (!(i & 1) << 2) & 15] - ); - UART_write_byte(' '); - for (i = 0; i < len * 2; i++) - UART_write_byte( - "0123456789abcdef"[colon[i >> 1] >> (!(i & 1) << 2) & 15] - ); - UART_write_byte(' '); - for (i = 0; i < sizeof time_msg * 2; i++) - UART_write_byte( - "0123456789abcdef"[time_msg[i >> 1] >> (!(i & 1) << 2) & 15] - ); -*/ - UART_write_byte(' '); - UART_write_byte('0' + result / 100000 % 10); - UART_write_byte('0' + result / 10000 % 10); - UART_write_byte('0' + result / 1000 % 10); - UART_write_byte('0' + result / 100 % 10); - UART_write_byte('0' + result / 10 % 10); - UART_write_byte('0' + result % 10); - UART_write_byte('\n'); - return 1; -} - -void advance_round_key(const char *orig_key, char *round_key) { - uint8_t i, j; - for (i = 0; i < 20; i++) { - j = orig_key[i] & 31; - round_key[j]++; - if (round_key[j] != 0) - break; - } -} - -static inline uint8_t *parse_time(const uint8_t *args, int64_t *time) { - int64_t a = 0, b; - while (*args >= '0' && *args <= '9') { - b = 10 * a + *args - '0'; - if (b / 10 != a) - return NULL; - a = b; - args++; - } - *time = a; - while (*args == ' ') - args++; - return args; -} - -static inline void init_decrypt_buffers( - struct decrypt_buffers *bufs, uint8_t *password, uint8_t password_len -) { - memcpy_P(bufs->orig_key, key, 20); - memcpy(bufs->round_key, bufs->orig_key, 20); - sha1_hmac_ipad_opad_init(password, password_len, bufs->ipad_opad_ctx); -} - -static inline uint8_t get_byte_from_decrypt_buffers( - struct decrypt_buffers *bufs, size_t i -) { - if (i % sizeof bufs->chunk == 0) { - if (i + sizeof bufs->chunk <= sizeof secret) - memcpy_P(bufs->chunk, secret + i, sizeof bufs->chunk); - else { - memcpy_P(bufs->chunk, secret + i, sizeof secret - i); - memset( - bufs->chunk + sizeof secret - i, - 0, - sizeof bufs->chunk - (sizeof secret - i) - ); - } - } - if (i % (sizeof bufs->mac / 2) == 0) { - if (i > 0) - advance_round_key(bufs->orig_key, bufs->round_key); - sha1_hmac_ipad_opad_digest( - bufs->ipad_opad_ctx, bufs->round_key, sizeof bufs->round_key, bufs->mac - ); - } - return bufs->chunk[i % sizeof bufs->chunk] ^ bufs->mac[i % (sizeof bufs->mac / 2)]; -} - -uint8_t decrypt_secrets(const uint8_t *password, const uint8_t *args) { - struct decrypt_buffers bufs; - int64_t time; - size_t i; - uint8_t round_bytes = 0, chunk_offset = 0, bytes_remaining, chunk_bytes = 0; - uint8_t line[80], c, line_index = 0, replied = 0; - uint8_t password_len = strlen(password); - if ((password_len = strlen(password)) == 0) { - UART_write_string("ERROR:NOPASSWORD\n"); - return 1; - } - if ((args = parse_time(args, &time)) == NULL) { - UART_write_string("ERROR:PARSETIMEFAILED\n"); - return 1; - } - init_decrypt_buffers(&bufs, password, password_len); - for (i = 0; i < sizeof secret; i++) { - c = get_byte_from_decrypt_buffers(&bufs, i); - if (c == '\n' || line_index == sizeof line - 1) { - line[line_index] = '\0'; - process_line(password, password_len, line, args, time); - line_index = 0; - } else - line[line_index++] = c; - } - if (line_index > 0) { - line[line_index] = '\0'; - process_line(password, password_len, line, args, time); - } - return 0; -} - -uint8_t dump_secrets(const uint8_t *password) { - struct decrypt_buffers bufs; - size_t i; - uint8_t password_len = strlen(password); - if (password_len == 0) { - UART_write_string("ERROR:NOPASSWORD\n"); - return 1; - } - init_decrypt_buffers(&bufs, password, password_len); - for (i = 0; i < sizeof secret; i++) - UART_write_byte(get_byte_from_decrypt_buffers(&bufs, i)); - return 0; -} diff --git a/totp.h b/totp.h deleted file mode 100644 index 45e9162..0000000 --- a/totp.h +++ /dev/null @@ -1,14 +0,0 @@ - -// decrypt.h - -#ifndef DECRYPT_H -#define DECRYPT_H - -#include -#include - -int check_password(uint8_t *password, size_t password_len); -uint8_t decrypt_secrets(const uint8_t *password, const uint8_t *args); -uint8_t dump_secrets(const uint8_t *password); - -#endif // DECRYPT_H \ No newline at end of file diff --git a/uart.c b/uart.c index 5e4f3e1..f0544a5 100644 --- a/uart.c +++ b/uart.c @@ -9,7 +9,7 @@ static struct { volatile uint8_t data[62], head, tail; -} buffer = { { 0 }, 0, 0 }; +} UART_read_buffer = { { 0 }, 0, 0 }; void UART_init(void) { UBRR0H = (uint8_t)(MYUBRR >> 8); // Set baud rate High byte @@ -18,33 +18,34 @@ void UART_init(void) { // Enable Transmitter, Receiver and Receive Interrupt hardware trigger UCSR0B = (1 << TXEN0) | (1 << RXEN0) | (1 << RXCIE0); UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // 8 data bits, 1 stop bit + sei(); } -void UART_flush(void) { - buffer.head = buffer.tail = 0; +void UART_read_buffer_flush(void) { + UART_read_buffer.head = UART_read_buffer.tail = 0; } ISR(USART_RX_vect) { - uint8_t next_head = buffer.head + 1, c = UDR0; - if (next_head == sizeof buffer.data) + uint8_t next_head = UART_read_buffer.head + 1, c = UDR0; + if (next_head == sizeof UART_read_buffer.data) next_head = 0; // Store in ring buffer if it isn't full - if (next_head != buffer.tail) { - buffer.data[buffer.head] = c; - buffer.head = next_head; + if (next_head != UART_read_buffer.tail) { + UART_read_buffer.data[UART_read_buffer.head] = c; + UART_read_buffer.head = next_head; } } uint8_t UART_bytes_available(void) { - return buffer.head != buffer.tail; + return UART_read_buffer.head != UART_read_buffer.tail; } uint8_t UART_read_byte(void) { - unsigned char c = buffer.data[buffer.tail]; - if (buffer.tail != buffer.head) { - buffer.tail = buffer.tail + 1; - if (buffer.tail == sizeof buffer.data) - buffer.tail = 0; + unsigned char c = UART_read_buffer.data[UART_read_buffer.tail]; + if (UART_read_buffer.tail != UART_read_buffer.head) { + UART_read_buffer.tail = UART_read_buffer.tail + 1; + if (UART_read_buffer.tail == sizeof UART_read_buffer.data) + UART_read_buffer.tail = 0; } return c; } diff --git a/uart.h b/uart.h index c0e7c2b..cdf903b 100644 --- a/uart.h +++ b/uart.h @@ -4,12 +4,12 @@ #ifndef UART_H #define UART_H -#include #include +#include #include void UART_init(void); -void UART_flush(void); +void UART_read_buffer_flush(void); uint8_t UART_bytes_available(void); uint8_t UART_read_byte(void); @@ -23,15 +23,11 @@ static inline void UART_write_byte(uint8_t c) { UDR0 = c; } -static inline void UART_write_string(const uint8_t* str) { - while (*str) - UART_write_byte(*str++); -} - static inline void UART_write_string_partial(const uint8_t* str, size_t len) { size_t i; - for (i = 0; i < len; i++) + for (i = 0; len ? (i < len) : str[i]; i++) UART_write_byte(str[i]); } +#define UART_write_string(s) UART_write_string_partial((s), 0) #endif // UART_H -- 2.54.0