Крутой менеджер паролей своими руками на Arduino Pro Micro Atmega32u4 с защитой от кражи.

Здравствуйте!

Эта статья является инструкцией, для изготовления самодельного менеджера паролей. В который можно загружать до 25 аккаунтов. Для безопасности данных пришлось добавить четырехзначный пароль, для доступа к списку аккаунтов, а также двухступенчатый таймер, на тот случай если будет введен неверный пароль.

 Arduino PRO Micro 32u4

Для проекта использую:

Плату Arduino Pro Micro, на базе микроконтроллера ATmega32U4, OLED I2C дисплей 128х32 пикселя, макетная плата, и 3 кнопки.

Я собирал по этой схеме.

Arduino ProMicro  I2C display 128х32

После чего необходимо загрузить этот скетч на плату, предварительно настроив его, как показано в видео инструкции, которая расположена ниже под скетчем.


//Начало скетча


#include <Keyboard.h>
#include "EEPROM.h"
#include <Adafruit_SSD1306.h>
#define SSD1306_DISPLAYOFF 0xAE
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32

#define OLED_RESET     4 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int  pas_1 = 2;     // 1 цифра пароля (от 0 до 9)
const int  pas_2 = 9;     // 2 цифра пароля (от 0 до 9)
const int  pas_3 = 7;     // 3 цифра пароля (от 0 до 9)
const int  pas_4 = 1;     // 4 цифра пароля (от 0 до 9)

const int  pin_OK = 6;    //пин кнопки подтверждения
const int  pin_UP = 7;    //пин кнопки вверх
const int  pin_DOWN = 8;  //пин кнопки вниз

int max_account_number = 25; //количество используемых аккаунтов, должно быть меньше или равно 25

typedef struct {  //эта функция делит массив на столбцы
     //сайт______имя польз______логин_________пароль
  char* site; char* name; char* login; char* password;} State;

State arr[25] = {
//сайт,      имя польз,    логин,        пароль
{"site 1",   "name 1",   "login 1",   "password 1"},
{"site 2",   "name 2",   "login 2",   "password 2"},
{"site 3",   "name 3",   "login 3",   "password 3"},
{"site 4",   "name 4",   "login 4",   "password 4"},
{"site 5",   "name 5",   "login 5",   "password 5"},
{"site 6",   "name 6",   "login 6",   "password 6"},
{"site 7",   "name 7",   "login 7",   "password 7"},
{"site 8",   "name 8",   "login 8",   "password 8"},
{"site 9",   "name 9",   "login 9",   "password 9"},
{"site 10",  "name 10",  "login 10",  "password 10"},
{"site 11",  "name 11",  "login 11",  "password 11"},
{"site 12",  "name 12",  "login 12",  "password 12"},
{"site 13",  "name 13",  "login 13",  "password 13"},
{"site 14",  "name 14",  "login 14",  "password 14"},
{"site 15",  "name 15",  "login 15",  "password 15"},
{"site 16",  "name 16",  "login 16",  "password 16"},
{"site 17",  "name 17",  "login 17",  "password 17"},
{"site 18",  "name 18",  "login 18",  "password 18"},
{"site 19",  "name 19",  "login 19",  "password 19"},
{"site 20",  "name 20",  "login 20",  "password 20"},
{"site 21",  "name 21",  "login 21",  "password 21"},
{"site 22",  "name 22",  "login 22",  "password 22"},
{"site 23",  "name 23",  "login 23",  "password 23"},
{"site 24",  "name 24",  "login 24",  "password 24"},
{"site 25",  "name 25",  "login 25",  "password 25"}
};

int pas_ST_1 = 0, pas_ST_2 = 0, pas_ST_3 = 0, pas_ST_4 = 0, flag_menu = 60, flag_RES_DISP = 0, msecs = 300;
int pin_OK_st = 0, pin_UP_st = 0, pin_DOWN_st = 0, account_number = 0, flag_RES_ACC = 0, timer = 0;
int address_FLAG = 1, flag_EEPROM = 125, seconds = 0;
int seconds1 = 10, seconds2 = 20;

