Skip to content

Instantly share code, notes, and snippets.

@fer
Last active October 18, 2025 21:06
Show Gist options
  • Select an option

  • Save fer/2e638e1e7194a96ca525bdb9c58ff7c4 to your computer and use it in GitHub Desktop.

Select an option

Save fer/2e638e1e7194a96ca525bdb9c58ff7c4 to your computer and use it in GitHub Desktop.
USB Password Injector with ATmega32U4 (CJMCU / Pro Micro / Leonardo)
/*
USB Password Injector with ATmega32U4 (CJMCU / Pro Micro / Leonardo)
-------------------------------------------------------------------
HOW TO CREATE AND USE THIS PROJECT WITH ARDUINO-CLI
===================================================
1. Create a new sketch folder:
arduino-cli sketch new usb_password
cd usb_password
2. Replace the generated usb_password.ino with this file.
(You can copy-paste this content into usb_password/usb_password.ino)
3. Compile the sketch:
arduino-cli compile --fqbn arduino:avr:leonardo usb_password
4. Upload the sketch to your board:
arduino-cli upload -p /dev/ttyACM0 --fqbn arduino:avr:leonardo usb_password
⚠️ If you get errors, press the reset button twice quickly and retry.
Sometimes the bootloader uses /dev/ttyACM1 instead of /dev/ttyACM0.
Confirm the port with:
arduino-cli board list
5. Optional: open serial monitor (for debug if you add Serial.print()):
arduino-cli monitor -p /dev/ttyACM0 -c baudrate=9600
BEHAVIOR
--------
- Single reset / power-on:
→ Device enters a "waiting window" (default 4 seconds).
→ If no second reset occurs within that time, it types PASSWORD1.
→ LED on pin 13 blinks during waiting and lights up when typing PASSWORD1.
- Double reset (second reset within the window):
→ On the next boot, the device immediately types PASSWORD2.
→ LED on pin 8 lights up while typing PASSWORD2.
- Triple reset (third reset within the window):
→ Wipes EEPROM (all 0s)
→ Both LEDs blink to confirm clear.
→ No password is sent.
NOTES
-----
- EEPROM stores the reset flag between reboots.
- USB HID requires a short delay (HOST_DETECT_MS) before sending keystrokes,
so the host OS can enumerate the device as a keyboard.
- Adjust WINDOW_MS if you need a longer/shorter double reset detection window.
*/
#include <Keyboard.h>
#include <EEPROM.h>
// --- Passwords ---
const char PASSWORD1[] = "PasswordOnePress!";
const char PASSWORD2[] = "PasswordTwoPresses!";
// --- LED pins ---
const int LED_SINGLE = 13; // feedback for PASSWORD1
const int LED_DOUBLE = 8; // feedback for PASSWORD2
// --- EEPROM ---
const int COUNT_ADDR = 0; // counter of resets
// --- Timing ---
const unsigned long WINDOW_MS = 4000; // max time window for multiple resets
const unsigned long HOST_DETECT_MS = 2000; // delay before typing
void clearEEPROM() {
for (int i = 0; i < EEPROM.length(); i++) {
EEPROM.write(i, 0);
}
// Blink both LEDs to confirm
for (int i = 0; i < 6; i++) {
digitalWrite(LED_SINGLE, HIGH);
digitalWrite(LED_DOUBLE, HIGH);
delay(200);
digitalWrite(LED_SINGLE, LOW);
digitalWrite(LED_DOUBLE, LOW);
delay(200);
}
}
void setup() {
pinMode(LED_SINGLE, OUTPUT);
pinMode(LED_DOUBLE, OUTPUT);
digitalWrite(LED_SINGLE, LOW);
digitalWrite(LED_DOUBLE, LOW);
// Read counter
byte cnt = EEPROM.read(COUNT_ADDR);
if (cnt == 255) cnt = 0; // safeguard
// Increment counter on each reset
cnt++;
EEPROM.write(COUNT_ADDR, cnt);
// Wait for possible more resets
unsigned long start = millis();
while (millis() - start < WINDOW_MS) {
delay(50);
// If reset happens here, MCU restarts and counter increments again
}
// Final count
byte finalCnt = EEPROM.read(COUNT_ADDR);
if (finalCnt == 1) {
// Single reset → PASSWORD1
delay(HOST_DETECT_MS);
Keyboard.begin();
digitalWrite(LED_SINGLE, HIGH);
Keyboard.print(PASSWORD1);
Keyboard.write(KEY_RETURN);
Keyboard.end();
digitalWrite(LED_SINGLE, LOW);
}
else if (finalCnt == 2) {
// Double reset → PASSWORD2
delay(HOST_DETECT_MS);
Keyboard.begin();
digitalWrite(LED_DOUBLE, HIGH);
Keyboard.print(PASSWORD2);
Keyboard.write(KEY_RETURN);
Keyboard.end();
digitalWrite(LED_DOUBLE, LOW);
}
else if (finalCnt >= 3) {
// Triple reset or more → clear EEPROM
clearEEPROM();
return; // stop here
}
// Reset counter for next time
EEPROM.write(COUNT_ADDR, 0);
}
void loop() {
// nothing
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment