Compare commits
10 Commits
880916166b
...
a6a4c1a6cc
Author | SHA1 | Date |
---|---|---|
King Kévin | a6a4c1a6cc | |
King Kévin | ca87f6cd63 | |
King Kévin | 35aef360cf | |
King Kévin | bb15bbda72 | |
King Kévin | 47528d2b7e | |
King Kévin | 5adb4421ef | |
King Kévin | dcf4dedd2b | |
King Kévin | 0c9ae4bbfd | |
King Kévin | 16af15e47d | |
King Kévin | d17bc7b3a4 |
91
README.rst
91
README.rst
|
@ -4,28 +4,28 @@ purpose
|
|||
=======
|
||||
|
||||
passkey is a USB dongle to paste credentials.
|
||||
It appears a serial port to enter the credentials, and HID keyboard to paste them.
|
||||
It appears as a serial port to enter the credentials, and HID keyboard to paste them.
|
||||
|
||||
Usage:
|
||||
|
||||
- insert the passkey dongle in the USB port, buttons facing up
|
||||
- insert the passkey dongle in the USB port, with "passkey" text facing up
|
||||
- it will appear as serial port to enter the credentials, and HID keyboard to paste them
|
||||
- the red light will blink, indicating it no credentials have been entered yet
|
||||
- connect to it using your favorite serial terminal (e.g. [putty](https://putty.org/) or [picocom](https://github.com/npat-efault/picocom)) using any baud rate
|
||||
- the red light will blink, indicating no credentials have been entered yet
|
||||
- connect to it using your favourite serial terminal (e.g. [putty](https://putty.org/) or [picocom](https://github.com/npat-efault/picocom)) using any baud rate
|
||||
- press 'c' to enter your credentials to paste (username and password)
|
||||
- the light will remain on
|
||||
- press one button of the dongle for it to just paste the password
|
||||
- press the other button to paste the username and password (tab separated)
|
||||
|
||||
You can configure it over the serial terminal:
|
||||
You can configure passkey over the serial terminal:
|
||||
|
||||
- press 'h' to list all available options
|
||||
- press 'b' to swap the button, changing which is for the password or username and password
|
||||
- press 'l' to set using keyboard layout should be used: use the same are configured in your OS, else the pasted credentials might not be exactly the ones you entered
|
||||
- press 'b' to swap the buttons, changing which is for the password or username and password
|
||||
- press 'l' to set which keyboard layout should be used: use the same are configured in your OS, else some letter in the pasted credentials might be different
|
||||
- by default the credentials will be cleared 12 hours after they have been entered. Press 'g' to change this time, up to 12 hours
|
||||
- by default the credentials will be cleared 3 hours after the last time they have been pasted. Press 'r' to change this time, up to 3 hours
|
||||
- press 'a' to authenticate the device. Enter a random word, and it will provide a corresponding result. Copy the provided text to the [homepage](https://passkey.cuvoodoo.info/). If the response is the same, the device is running the original firmware.
|
||||
- press 'k' to enter your own key, which you need to remember. You can then authenticate the device locally (without using the homepage), using any SHA256 calculator.
|
||||
- press 'a' to authenticate the device. Enter a random word, and it will provide an URL and a corresponding result. Click on the link, and if the response is the same, the device is running the original firmware.
|
||||
- press 'k' to enter your own key, which you need to remember. You can then authenticate the device locally (without using the link), using any SHA256 calculator.
|
||||
|
||||
security
|
||||
========
|
||||
|
@ -43,45 +43,61 @@ You can clear the credentials by:
|
|||
|
||||
- unplugging the dongle
|
||||
- pressing both buttons at the same time
|
||||
- pressing 4 times CapsLock within 2 seconds on your keyboard
|
||||
- pressing 4 times NumLock within 2 seconds on your keyboard
|
||||
- pressing 4 times CapsLock or NumLock within 2 seconds on your keyboard
|
||||
|
||||
The credentials will be cleared up to 12 hours after they have been entered.
|
||||
The credentials will be cleared up to 3 hours after the last time they have been pasted.
|
||||
This decreases the risk of having them leaked if the device is left unattended for too long.
|
||||
This decreases the risk of having them leaked if the dongle is left unattended for too long.
|
||||
These timeouts can be configured over the serial port.
|
||||
|
||||
The dongle is locked after been programmed.
|
||||
The dongle can be locked after been programmed.
|
||||
This prevents from:
|
||||
|
||||
- using the SWD interface to attach a debugger on the test point and dump the credentials from the running system
|
||||
- using the SWD interface to attach a debugger on the test points and dump the credentials from the running system
|
||||
- using the bootloader to flash a new malicious firmware (e.g. that could store the credentials on non-volatile memory and reveal them later)
|
||||
- mass erase the device, to re-enable debugging and flashing
|
||||
|
||||
The flash memory is also write protected.
|
||||
Only the last 4 kB of flash are re-writable, as the are used to store the configuration set over serial.
|
||||
The makes it very hard from exploiting the runtime firmware and overwrite.
|
||||
The flash memory can also write protected.
|
||||
Only the last 4 kB of flash are re-writable, as they are used to store the configuration set over serial.
|
||||
This makes it very hard from exploiting the runtime firmware and overwriting it.
|
||||
|
||||
To verify if the firmware is original, use the authentication menu.
|
||||
If you get the passkey from CuVoodoo, you will also has received it's ID per email.
|
||||
This ID should the prefix of the authentication token.
|
||||
Each device has been programmed with an individual key before being locked.
|
||||
Matching the result with the website ensures the key is the same.
|
||||
To avoid using the website, you can set a user key, and perform the authentication locally using any SHA256 calculator.
|
||||
|
||||
risks
|
||||
-----
|
||||
|
||||
The [STM32F042F6P](https://www.st.com/en/microcontrollers-microprocessors/stm32f042f6.html) micro-controller does not have security certifications.
|
||||
If the device locking mechanism can be circumvented (e.g. using fault injection), a malicious firmware could be installed.
|
||||
Because of that, it is not recommended to leave the dongle unattended.
|
||||
It has a hole to pass a string through and attach it to a key-chain you keep with you.
|
||||
This string also allows to easily unplug the device from the computer.
|
||||
It is also recommend to draw on the back of the device, so it becomes unique and hard to tamper with unnoticed.
|
||||
It is also recommended to draw on the back of the device, so it becomes unique and hard to tamper with unnoticed.
|
||||
|
||||
Obermaier and Tatschner [showed in 20179(https://www.usenix.org/system/files/conference/woot17/woot17-paper-obermaier.pdf) how to degrade the readout protection.
|
||||
This involved decapsulating the chip, which would make it easy to see that the device has been tampered with once you added a drawing onto it.
|
||||
Other side channel or fault injection attacks could exist to retrieve the key in a less destructive way.
|
||||
Since the passkey is inexpensive, just toss it away and get a new one if you suspect it has been tampered with.
|
||||
The other possibility would be for and attacker to intercept the device on the shipping way, extract the ID and corresponding manufacturer key, and programming them on a new chip, along with a malicious firmware.
|
||||
This malicious device could still pass authentication.
|
||||
To prevent this attack, you can manufacturer the passkey yourself.
|
||||
The board design files and firmware source code are open and available.
|
||||
The bill of material in around $2, and the parts can be hand soldered with little experience.
|
||||
|
||||
firmware
|
||||
========
|
||||
|
||||
The devices is based on a [STM32F042F6P](https://www.st.com/en/microcontrollers-microprocessors/stm32f042f6.html) micro-controller.
|
||||
The firmware uses [TinyUSB](https://github.com/hathach/tinyusb).
|
||||
The device comes locked, preventing it to be re-flashed.
|
||||
I connected a DAPlink programmer to flash it, using the SWD test points on the back.
|
||||
To compile and flash it:
|
||||
The firmware uses the [TinyUSB](https://github.com/hathach/tinyusb) USB stack.
|
||||
|
||||
If you got the passkey from CuVoodoo, it comes configured with a manufacturer key and locked.
|
||||
You can also request for a blank devices, and manufacturer it and flash the firmware yourself.
|
||||
|
||||
To compile the firmware, you will need and ARM GCC toolchain and run these commands:
|
||||
|
||||
~~~
|
||||
git clone https://git.cuvoodoo.info/kingkevin/passkey_fw
|
||||
|
@ -90,5 +106,34 @@ git checkout passkey
|
|||
cd examples/device/hid_cdc_passkey
|
||||
make BOARD=stm32f042passkey get-deps
|
||||
make BOARD=stm32f042passkey
|
||||
make flash
|
||||
~~~
|
||||
|
||||
When no firmware has been programmed on the passkey, the STM32 bootloader will allow to flash the firmware over USB using dfu-util:
|
||||
|
||||
~~~
|
||||
make dfu
|
||||
~~~
|
||||
|
||||
Re-plug the dongle in the USB port and the passkey will boot the flashed firmware.
|
||||
|
||||
Using the serial terminal you can then enter the manufacturer key by pressing 'K'.
|
||||
Finally, you can lock the firmware by pressing 'L'.
|
||||
This it not revocable.
|
||||
Once locked, you can re-flash the device, change de manufacturer key, or debug the device.
|
||||
|
||||
Before it is locked, you can erase the firmware using 'E'.
|
||||
Re-plugging the dongle will start the bootloader again, allowing to re-flash a firmware.
|
||||
You can also connect an SWD programmer, such as a DAPlink, on the test points.
|
||||
The pinout is a follow:
|
||||
|
||||
- G: ground
|
||||
- C: SWCLK
|
||||
- D: SWDIO
|
||||
- T: the UART TX used to print debug messages
|
||||
|
||||
You can then flash and debug the firmware.
|
||||
|
||||
~~~
|
||||
make flash
|
||||
make debug
|
||||
~~~
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
/** build year as number */
|
||||
#define COMPUTE_BUILD_YEAR \
|
||||
( \
|
||||
(__DATE__[ 7] - '0') * 1000 + \
|
||||
(__DATE__[ 8] - '0') * 100 + \
|
||||
(__DATE__[ 9] - '0') * 10 + \
|
||||
(__DATE__[10] - '0') \
|
||||
)
|
||||
/** build day as number */
|
||||
#define COMPUTE_BUILD_DAY \
|
||||
( \
|
||||
((__DATE__[4] >= '0') ? (__DATE__[4] - '0') * 10 : 0) + \
|
||||
(__DATE__[5] - '0') \
|
||||
)
|
||||
/** check if build month is January */
|
||||
#define BUILD_MONTH_IS_JAN (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n')
|
||||
/** check if build month is February */
|
||||
#define BUILD_MONTH_IS_FEB (__DATE__[0] == 'F')
|
||||
/** check if build month is March */
|
||||
#define BUILD_MONTH_IS_MAR (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r')
|
||||
/** check if build month is April */
|
||||
#define BUILD_MONTH_IS_APR (__DATE__[0] == 'A' && __DATE__[1] == 'p')
|
||||
/** check if build month is May */
|
||||
#define BUILD_MONTH_IS_MAY (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y')
|
||||
/** check if build month is June */
|
||||
#define BUILD_MONTH_IS_JUN (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n')
|
||||
/** check if build month is July */
|
||||
#define BUILD_MONTH_IS_JUL (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l')
|
||||
/** check if build month is August */
|
||||
#define BUILD_MONTH_IS_AUG (__DATE__[0] == 'A' && __DATE__[1] == 'u')
|
||||
/** check if build month is September */
|
||||
#define BUILD_MONTH_IS_SEP (__DATE__[0] == 'S')
|
||||
/** check if build month is October */
|
||||
#define BUILD_MONTH_IS_OCT (__DATE__[0] == 'O')
|
||||
/** check if build month is November */
|
||||
#define BUILD_MONTH_IS_NOV (__DATE__[0] == 'N')
|
||||
/** check if build month is December */
|
||||
#define BUILD_MONTH_IS_DEC (__DATE__[0] == 'D')
|
||||
/** build month as number */
|
||||
#define COMPUTE_BUILD_MONTH \
|
||||
( \
|
||||
(BUILD_MONTH_IS_JAN) ? 1 : \
|
||||
(BUILD_MONTH_IS_FEB) ? 2 : \
|
||||
(BUILD_MONTH_IS_MAR) ? 3 : \
|
||||
(BUILD_MONTH_IS_APR) ? 4 : \
|
||||
(BUILD_MONTH_IS_MAY) ? 5 : \
|
||||
(BUILD_MONTH_IS_JUN) ? 6 : \
|
||||
(BUILD_MONTH_IS_JUL) ? 7 : \
|
||||
(BUILD_MONTH_IS_AUG) ? 8 : \
|
||||
(BUILD_MONTH_IS_SEP) ? 9 : \
|
||||
(BUILD_MONTH_IS_OCT) ? 10 : \
|
||||
(BUILD_MONTH_IS_NOV) ? 11 : \
|
||||
(BUILD_MONTH_IS_DEC) ? 12 : \
|
||||
/* error default */ 99 \
|
||||
)
|
||||
/** check if build date is unknown */
|
||||
#define BUILD_DATE_IS_BAD (__DATE__[0] == '?')
|
||||
/** build year as number if known, or 0 if unknown */
|
||||
#define BUILD_YEAR ((BUILD_DATE_IS_BAD) ? 0 : COMPUTE_BUILD_YEAR)
|
||||
/** build month as number if known, or 0 if unknown */
|
||||
#define BUILD_MONTH ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_MONTH)
|
||||
/** build day as number if known, or 0 if unknown */
|
||||
#define BUILD_DAY ((BUILD_DATE_IS_BAD) ? 99 : COMPUTE_BUILD_DAY)
|
|
@ -13,6 +13,7 @@
|
|||
#include "usb_descriptors.h"
|
||||
#include "keylayouts.h"
|
||||
#include "WjCryptLib_Sha256.h"
|
||||
#include "date.h"
|
||||
|
||||
// get the length of an array
|
||||
#define LENGTH(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
@ -76,6 +77,12 @@ static const char* help_str[] = {
|
|||
"l set keyboard layout\r\n",
|
||||
};
|
||||
|
||||
static const char* prog_str[] = {
|
||||
"K set manufacturer key\r\n",
|
||||
"L lock device\r\n",
|
||||
"E erase firmware\r\n",
|
||||
};
|
||||
|
||||
enum {
|
||||
MENU_HOME,
|
||||
MENU_USER,
|
||||
|
@ -115,6 +122,13 @@ uint32_t board_button2_read(void)
|
|||
return BUTTON2_STATE_ACTIVE == HAL_GPIO_ReadPin(BUTTON2_PORT, BUTTON2_PIN);
|
||||
}
|
||||
|
||||
static bool locked(void)
|
||||
{
|
||||
FLASH_OBProgramInitTypeDef ob;
|
||||
HAL_FLASHEx_OBGetConfig(&ob);
|
||||
return (OB_RDP_LEVEL_2 == ob.RDPLevel);
|
||||
}
|
||||
|
||||
static void clear_credentials(void)
|
||||
{
|
||||
// clear credentials
|
||||
|
@ -139,7 +153,7 @@ static void load_config(void)
|
|||
if (!manuf_ok) {
|
||||
memset(manuf_key, 0, sizeof(manuf_key));
|
||||
}
|
||||
|
||||
|
||||
memcpy(&config, (uint8_t*)FLASH_CONFIG_ADDR, sizeof(config));
|
||||
uint8_t crc = 0x42; // start with non-zero value to have a checksum work with empty config
|
||||
for (uint16_t i = 0; i < sizeof(config); i++) {
|
||||
|
@ -266,7 +280,9 @@ int main(void)
|
|||
// init device stack on configured roothub port
|
||||
tud_init(BOARD_TUD_RHPORT);
|
||||
|
||||
printf("\r\npasskey v2\r\n");
|
||||
printf("\r\npasskey\r\n");
|
||||
printf("hardware version: 2\r\n"); // for now we just have version 2
|
||||
printf("firmware date: %04u-%02u-%02u\r\n", BUILD_YEAR, BUILD_MONTH, BUILD_DAY); // show firmware build date
|
||||
load_config();
|
||||
|
||||
FLASH_OBProgramInitTypeDef ob;
|
||||
|
@ -368,7 +384,7 @@ void cdc_task(void)
|
|||
case 'c': // input credentials
|
||||
i = 0; // reset index
|
||||
menu = MENU_USER; // go to corresponding menu
|
||||
str = "\r\nusername: ";
|
||||
str = "\r\nenter credentials to paste\r\nusername: ";
|
||||
break;
|
||||
case 'b': // swap buttons
|
||||
config.button_swap = !config.button_swap;
|
||||
|
@ -402,50 +418,55 @@ void cdc_task(void)
|
|||
}
|
||||
break;
|
||||
case 'l': // set keyboard layout
|
||||
tud_cdc_write(buf, 1); // since echo will be off
|
||||
tud_cdc_write_flush();
|
||||
echo = false;
|
||||
tud_cdc_write(buf, 1); // since echo will be off
|
||||
tud_cdc_write_str("\n\r");
|
||||
tud_cdc_write_flush();
|
||||
for (uint8_t j = 0; j < LENGTH(name_asciimap); j++) {
|
||||
snprintf(tmp, sizeof(tmp), "%02u %s\r\n", j, name_asciimap[j]);
|
||||
tud_cdc_write_str_flush(tmp);
|
||||
}
|
||||
snprintf(tmp, sizeof(tmp), "\r\nset keyboard layout [%s]: ", name_asciimap[config.layout]);
|
||||
snprintf(tmp, sizeof(tmp), "set keyboard layout [%s]: ", name_asciimap[config.layout]);
|
||||
tud_cdc_write_str_flush(tmp);
|
||||
i = 0; // reset index
|
||||
menu = MENU_LAYOUT;
|
||||
break;
|
||||
// hidden menu
|
||||
case 'K': // set manufacturer key
|
||||
{
|
||||
FLASH_OBProgramInitTypeDef ob;
|
||||
HAL_FLASHEx_OBGetConfig(&ob);
|
||||
if (OB_RDP_LEVEL_2 == ob.RDPLevel) {
|
||||
str = "\r\ndevice locked\r\n";
|
||||
} else {
|
||||
i = 0; // reset index
|
||||
menu = MENU_MANUF;
|
||||
str = "\r\nenter manufacturer key (up to 32 char): ";
|
||||
}
|
||||
if (!locked()) {
|
||||
i = 0; // reset index
|
||||
menu = MENU_MANUF;
|
||||
str = "\r\nenter manufacturer key (up to 32 char): ";
|
||||
}
|
||||
break;
|
||||
case 'L': // lock device
|
||||
{
|
||||
if (!locked()) {
|
||||
tud_cdc_write_str_flush("\r\nlocking device\r\n");
|
||||
FLASH_OBProgramInitTypeDef ob;
|
||||
HAL_FLASHEx_OBGetConfig(&ob);
|
||||
if (OB_RDP_LEVEL_2 == ob.RDPLevel) {
|
||||
str = "\r\ndevice locked\r\n";
|
||||
} else {
|
||||
str = "\r\nlocking device\r\n";
|
||||
ob.RDPLevel = OB_RDP_LEVEL_2; // level 2, disabling debug, and write protecting option byte
|
||||
ob.WRPState = OB_WRPSTATE_ENABLE; // write protect pages
|
||||
ob.WRPPage = 0x7; // all but last sector holding the config
|
||||
HAL_FLASH_Unlock();
|
||||
HAL_FLASH_OB_Unlock();
|
||||
//HAL_FLASHEx_OBProgram(&ob);
|
||||
HAL_FLASH_OB_Lock();
|
||||
HAL_FLASH_Lock();
|
||||
HAL_FLASH_OB_Launch();
|
||||
ob.RDPLevel = OB_RDP_LEVEL_2; // level 2, disabling debug, and write protecting option byte
|
||||
ob.WRPState = OB_WRPSTATE_ENABLE; // write protect pages
|
||||
ob.WRPPage = 0x7; // all but last sector holding the config
|
||||
HAL_FLASH_Unlock();
|
||||
HAL_FLASH_OB_Unlock();
|
||||
//HAL_FLASHEx_OBProgram(&ob);
|
||||
HAL_FLASH_OB_Lock();
|
||||
HAL_FLASH_Lock();
|
||||
HAL_FLASH_OB_Launch();
|
||||
}
|
||||
break;
|
||||
case 'E': // mass erase to restart STM32 bootloader
|
||||
if (!locked()) {
|
||||
tud_cdc_write_str_flush("\r\nerasing firmware\r\n");
|
||||
HAL_FLASH_Unlock();
|
||||
FLASH_EraseInitTypeDef EraseInitStruct;
|
||||
EraseInitStruct.TypeErase = FLASH_TYPEERASE_MASSERASE;
|
||||
uint32_t error;
|
||||
if (HAL_FLASHEx_Erase(&EraseInitStruct, &error) != HAL_OK) {
|
||||
printf("mass erase failed\r\n");
|
||||
}
|
||||
HAL_FLASH_Lock();
|
||||
HAL_FLASH_OB_Launch(); // just to restart
|
||||
}
|
||||
break;
|
||||
case '\r':
|
||||
|
@ -459,6 +480,11 @@ void cdc_task(void)
|
|||
for (uint8_t j = 0; j < LENGTH(help_str); j++) {
|
||||
tud_cdc_write_str_flush(help_str[j]);
|
||||
}
|
||||
if (!locked()) {
|
||||
for (uint8_t j = 0; j < LENGTH(prog_str); j++) {
|
||||
tud_cdc_write_str_flush(prog_str[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MENU_USER:
|
||||
|
@ -714,33 +740,41 @@ void tud_cdc_rx_cb(uint8_t itf)
|
|||
//--------------------------------------------------------------------+
|
||||
// USB HID
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static void send_hid_report(char c)
|
||||
static void send_hid_report(uint8_t modifier, uint8_t keycode)
|
||||
{
|
||||
// skip if hid is not ready yet
|
||||
if ( !tud_hid_ready() ) {
|
||||
return;
|
||||
}
|
||||
// ensure it's a printable ASCII
|
||||
if (0 != c && c < ' ') {
|
||||
return;
|
||||
|
||||
uint8_t keycodes[6] = {keycode, 0, 0, 0, 0, 0};
|
||||
if (keycode) {
|
||||
key_when = board_millis(); // remember when we sent the key
|
||||
key_pressed = true; // remember we pressed a key
|
||||
} else {
|
||||
key_pressed = false; // key released
|
||||
}
|
||||
tud_hid_keyboard_report(REPORT_ID_KEYBOARD, modifier, keycodes);
|
||||
}
|
||||
|
||||
static void send_hid_char(char c)
|
||||
{
|
||||
// set default to US
|
||||
if (config.layout >= LENGTH(map_asciimap)) {
|
||||
config.layout = 0;
|
||||
}
|
||||
|
||||
uint8_t keycode[6] = {0, 0, 0, 0, 0, 0};
|
||||
if (c) {
|
||||
if (0 == c) {
|
||||
send_hid_report(0, 0);
|
||||
} else if ('\t' == c) {
|
||||
send_hid_report(0, KEY_TAB);
|
||||
} else if ('\r' == c || '\n' == c) {
|
||||
send_hid_report(0, KEY_ENTER);
|
||||
} else if (c >= ' ' && c <= '~') {
|
||||
const uint16_t code = map_asciimap[config.layout][c - ' '];
|
||||
const uint8_t modifier = code >> 8;
|
||||
keycode[0] = code & 0xff;
|
||||
tud_hid_keyboard_report(REPORT_ID_KEYBOARD, modifier, keycode);
|
||||
key_when = board_millis(); // remember when we sent the key
|
||||
key_pressed = true; // remember we pressed a key
|
||||
} else {
|
||||
tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, keycode); // release press
|
||||
key_pressed = false;
|
||||
const uint8_t keycode = code & 0xff;
|
||||
send_hid_report(modifier, keycode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -757,10 +791,10 @@ void hid_task(void)
|
|||
return;
|
||||
}
|
||||
if (pass_paste) { // send password
|
||||
if (pass_paste < strlen(username)) { // send password
|
||||
send_hid_report(password[pass_paste++]);
|
||||
if (pass_paste < strlen(password)) { // send password
|
||||
send_hid_char(password[pass_paste++]);
|
||||
} else if (pass_paste == strlen(password)) { // press enter
|
||||
send_hid_report('\n');
|
||||
send_hid_char('\n');
|
||||
pass_paste++;
|
||||
} else if (pass_paste == (strlen(password) + 1)) { // finished pasting
|
||||
user_paste = 0;
|
||||
|
@ -770,13 +804,13 @@ void hid_task(void)
|
|||
}
|
||||
if (user_paste) { // send username
|
||||
if (user_paste < strlen(username)) { // send username
|
||||
send_hid_report(username[user_paste++]);
|
||||
send_hid_char(username[user_paste++]);
|
||||
} else if (user_paste == strlen(username)) { // switch to password
|
||||
send_hid_report('\t');
|
||||
send_hid_char('\t');
|
||||
user_paste++;
|
||||
} else if (user_paste == (strlen(username) + 1)) { // start sending password
|
||||
pass_paste = 0;
|
||||
send_hid_report(password[pass_paste++]);
|
||||
send_hid_char(password[pass_paste++]);
|
||||
user_paste++;
|
||||
}
|
||||
}
|
||||
|
@ -795,17 +829,17 @@ static void paste_credentials(bool user)
|
|||
pasted_when = board_millis();
|
||||
|
||||
if (user) {
|
||||
send_hid_report(username[user_paste++]);
|
||||
send_hid_char(username[user_paste++]);
|
||||
printf("pasting username and password\r\n");
|
||||
} else {
|
||||
send_hid_report(password[pass_paste++]);
|
||||
send_hid_char(password[pass_paste++]);
|
||||
printf("pasting password\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void button_task(void)
|
||||
{
|
||||
static uint32_t button1_ms = 0; // when the button has been pressed (in ms)
|
||||
static uint32_t button1_ms = 0; // when the button has been pressed (in ms)
|
||||
static bool button1_ok = false; // if the button is pressed (after debounce)
|
||||
static uint32_t button2_ms = 0; // when the button has been pressed (in ms)
|
||||
static bool button2_ok = false; // if the button is pressed (after debounce)
|
||||
|
@ -887,7 +921,7 @@ void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_
|
|||
|
||||
if ((report[0] == REPORT_ID_KEYBOARD) && key_pressed) {
|
||||
//tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, NULL); // release press
|
||||
send_hid_report(0); // release key
|
||||
send_hid_report(0, 0); // release key
|
||||
//return;
|
||||
}
|
||||
}
|
||||
|
@ -915,7 +949,7 @@ void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_
|
|||
static uint8_t kbd_leds_last = 0; // last state
|
||||
static uint32_t kbd_leds_when = 0; // when did the state change
|
||||
static uint8_t kbd_leds_count = 0; // how many times it changed (within a certain period)
|
||||
|
||||
|
||||
if (report_type == HID_REPORT_TYPE_OUTPUT) {
|
||||
// Set keyboard LED e.g Capslock, Numlock etc...
|
||||
if (report_id == REPORT_ID_KEYBOARD) {
|
||||
|
|
|
@ -23,3 +23,6 @@ flash: $(BUILD)/$(PROJECT).elf
|
|||
|
||||
debug: $(BUILD)/$(PROJECT).elf
|
||||
$(GDB) --eval-command='target remote | $(OOCD) --file interface/$(OOCD_INTERFACE).cfg --command "transport select swd" --file target/$(OOCD_TARGET).cfg --command "gdb_port pipe; log_output /dev/null; init"' $<
|
||||
|
||||
dfu: $(BUILD)/$(PROJECT).bin
|
||||
dfu-util --device 0483:df11 --cfg 1 --intf 0 --alt 0 --detach --dfuse-address 0x08000000 --download $<
|
||||
|
|
Loading…
Reference in New Issue