void pass_menu(){ //функция для меню ввода пароля, вывод на дисплей
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(0,8);
  display.print(F("Pass:"));
  display.setCursor(60,8);
  display.print(pas_ST_1, DEC);
  display.setCursor(73,8); 
  display.print(pas_ST_2, DEC);
  display.setCursor(86,8); 
  display.print(pas_ST_3, DEC);
  display.setCursor(99,8); 
  display.print(pas_ST_4, DEC);
  display.setCursor(flag_menu,26); 
  display.print(F("^"));
}

void scan_buttons(){  //функция сканирование кнопок
  pin_OK_st = digitalRead(pin_OK);
  pin_UP_st = digitalRead(pin_UP);
  pin_DOWN_st = digitalRead(pin_DOWN);
}

void setup() {
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // I2C address 128x32 0x3C,  
    for(;;);
  }
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  pinMode(pin_OK, INPUT_PULLUP);
  pinMode(pin_UP, INPUT_PULLUP);
  pinMode(pin_DOWN, INPUT_PULLUP);
  pass_menu ();
  
  EEPROM.get(address_FLAG, flag_EEPROM); //чтение из EEPROM
  if(flag_EEPROM < 10){
    EEPROM.put(address_FLAG, flag_EEPROM); //запись в EEPROM
  } 
  EEPROM.get(address_FLAG, flag_EEPROM); //чтение из EEPROM
  if(flag_EEPROM == 126){
    flag_menu = 126; seconds = seconds2; }//если флаг = 6, то сначала выводится таймер
}

