diff --git a/README.md b/README.md index 4c6dc15..a85dd9c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ TurtlPass Firmware provides a simple and secure way of generating passwords usin * Generates unique, secure passwords from a simple input hash * 100 characters long, including a combination of lowercase and uppercase letters, as well as numbers -* Uses a seed stored in flash memory for added security +* Seed material stored in flash memory for added security * Automatically types the password for you, so you don't have to * Erases the password from memory after use, for extra peace of mind * Easy to integrate into your existing projects with USB serial port connectivity @@ -26,9 +26,9 @@ TurtlPass Firmware provides a simple and secure way of generating passwords usin -1. **Raspberry Pi Pico** -2. **OTG Cable**: micro-USB (male) to USB-C (male) -3. **Cover/Case** (optional) +1. **RP2040 Board**: both **Raspberry Pi Pico** and **Adafruit Trinkey QT2040** have been tested ✅ +2. **USB OTG Cable / Adapter** +3. Cover/Case (optional) ## 💡 LED State @@ -43,6 +43,16 @@ TurtlPass Firmware provides a simple and secure way of generating passwords usin * No power input +**If your board have a RGB LED**, is possible to **switch seed** by pressing the `BOOTSEL` button on the board (in the `ON` state only). Here are the 6 available colors: + +1. 🟢 Green (default) +2. 🟡 Yellow +3. 🔴 Red +4. 🔵 Blue +5. ⚪ White +6. 🟣 Magenta + + ## 💿 Installation and getting started ### 1. Install the Arduino Legacy IDE (1.8.19) diff --git a/generate_seed_file.sh b/generate_seed_file.sh index db5d32c..e379906 100755 --- a/generate_seed_file.sh +++ b/generate_seed_file.sh @@ -5,14 +5,18 @@ echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" echo ">>> Generating Seed.cpp file" echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" -# Generate a new private key -openssl genrsa -out seed.tmp 4096 - -# Skip the first and last line of the private key file -TOTAL_LINES=$(wc -l seed.tmp | awk '{print $1}') - -# Store the output of the tail and head commands in the SEED variable -SEED=$(tail -n +2 seed.tmp | head -n $((TOTAL_LINES - 2))) +SEEDS=() +for i in {1..6}; do + # Generate a new private key 4096 bits + openssl genrsa -out seed.tmp 4096 + # Skip the first and last line of the private key file + TOTAL_LINES=$(wc -l seed.tmp | awk '{print $1}') + # Store the output of the tail and head commands in the SEED variable + SEED=$(tail -n +2 seed.tmp | head -n $((TOTAL_LINES - 2))) + SEEDS+=( "$SEED" ) + # Clean up + rm seed.tmp +done # Create the timestamp TIMESTAMP=$(date +"%Y%m%d%H%M%S") @@ -24,17 +28,20 @@ touch "$FILE_NAME" # Write the contents of the file cat > "$FILE_NAME" << EOF #include "Seed.h" +EOF -const char* seed PROGMEM = R"key( -$SEED +for i in {0..5}; do + cat >> "$FILE_NAME" << EOF +const char* seed$i PROGMEM = R"key( +${SEEDS[$i]} )key"; EOF +done -# Clean up -rm seed.tmp +cat >> "$FILE_NAME" << EOF +const char* seedArray[] PROGMEM = {seed0, seed1, seed2, seed3, seed4, seed5}; +EOF -echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" -echo "$SEED" echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" echo ">>> Generated file: $FILE_NAME" echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" diff --git a/turtlpass-firmware/Kdf.cpp b/turtlpass-firmware/Kdf.cpp index 63be228..e8a063a 100644 --- a/turtlpass-firmware/Kdf.cpp +++ b/turtlpass-firmware/Kdf.cpp @@ -6,7 +6,7 @@ const uint8_t KDF_SIZE = 75; // 3/4 of 100 characters // KDF // ///////// -bool processKeyDerivation(uint8_t *output, size_t outputLength, char *input) { +bool processKeyDerivation(uint8_t *output, size_t outputLength, char *input, const char* seed) { size_t inputLength = strlen(input); uint8_t *src = (uint8_t *)malloc(inputLength); memcpy(src, input, inputLength); diff --git a/turtlpass-firmware/Kdf.h b/turtlpass-firmware/Kdf.h index 7a91d93..26b992b 100644 --- a/turtlpass-firmware/Kdf.h +++ b/turtlpass-firmware/Kdf.h @@ -4,10 +4,9 @@ #include #include "SHA512.h" #include "HKDF.h" -#include "Seed.h" #include "HexUtil.h" -bool processKeyDerivation(uint8_t *output, size_t outputLength, char *input); +bool processKeyDerivation(uint8_t *output, size_t outputLength, char *input, const char* seed); void hkdf(const uint8_t *password, size_t passwordLength, const uint8_t *salt, size_t saltLength, uint8_t *key, size_t keyLength); void hex2Password(const uint8_t *src, size_t srcLength, uint8_t *dst); diff --git a/turtlpass-firmware/LedState.cpp b/turtlpass-firmware/LedState.cpp index edced47..f761804 100644 --- a/turtlpass-firmware/LedState.cpp +++ b/turtlpass-firmware/LedState.cpp @@ -24,7 +24,6 @@ unsigned long lastLedPulseUpdateMillis = MAX_LONG; LedState::LedState(byte pin) { this->pin = pin; - init(); } ////////// diff --git a/turtlpass-firmware/RgbLedState.cpp b/turtlpass-firmware/RgbLedState.cpp new file mode 100644 index 0000000..023ee15 --- /dev/null +++ b/turtlpass-firmware/RgbLedState.cpp @@ -0,0 +1,111 @@ +#include "RgbLedState.h" + +// Create the neopixel with the built in definitions NUM_NEOPIXEL and PIN_NEOPIXEL +Adafruit_NeoPixel neoPixel = Adafruit_NeoPixel(NUM_NEOPIXEL, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800); +Led RgbLedState::led; + +///////////////// +// CONSTRUCTOR // +///////////////// + +RgbLedState::RgbLedState() {} + +////////// +// INIT // +////////// + +void RgbLedState::init() { + led.red = 0; + led.green = 255; + led.blue = 0; + led.brightness = 255; // max + led.fadeAmount = 3; // step + led.blinkSpeed = 60; // in ms + led.pulseSpeed = 6; // in ms + led.lastUpdate = 1410065407; // max long + led.state = LED_ON; + + neoPixel.begin(); + neoPixel.setPixelColor(0, neoPixel.Color(led.red, led.green, led.blue)); + neoPixel.setBrightness(led.brightness); + neoPixel.show(); +} + +////////////////// +// UPDATE STATE // +////////////////// + +void RgbLedState::setOn() { + if (led.state != LED_ON) { + led.state = LED_ON; + led.brightness = 255; + } +} + +void RgbLedState::setOff() { + if (led.state != LED_OFF) { + led.state = LED_OFF; + led.brightness = 0; + } +} + +void RgbLedState::setPulsing() { + if (led.state != LED_PULSING) { + led.brightness = 0; + led.fadeAmount = 3; + led.state = LED_PULSING; + } +} + +void RgbLedState::setBlinking() { + if (led.state != LED_BLINKING) { + led.state = LED_BLINKING; + } +} + +void RgbLedState::setColor(int colorIndex) { + if (colorIndex < 0 || colorIndex >= NUM_COLORS) { + return; + } + led.red = colors[colorIndex][0]; + led.green = colors[colorIndex][1]; + led.blue = colors[colorIndex][2]; +} + + +////////// +// LOOP // +////////// + +void RgbLedState::loop() { + switch (led.state) { + case LED_OFF: { + led.brightness = 0; + break; + } + case LED_BLINKING: { + if (millis() - led.lastUpdate > led.blinkSpeed) { + led.brightness = (led.brightness == 0) ? 255 : 0; + led.lastUpdate = millis(); + } + break; + } + case LED_PULSING: { + if (millis() - led.lastUpdate > led.pulseSpeed) { + led.brightness += led.fadeAmount; + // reverse the direction of the fading at the ends of the fade + if (led.brightness <= 0 || led.brightness >= 255) { + led.fadeAmount = -led.fadeAmount; + } + led.lastUpdate = millis(); + } + break; + } + default: { //case LED_ON: + led.brightness = 255; + break; + } + } + neoPixel.setPixelColor(0, neoPixel.Color(led.red * led.brightness / 255, led.green * led.brightness / 255, led.blue * led.brightness / 255)); + neoPixel.show(); +} diff --git a/turtlpass-firmware/RgbLedState.h b/turtlpass-firmware/RgbLedState.h new file mode 100644 index 0000000..32c6235 --- /dev/null +++ b/turtlpass-firmware/RgbLedState.h @@ -0,0 +1,53 @@ +#ifndef RGB_LED_STATE_H +#define RGB_LED_STATE_H + +#include +#include + +enum State { + LED_OFF = 0, + LED_ON = 1, + LED_PULSING = 2, + LED_BLINKING = 3 +}; + +#define NUM_COLORS 6 +const uint8_t colors[NUM_COLORS][3] = { + {0, 255, 0}, // green + {255, 255, 0}, // yellow + {255, 0, 0}, // red + {0, 0, 255}, // blue + {255, 255, 255},// white + {255, 0, 255}, // magenta +}; + +struct Led { + uint8_t red; + uint8_t green; + uint8_t blue; + int brightness; + int fadeAmount; + int blinkState; + int blinkSpeed; // in ms + int pulseSpeed; // in ms + unsigned long lastUpdate; + State state; +}; + +class RgbLedState { + + public: + RgbLedState(); + void init(); + void setOn(); + void setOff(); + void setPulsing(); + void setBlinking(); + void setColor(int colorIndex); + void loop(); + + private: + static Led led; +}; + +#endif // RGB_LED_STATE_H diff --git a/turtlpass-firmware/Seed.cpp.example b/turtlpass-firmware/Seed.cpp.example index 079f740..272b6b1 100644 --- a/turtlpass-firmware/Seed.cpp.example +++ b/turtlpass-firmware/Seed.cpp.example @@ -1,10 +1,9 @@ #include "Seed.h" - -const char* seed PROGMEM = R"key( -MIIJKAIBAAKCAgEAxDQLexB3Xwn4I1GSAV/PNDUCDkP+MIcxcyG0BtYtBErV+Xi0 +const char* seed0 PROGMEM = R"key( +EXAMPLE_AAKCAgEAxDQLexB3Xwn4I1GSAV/PNDUCDkP+MIcxcyG0BtYtBErV+Xi0 y7qmzXaP3+jQRXWaC3gKTUVaKW9YcxMUX7C3P7MQ7/OCh6L/coUsY257nY7xEPtd ztypLf89mz4fzZKRWKI5m5AtFQg1YQuatXNLqKarwUZWMG+ETv7x3Wq/+XF7riny -mAZA5zhXSL4iHAST9EkoLchw3PlmAkeEwEkqdi/WD3G3Lg/xHkp1xpnRrIB4jcIQ +mAZA5zaXSL4iHAST9EkoLchw3PlmAkeEwEkqdi/WD3G3Lg/xHkp1xpnRrIB4jcIQ ZS9hAyFa2ddCsOeBQxBp+H2XyDxSe8AU59yNqrEgGLvPFochCSImAhTIm+InakOM RbaVeqYWNfZpp1ILoHRNtBh28Xm3Bvf65vL1DBu3vkF2km3DRD7NpFGBt9YvJSRa 8RvpGNhhvbxFBSJJTuakukgy4IaLMJj81JBo0a3vX6JNZzYCUb53NMG4uiLlRoN6 @@ -23,7 +22,7 @@ qL/haVSYl9/UculTviIKdKmsO/R4gQ5trsPH2c9t2UXFMp44p2M5FWN/L4nJFuPS Nehl+P+1H8MicTjqgzStUmBoZBA+KBeMPr2z1wc3gwnAMynmlt3IUIoHwL+BKWu7 lFk+iEemo40T7jQ3io7Ydn9Ovrx0k0UufxiG/tKLyKQQdajJNaYkEzVK5GsiaXRz Bbg1RuIe6DG6DJKPykp+z00oDWFD7e3nJ81R3oMqICT9YZ+wyQKCAQEA9BiolcBb -uZvOFFT378dqW9/Ro6CZihv02eRU+PsxqIoXJ/1aaDX8lrg5uEHpgIbHhx+iFwhf +uZvOFFT378dqW9/Ro6CZihv02eRU+PsxqIoXJ/1aaDX8vrg5uEHpgIbHhx+iFwhf vunFfi7JBeZWeVaGb9BXMGKrwDsChXfx9+s34/4yAQzncK7/BoL5NotPvzjifjT4 I/RDzXJY7pWPsgpB0u7cujQpgG+3JZOlzkpF8M6Xxy4rk0QUjiUrbHf43XToPPsj lIdu6sNaEbnBbhLirkUyLY2GxrVTL2xBrY4y8tL182KwpN9F6KetMJD6nSBZ3UFO @@ -51,3 +50,259 @@ azwpBV2Ek0bHFE5rB+i9jIt982VGU0oAHPI706VZ60vamzkrgVCOpkWM37+FsbDZ m7abBzkDGFYH07KOT4SnKjDdxb4nXGUZGuro3VpN/BPtBivjw6V7GvSmhfYQ0MDD ZXfM+TjjxrqAIFwaFIc8cq8B9geqe2RlmfIOqXNTtMpQN7hP27GmG7dnMxo= )key"; +const char* seed1 PROGMEM = R"key( +EXAMPLE_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 +)key"; +const char* seed2 PROGMEM = R"key( +EXAMPLE_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 +)key"; +const char* seed3 PROGMEM = R"key( +EXAMPLE_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 +)key"; +const char* seed4 PROGMEM = R"key( +EXAMPLE_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 +)key"; +const char* seed5 PROGMEM = R"key( +EXAMPLE_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 +)key"; +const char* seedArray[] PROGMEM = {seed0, seed1, seed2, seed3, seed4, seed5}; diff --git a/turtlpass-firmware/Seed.h b/turtlpass-firmware/Seed.h index 8a8ad95..0765976 100644 --- a/turtlpass-firmware/Seed.h +++ b/turtlpass-firmware/Seed.h @@ -3,6 +3,6 @@ #include -extern const char *seed PROGMEM; +extern const char* seedArray[] PROGMEM; #endif // SEED_H diff --git a/turtlpass-firmware/turtlpass-firmware.ino b/turtlpass-firmware/turtlpass-firmware.ino index 0755863..2248216 100644 --- a/turtlpass-firmware/turtlpass-firmware.ino +++ b/turtlpass-firmware/turtlpass-firmware.ino @@ -20,8 +20,18 @@ #include #include +#include "Seed.h" #include "Kdf.h" + +#define BOARD_WITH_RGB_LED true // <--- COMMENT THIS LINE IF YOUR BOARD DOES NOT HAVE A RGB LED + +#ifdef BOARD_WITH_RGB_LED +#include "RgbLedState.h" +RgbLedState ledState; +#else #include "LedState.h" +LedState ledState(LED_BUILTIN); +#endif /////////////// // Variables // @@ -34,7 +44,7 @@ const uint8_t OUTPUT_SIZE = 100; // 100 characters char input[INPUT_BUFFER_SIZE]; uint8_t output[OUTPUT_SIZE + 1]; bool isExecuting = false; -LedState ledState(LED_BUILTIN); +int colorIndex = 0; // green ///////////// // Methods // @@ -53,12 +63,20 @@ void typeOutputKey(); void setup() { Serial.begin(115200); Keyboard.begin(); + ledState.init(); delay(1000); } void loop() { if (BOOTSEL) { - typeOutputKey(); + if (output[0] != 0) { + typeOutputKey(); + } else { +#ifdef BOARD_WITH_RGB_LED + colorIndex = (colorIndex + 1) % NUM_COLORS; + ledState.setColor(colorIndex); +#endif + } while (BOOTSEL); } else { processSerial(); @@ -124,7 +142,7 @@ bool validateInput() { return false; } } - return processKeyDerivation(output, sizeof(output), substring); + return processKeyDerivation(output, sizeof(output), substring, seedArray[colorIndex]); } ////////////