*.elf
*.hex
.idea
+__pycache__/
secrets.h
#!/usr/bin/env bash
tmpdir="$(mktemp -d -p/dev/shm)"
+
cleanup() {
rm -rf "${tmpdir}"
}
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}"
--- /dev/null
+
+// 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);
+}
--- /dev/null
+
+// decrypt.h
+
+#ifndef DECRYPT_H
+#define DECRYPT_H
+
+#include <stdint.h>
+
+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
--- /dev/null
+
+// encoding.h
+
+#ifndef ENCODING_H
+#define ENCODING_H
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+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
+++ /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()
// main.c
+#include <limits.h>
#include <stdint.h>
-#include <avr/interrupt.h>
+#include <avr/io.h>
-#include "totp.h"
-#include "sha1.h"
+#include "decrypt.h"
+#include "encoding.h"
#include "uart.h"
static uint8_t password[64];
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 <hex-encoded-pw> -> OK if hmac matches else NOK X
+ * OTP LS -> list all secrets and OK X
+ * OTP GET <timestamp> <hex-encoded-filter> -> show totp digits for matches of filter
+ * OTP GET <timestamp> -> 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");
}
}
--- /dev/null
+#!/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 <stdint.h>", file=self.fh)
+ print("#include <avr/pgmspace.h>\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()
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__":
#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 },
},
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;
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++) {
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) {
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(
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);
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);
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);
#include <stdint.h>
#include <stdlib.h>
-struct sha1_ctx_type {
+struct sha1_ctx {
struct sha1_ctx_data {
uint8_t b[64];
} data;
} 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
+++ /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
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
// 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;
}
#ifndef UART_H
#define UART_H
-#include <stdlib.h>
#include <stdint.h>
+#include <stdlib.h>
#include <avr/io.h>
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);
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