void loop() {
  scan_buttons(); //сканирование кнопок
  
  //обновление дисплея при изменении значения пароля
  if(flag_RES_DISP == 1){ pass_menu(); flag_RES_DISP = 0;}
  
  if(pin_OK_st == LOW && (flag_menu >= 59 && flag_menu < 100)){ //переход к следующему числу пароля
    flag_menu+=13; if(flag_menu < 100){ flag_RES_DISP = 1;} delay(msecs);}
  
  if(flag_menu == 60){ //выбор 1 числа пароля
    if(pin_UP_st == LOW){  pas_ST_1++; flag_RES_DISP = 1; delay(msecs);}
    if(pin_DOWN_st == LOW){  pas_ST_1--; flag_RES_DISP = 1; delay(msecs);}
    if(pas_ST_1 > 9){ pas_ST_1 = 0;} if(pas_ST_1 < 0){  pas_ST_1 = 9;}
  }
  if(flag_menu == 73){ //выбор 2 числа пароля
    if(pin_UP_st == LOW){  pas_ST_2++; flag_RES_DISP = 1; delay(msecs);}
    if(pin_DOWN_st == LOW){  pas_ST_2--; flag_RES_DISP = 1; delay(msecs);}
    if(pas_ST_2 > 9){ pas_ST_2 = 0;} if(pas_ST_2 < 0){  pas_ST_2 = 9;}
  }
  if(flag_menu == 86){ //выбор 3 числа пароля
    if(pin_UP_st == LOW){  pas_ST_3++; flag_RES_DISP = 1; delay(msecs);}
    if(pin_DOWN_st == LOW){  pas_ST_3--; flag_RES_DISP = 1; delay(msecs);}
    if(pas_ST_3 > 9){ pas_ST_3 = 0;} if(pas_ST_3 < 0){  pas_ST_3 = 9;}
  }
  if(flag_menu == 99){ //выбор 4 числа пароля
    if(pin_UP_st == LOW){  pas_ST_4++; flag_RES_DISP = 1; delay(msecs);}
    if(pin_DOWN_st == LOW){  pas_ST_4--; flag_RES_DISP = 1; delay(msecs);}
    if(pas_ST_4 > 9){ pas_ST_4 = 0;} if(pas_ST_4 < 0){  pas_ST_4 = 9;}
  }
  
  if(flag_menu == 112 && pin_OK_st == LOW){  //подтверждение пароля
    if(pas_ST_1 == pas_1 && pas_ST_2 == pas_2 && pas_ST_3 == pas_3 && pas_ST_4 == pas_4){
      flag_menu = 125; flag_RES_ACC = 1; delay(msecs);
      flag_EEPROM = 125; EEPROM.put(address_FLAG, flag_EEPROM); //восстановление флага
    }else{  
      if(flag_EEPROM == 126){ flag_menu = 126; seconds = seconds2; }  //если 2 попытка не верна
      
      if(flag_EEPROM == 125){ flag_menu = 126; seconds = seconds1;    //если 1 попытка не верна
        flag_EEPROM = 126; EEPROM.put(address_FLAG, flag_EEPROM);}    //изменяем флаг для второй неверной попытки
    }
  }
  
  scan_buttons(); //сканирование кнопок
  
  if(flag_menu == 125){ //выбор сайта и акаунта
    if(pin_UP_st == LOW){  account_number-=1; flag_RES_ACC = 1; delay(msecs);}
    if(pin_DOWN_st == LOW){  account_number+=1; flag_RES_ACC = 1; delay(msecs);}
    if(account_number > max_account_number - 1){  account_number = 0;} 
    if(account_number < 0){ account_number = max_account_number - 1;}
  }
  
  if(flag_menu == 125 && pin_OK_st == LOW){  //печать логина и пароля
    delay(msecs);
    Keyboard.print(arr[account_number].login);
    Keyboard.write(KEY_TAB);
    Keyboard.println(arr[account_number].password);
  }
  
  if(flag_menu == 125 && flag_RES_ACC == 1){  //отображение сайта и акаунта на дисплее
    display.clearDisplay();
    display.setCursor(0,0);
    display.print(arr[account_number].site);
    display.setCursor(0,18);
    display.print(arr[account_number].name);
    flag_RES_ACC = 0;
  }
  
  if(flag_menu == 126){ timer = seconds;      //отображение таймера на дисплее, после ввода неверного пароля
    while(timer > 0){
      display.clearDisplay();
      display.setTextSize(2);
      display.setCursor(5,0);
      display.print(timer, DEC); 
      display.setCursor(5,18);
      display.print(F("seconds"));
      display.display();
      delay(1000); timer--;
      
    }
    flag_menu = 60; flag_RES_DISP = 1; display.clearDisplay();
    pas_ST_1 = 0; pas_ST_2 = 0; pas_ST_3 = 0; pas_ST_4 = 0;
  }   display.display();
}

//Конец скетча




Видео инструкция " Крутой менеджер паролей своими руками на Arduino Pro Micro Atmega32u4 с защитой от кражи."


Крутой менеджер паролей своими руками на Arduino Pro Micro Atmega32u4 с защитой от кражи.



Это скетч, который получился в результате проектирования в симуляторе Arduino UnoArduSim. Можете им воспользоваться, если есть желание протестировать, как это работает в UnoArduSim. О том как это происходило можете посмотреть в видео, которое выше!


//Начало скетча


#include "EEPROM.h"
#include "Adafruit_LiquidCrystal.h"
Adafruit_LiquidCrystal lcd(0);

const int  pas_1 = 0;     // 1 цифра пароля (от 0 до 9)
const int  pas_2 = 0;     // 2 цифра пароля (от 0 до 9)
const int  pas_3 = 0;     // 3 цифра пароля (от 0 до 9)
const int  pas_4 = 0;     // 4 цифра пароля (от 0 до 9)

const int  pin_OK = 2;    //пин кнопки подтверждения
const int  pin_UP = 3;    //пин кнопки вверх
const int  pin_DOWN = 4;  //пин кнопки вниз

