--- /dev/null
+*.bin
+*.eep
+*.elf
+*.hex
+.idea
+secrets.h
--- /dev/null
+#!/usr/bin/env bash
+
+tmpdir="$(mktemp -d -p/dev/shm)"
+cleanup() {
+ rm -rf "${tmpdir}"
+}
+trap cleanup EXIT
+
+extra_args=(
+ --fqbn arduino:avr:nano
+ --build-path "${tmpdir}"
+ --build-property "compiler.c.extra_flags=-Wall -Wextra -std=c99"
+ --build-property "compiler.cpp.extra_flags=-Wall -Wextra"
+ --output-dir .
+)
+while (( $# )); do
+ case "${1}" in
+ -u|--upload)
+ extra_args+=(-u -p /dev/ttyUSB0)
+ ;;
+ esac
+ shift
+done
+arduino-cli compile "${extra_args[@]}" .
+#rm -r "${tmpdir}"
--- /dev/null
+#!/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 <stdint.h>")
+ print("#include <avr/pgmspace.h>\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()
--- /dev/null
+
+// main.c
+
+#include <stdint.h>
+#include <avr/interrupt.h>
+
+#include "totp.h"
+#include "sha1.h"
+#include "uart.h"
+
+static uint8_t password[64];
+
+static inline void wait_for_input(void) {
+ register uint8_t corr = 0; // prevent drift (8 iterations of TCNT1 => 62500)
+ DDRB |= (1 << PB5); // Set Digital Pin 13 (Port B, Pin 5) to OUTPUT
+ TCCR1A = 0; // Normal operation mode
+ TCCR1B = (1 << CS12); // Set Prescaler to 256 (62,500 ticks per second)
+ while (!UART_bytes_available()) {
+ if (TCNT1 >= 7812 + corr) {
+ PORTB ^= (1 << PB5); // Toggle LED
+ TCNT1 = 0; // Reset hardware timer register back to 0
+ corr ^= 1;
+ }
+ }
+ PORTB &= ~(1 << PB5); // Turn off LED
+ 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]
+ );
+}
+*/
+
+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)
+ 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 (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;
+}
+
+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;
+ }
+ switch (state) {
+ case STATE_IDLE:
+ if (esc == 0 && c == '$') {
+ state = STATE_PAYLOAD;
+ payload_idx = calculated_xor = 0;
+ }
+ 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");
+ }
+ 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
+ break;
+ }
+ if (esc == 1)
+ esc = 0;
+ }
+}
+
+int main(void) {
+ UART_init();
+ sei();
+ for (;;) {
+ wait_for_input();
+ parse_serial_frame();
+ memset(password, 0, sizeof password);
+ UART_flush();
+ UART_write_string("EYB\n");
+ }
+}
--- /dev/null
+#!/usr/bin/env python3
+
+import os
+import sys
+from getpass import getpass
+from termios import (
+ B115200,
+ CS8,
+ CLOCAL,
+ CREAD,
+ CSIZE,
+ CSTOPB,
+ ECHO,
+ ECHOE,
+ ICANON,
+ ICRNL,
+ IXANY,
+ IXOFF,
+ IXON,
+ ISIG,
+ ONLCR,
+ OPOST,
+ PARENB,
+ TCSANOW,
+ tcgetattr,
+ tcsetattr,
+)
+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 await_some_reply(fd, block=False):
+ received_nothing = True
+ while received_nothing:
+ sleep(0.1)
+ try:
+ response_bytes = os.read(fd, 256)
+ except BlockingIOError:
+ if block:
+ continue
+ break
+ if not response_bytes:
+ if block:
+ continue
+ break
+ received_nothing = False
+ try:
+ response = response_bytes.decode('ascii').strip()
+ except UnicodeDecodeError:
+ print("decoding failed.")
+ response = str(response_bytes)
+ print(response)
+
+
+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:]}"
+ send(fd, cmd)
+ sent_bye = cmd == "bye"
+ await_some_reply(fd, True)
+ else:
+ await_some_reply(fd, False)
+ return True
+
+
+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 __name__ == "__main__":
+ main()
--- /dev/null
+
+// sha1.c
+
+#include <string.h>
+#include "sha1.h"
+
+#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){
+ .state = {
+ .i = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 },
+ },
+ .bytelen = 0,
+ };
+}
+
+static const uint32_t k[] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
+
+static void sha1_transform(struct sha1_ctx_type *ctx) {
+ struct sha1_ctx_state st;
+ uint32_t f, t, m[80];
+ uint8_t i;
+ for (i = 0; i < sizeof ctx->data.b; i += 4)
+ m[i >> 2] = (
+ ((uint32_t)ctx->data.b[i] << 24)
+ | ((uint32_t)ctx->data.b[i + 1] << 16)
+ | ((uint32_t)ctx->data.b[i + 2] << 8)
+ | (uint32_t)ctx->data.b[i + 3]
+ );
+ for (i = 16; i < 80; i++) {
+ m[i] = (m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16]);
+ m[i] = ROTLEFT(m[i], 1);
+ }
+ st = ctx->state;
+ for (i = 0; i < 80; i++) {
+ if (i < 20)
+ f = (st.i[1] & st.i[2]) | (~st.i[1] & st.i[3]);
+ else if (i < 40)
+ f = st.i[1] ^ st.i[2] ^ st.i[3];
+ else if (i < 60)
+ f = (st.i[1] & st.i[2]) | (st.i[1] & st.i[3]) | (st.i[2] & st.i[3]);
+ else
+ f = st.i[1] ^ st.i[2] ^ st.i[3];
+ t = ROTLEFT(st.i[0], 5) + f + st.i[4] + k[i / 20] + m[i];
+ st.i[4] = st.i[3];
+ st.i[3] = st.i[2];
+ st.i[2] = ROTLEFT(st.i[1], 30);
+ st.i[1] = st.i[0];
+ st.i[0] = t;
+ }
+
+ for (i = 0; i < ARRAY_LENGTH(st.i); i++)
+ ctx->state.i[i] += st.i[i];
+}
+
+void sha1_update(struct sha1_ctx_type *ctx, const uint8_t *data, size_t len) {
+ size_t i;
+ uint8_t di;
+ for (i = 0, di = ctx->bytelen & 63; i < len; i++) {
+ ctx->data.b[di++] = data[i];
+ if (di == 64) {
+ sha1_transform(ctx);
+ di = 0;
+ }
+ }
+ ctx->bytelen += len;
+}
+
+void sha1_final(struct sha1_ctx_type *ctx, uint8_t *hash) {
+ uint8_t di = ctx->bytelen & 63, i;
+ ctx->data.b[di++] = 128;
+ if (di > 56) {
+ memset(ctx->data.b + di, 0, 64 - di);
+ sha1_transform(ctx);
+ di = 0;
+ } else
+ memset(ctx->data.b + di, 0, 56 - di);
+ ctx->data.b[56] = ctx->bytelen >> 53;
+ ctx->data.b[57] = ctx->bytelen >> 45;
+ ctx->data.b[58] = ctx->bytelen >> 37;
+ ctx->data.b[59] = ctx->bytelen >> 29;
+ ctx->data.b[60] = ctx->bytelen >> 21;
+ ctx->data.b[61] = ctx->bytelen >> 13;
+ ctx->data.b[62] = ctx->bytelen >> 5;
+ 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));
+}
+
+void sha1_hmac(
+ const uint8_t *key,
+ size_t key_len,
+ const uint8_t *data,
+ size_t data_len,
+ uint8_t *mac
+) {
+ struct sha1_ctx_type ctx;
+ uint8_t k_ipad[64], k_opad[64], tk[20], i;
+ if (key_len > 64) {
+ sha1_init(&ctx);
+ sha1_update(&ctx, key, key_len);
+ sha1_final(&ctx, tk);
+ key = tk;
+ key_len = sizeof tk;
+ }
+ for (i = 0; i < key_len; i++) {
+ k_ipad[i] = key[i] ^ 0x36;
+ k_opad[i] = key[i] ^ 0x5c;
+ }
+ memset(k_ipad + key_len, 0x36, sizeof k_ipad - key_len);
+ memset(k_opad + key_len, 0x5c, sizeof k_opad - key_len);
+ sha1_init(&ctx);
+ sha1_update(&ctx, k_ipad, 64);
+ sha1_update(&ctx, data, data_len);
+ sha1_final(&ctx, mac);
+ sha1_init(&ctx);
+ sha1_update(&ctx, k_opad, 64);
+ sha1_update(&ctx, mac, 20);
+ sha1_final(&ctx, 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_type ctx;
+ uint8_t k_ipad[64], k_opad[64], tk[20], i;
+ if (key_len > 64) {
+ sha1_init(&ctx);
+ sha1_update(&ctx, key, key_len);
+ sha1_final(&ctx, tk);
+ key = tk;
+ key_len = sizeof tk;
+ }
+ for (i = 0; i < key_len; i++) {
+ k_ipad[i] = key[i] ^ 0x36;
+ k_opad[i] = key[i] ^ 0x5c;
+ }
+ 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_init(&ipad_opad_ctx[1]);
+ sha1_update(&ipad_opad_ctx[1], k_opad, 64);
+}
+
+void sha1_hmac_ipad_opad_digest(
+ struct sha1_ctx_type ipad_opad_ctx[2],
+ const uint8_t *data,
+ size_t data_len,
+ uint8_t *mac
+) {
+ struct sha1_ctx_type 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);
+ sha1_final(&opad_ctx, mac);
+}
--- /dev/null
+
+// sha1.h
+
+#ifndef SHA1_H
+#define SHA1_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+struct sha1_ctx_type {
+ struct sha1_ctx_data {
+ uint8_t b[64];
+ } data;
+ struct sha1_ctx_state {
+ uint32_t i[5];
+ } state;
+ uint64_t bytelen;
+};
+
+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_hmac(
+ const uint8_t *key,
+ size_t key_len,
+ const uint8_t *data,
+ size_t data_len,
+ uint8_t *mac
+);
+void sha1_hmac_ipad_opad_init(
+ const uint8_t *key,
+ size_t key_len,
+ struct sha1_ctx_type ipad_opad_ctx[2]
+);
+void sha1_hmac_ipad_opad_digest(
+ struct sha1_ctx_type ipad_opad_ctx[2],
+ const uint8_t *data,
+ size_t data_len,
+ uint8_t *mac
+);
+
+#endif // SHA1_H
--- /dev/null
+
+// totp.c
+
+#include <ctype.h>
+#include <string.h>
+
+#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;
+}
--- /dev/null
+
+// decrypt.h
+
+#ifndef DECRYPT_H
+#define DECRYPT_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+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
--- /dev/null
+
+// uart.c
+
+#include <avr/interrupt.h>
+
+#include "uart.h"
+
+#define MYUBRR 16 // Register value for 115200 baud when U2X0 is enabled
+
+static struct {
+ volatile uint8_t data[62], head, tail;
+} buffer = { { 0 }, 0, 0 };
+
+void UART_init(void) {
+ UBRR0H = (uint8_t)(MYUBRR >> 8); // Set baud rate High byte
+ UBRR0L = (uint8_t)MYUBRR; // Set baud rate Low byte
+ UCSR0A |= (1 << U2X0); // Enable Double Speed Mode
+ // 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
+}
+
+void UART_flush(void) {
+ buffer.head = buffer.tail = 0;
+}
+
+ISR(USART_RX_vect) {
+ uint8_t next_head = buffer.head + 1, c = UDR0;
+ if (next_head == sizeof 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;
+ }
+}
+
+uint8_t UART_bytes_available(void) {
+ return buffer.head != 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;
+ }
+ return c;
+}
--- /dev/null
+
+// uart.h
+
+#ifndef UART_H
+#define UART_H
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <avr/io.h>
+
+void UART_init(void);
+void UART_flush(void);
+uint8_t UART_bytes_available(void);
+uint8_t UART_read_byte(void);
+
+static inline uint8_t UART_read_byte_blocking(void) {
+ while (!UART_bytes_available());
+ return UART_read_byte();
+}
+
+static inline void UART_write_byte(uint8_t c) {
+ while (!(UCSR0A & (1 << UDRE0)));
+ 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++)
+ UART_write_byte(str[i]);
+}
+
+#endif // UART_H