int max_account_number = 10; //количество используемых аккаунтов, должно быть меньше или равно 10

typedef struct { //эта функция делит массив на стобцы
     //сайт______имя польз______логин_________пароль
  char* site; char* name; char* login; char* password;} State;

State arr[10] = {
//сайт,    имя польз,    логин,       пароль
{"site 1",  "name 1",  "login 1",  "password 1"},
{"site 2",  "name 2",  "login 2",  "password 2"},
{"site 3",  "name 3",  "login 3",  "password 3"},
{"site 4",  "name 4",  "login 4",  "password 4"},
{"site 5",  "name 5",  "login 5",  "password 5"},
{"site 6",  "name 6",  "login 6",  "password 6"},
{"site 7",  "name 7",  "login 7",  "password 7"},
{"site 8",  "name 8",  "login 8",  "password 8"},
{"site 9",  "name 9",  "login 9",  "password 9"},
{"site 10", "name 10", "login 10", "password 10"}
};

int pas_ST_1 = 0, pas_ST_2 = 0, pas_ST_3 = 0, pas_ST_4 = 0, flag_menu = 0, flag_RES_DISP = 0, msecs = 300;
int pin_OK_st = 0, pin_UP_st = 0, pin_DOWN_st = 0, account_number = 0, flag_RES_ACC = 0, timer = 0;
int address_FLAG = 1, flag_EEPROM = 5, seconds = 0;
int seconds1 = 5, seconds2 = 10;

void pass_menu(){ //функция для меню ввода пароля, вывод на дисплей
  lcd.setCursor(0,0);
  lcd.print("Pass:");
  lcd.setCursor(6,0);
  lcd.print(pas_ST_1);
  lcd.setCursor(7,0); 
  lcd.print(pas_ST_2);
  lcd.setCursor(8,0); 
  lcd.print(pas_ST_3);
  lcd.setCursor(9,0); 
  lcd.print(pas_ST_4);
  lcd.setCursor(5 + flag_menu,1); 
  lcd.print(" ^");
}

void scan_buttons(){  //функция сканирование кнопок
  pin_OK_st = digitalRead(pin_OK);
  pin_UP_st = digitalRead(pin_UP);
  pin_DOWN_st = digitalRead(pin_DOWN);
}

void setup() {
  lcd.begin(20, 4);
  lcd.setBacklight(HIGH);
  Serial.begin(9600);
  
  pinMode(pin_OK, INPUT_PULLUP);
  pinMode(pin_UP, INPUT_PULLUP);
  pinMode(pin_DOWN, INPUT_PULLUP);
  pass_menu ();
  
  EEPROM.get(address_FLAG, flag_EEPROM); //чтение из EEPROM
  if(flag_EEPROM < 2){
    EEPROM.put(address_FLAG, flag_EEPROM); //запись в EEPROM
  } 
  EEPROM.get(address_FLAG, flag_EEPROM); //чтение из EEPROM
  if(flag_EEPROM == 6){
    flag_menu = 6; seconds = seconds2; }//если флаг = 6, то сначала выводится таймер
}

void loop() {
  scan_buttons(); //сканирование кнопок
  
  //обновление дисплея при изменении значения пароля
  if(flag_RES_DISP == 1){ pass_menu(); flag_RES_DISP = 0;}
  
  if(pin_OK_st == HIGH && (flag_menu >= 0 && flag_menu < 4)){ //переход к следующему числу пароля
    flag_menu++; if(flag_menu < 4){ flag_RES_DISP = 1;} delay(msecs);}
  
  if(flag_menu == 0){ //выбор 1 числа пароля
    if(pin_UP_st == HIGH){  pas_ST_1++; flag_RES_DISP = 1; delay(msecs);}
    if(pin_DOWN_st == HIGH){  pas_ST_1--; flag_RES_DISP = 1; delay(msecs);}
    if(pas_ST_1 > 9){ pas_ST_1 = 0;} if(pas_ST_1 < 0){  pas_ST_1 = 9;}
  }
  if(flag_menu == 1){ //выбор 2 числа пароля
    if(pin_UP_st == HIGH){  pas_ST_2++; flag_RES_DISP = 1; delay(msecs);}
    if(pin_DOWN_st == HIGH){  pas_ST_2--; flag_RES_DISP = 1; delay(msecs);}
    if(pas_ST_2 > 9){ pas_ST_2 = 0;} if(pas_ST_2 < 0){  pas_ST_2 = 9;}
  }
  if(flag_menu == 2){ //выбор 3 числа пароля
    if(pin_UP_st == HIGH){  pas_ST_3++; flag_RES_DISP = 1; delay(msecs);}
    if(pin_DOWN_st == HIGH){  pas_ST_3--; flag_RES_DISP = 1; delay(msecs);}
    if(pas_ST_3 > 9){ pas_ST_3 = 0;} if(pas_ST_3 < 0){  pas_ST_3 = 9;}
  }
  if(flag_menu == 3){ //выбор 4 числа пароля
    if(pin_UP_st == HIGH){  pas_ST_4++; flag_RES_DISP = 1; delay(msecs);}
    if(pin_DOWN_st == HIGH){  pas_ST_4--; flag_RES_DISP = 1; delay(msecs);}
    if(pas_ST_4 > 9){ pas_ST_4 = 0;} if(pas_ST_4 < 0){  pas_ST_4 = 9;}
  }
  
  if(flag_menu == 4 && pin_OK_st == HIGH){  //подтверждение пароля
    if(pas_ST_1 == pas_1 && pas_ST_2 == pas_2 && pas_ST_3 == pas_3 && pas_ST_4 == pas_4){
      flag_menu = 5; flag_RES_ACC = 1; delay(msecs);
      flag_EEPROM = 5; EEPROM.put(address_FLAG, flag_EEPROM); //востановление флага
    }else{  
      if(flag_EEPROM == 6){ flag_menu = 6; seconds = seconds2; }  //если 2 попытка не верна
      
      if(flag_EEPROM == 5){ flag_menu = 6; seconds = seconds1;    //если 1 попытка не верна
        flag_EEPROM = 6; EEPROM.put(address_FLAG, flag_EEPROM);}    //изменяем флаг для второй неверной попытки
    }
  }
  
  scan_buttons(); //сканирование кнопок
  
  if(flag_menu == 5){ //выбор сайта и акаунта
    if(pin_UP_st == HIGH){  account_number-=1; flag_RES_ACC = 1; delay(msecs);}
    if(pin_DOWN_st == HIGH){  account_number+=1; flag_RES_ACC = 1; delay(msecs);}
    if(account_number > max_account_number - 1){  account_number = 0;} 
    if(account_number < 0){ account_number = max_account_number - 1;}
  }
  
  if(flag_menu == 5 && pin_OK_st == HIGH){  //печать логина и пароля
    delay(msecs);
    Serial.print(arr[account_number].login);
    Serial.print(" Tab ");
    Serial.println(arr[account_number].password);
  }
  
  if(flag_menu == 5 && flag_RES_ACC == 1){  //отображение сайта и акаунта на дисплее
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print(arr[account_number].site);
    lcd.setCursor(0,1);
    lcd.print(arr[account_number].name);
    flag_RES_ACC = 0;
  }
  
  if(flag_menu == 6){ timer = seconds;      //отображение таймера на дисплее, после ввода неверного пароля
    while(timer > 0){
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print(timer); lcd.print(" seconds");
      delay(1000); timer--;
    }
    flag_menu = 0; flag_RES_DISP = 1; lcd.clear();
    pas_ST_1 = 0; pas_ST_2 = 0; pas_ST_3 = 0; pas_ST_4 = 0;
  } 
}

//Конец скетча