[DIY] Arduino Password Box: protéger vos mots de passe

arduino-password-box

L’Arduino Password Box est un petit gadget qui vous permet de sauvegarder vos mots de passe de manière totalement sécurisée. Pour moins de 10€ vous allez pouvoir concevoir un véritable périphérique de gestion de mots de passe. L’Arduino Password Box est simple à fabriquer et encore plus simple à utiliser. Ce gadget à base d’Arduino Pro Micro est l’accessoire indispensable pour sécuriser vos données et vos mots de passe. Protéger vos navigations sur Internet pour moins de 10€ est désormais possible grâce au Arduino Password Box !

Pourquoi un Arduino Password Box ?

J’ai décidé de créer le Arduino Password Box pour répondre à un besoin simple: être capable d’avoir l’ensemble de mes mots de passe dans un périphérique totalement sécurisé qui ne peut être déverrouillé que par son propriétaire. Grâce à l’Arduino Password Box, vous n’aurez plus besoin de retenir les mots de passe complexes que vous utilisez pour plusieurs dizaines de sites. Il vous suffit d’utiliser Arduino Password Box pour sécuriser au maximum vos navigations et pour limiter (voir supprimer) le vol de vos mots de passe et l’usurpation de vos comptes Internet.

Présentation de l’Arduino Password Box

Arduino Password Box est né d’un concept simple: utiliser un petit périphérique portatif totalement sécurisé dans lequel seront stockés tous vos mots de passe. Grâce à Arduino Password Box, vous n’avez donc plus besoin de vous souvenir de vos mots de passe puisque chacun de vos mots de passe sera associé à une couleur de votre choix. Il devient donc facile de se souvenir de tous vos mots de passe sans avoir à faire le moindre effort 🙂 Arduino Password Box remplit les formulaires tout seul, vous n’avez donc plus besoin de saisir vos mots de passe. Une simple pression sur un bouton vous permettra d’écrire le mot de passe dans vos formulaires d’authentification, vos pages protégées, vos sites favoris, … Arduino Password Box est accessible à tous et pas cher, il utilise le microcontrôleur Arduino Pro Micro c’est pourquoi sa fabrication ne coûte pas plus de 10€. La fabrication d’un Arduino Password Box est facile et nécessite peu de matériel et de composants électroniques: une led RGB 5mm, 3 boutons et 3 résistances suffisent. Il suffit de 15 minutes pour fabriquer un Arduino Password Box !

Principales caractériques du Arduino Password Box

Arduino Password Box est un outil simple par son utilisation mais puissant par ses fonctionnalités:

  • un concept original: stocker vos mots de passe dans un périphérique portatif
  • petit et transportable: le périphérique utilise un Arduino Pro Micro, ce qui lui assure un format de poche
  • toujours plus de sécurité: Arduino Password Box est protégé par un code à saisir. Vous seul pourrez déverrouiller Arduino Password Box pour l’utiliser
  • un prix attractif: moins de 10€
  • simple à fabriquer: moins de 10 composants électroniques
  • simple à utiliser: 3 boutons et une led RGB multicolore vous permettent de choisir un mot de passe et de le saisir automatiquement dans un champs de saisie ou un formulaire
  • une administration complète via une console série (putty par exemple sous Windows)
  • un générateur de mot de passe permet de générer des passwords complexes
  • Supporte les claviers QWERTY ou les claviers AZERTY
  • Arduino Password Box est évolutif et vous pouvez le faire évoluer à votre guise

Utilisation de l’Arduino Password Box

La grande force du Arduino Password Box est sa simplicité d’utilisation: à chaque mot de passe est associée une couleur, ce qui vous permet de sauver des dizaines de mots de passe sans les retenir. Par exemple, il vous suffit d’associer le mot de passe de votre compte Facebook au bleu foncé, celui de Twitter au bleu clair, celui de Vine au vert, … Il devient alors facile de se souvenir du code couleur associé au thème du site. Voyons dans le détail comment utiliser Arduino Password Box.

1) Débloquage du Arduino Password Box

Arduino Password Box est protégé par une combinaison de touches que vous avez définie. Après avoir branché votre Arduino Password Box sur le port USB de votre ordinateur, la led devient rouge. Tant que l’Arduino Password Box n’est pas déverrouillé, vous ne pourrez pas l’utiliser. Arduino Password Box est donc un périphérique externe sécurisé. Pour déverrouiller l’Arduino Password Box, il suffit de saisir votre code en appuyant sur les 3 boutons. Lorsque vous commencez la saisie de votre code de protection, la led devient orange. Si le code saisie est valide, alors la led clignotte en vert 3 fois avant devenir bleue. Si le code est erroné, la led redevient rouge.

2) Gérer les mots de passe

Pour gérer vos mots de passe, il vous suffit de vous connecter via la connexion Série (Serial) et vous accéderez à l’aide suivante:

***********************
* Password Box by jhd *
* http://www.ZeM.fr   *
***********************
List of available commands: 
* add: add a new password configuration (ex: add Facebook;mypassword;0000FF)
* del: remove a password stored (ex: del 8)
* list: list all passwords defined
* sel: select a password stored (ex: sel 7)
* gen: generate a random password (ex: gen 32)
* load: load configuration from eeprom
* save: save current configuration to eeprom
* erase: erase all data stored: login keys and passwords (use with caution)
* verbose: change verbose output
Il ne vous reste plus qu’à ajouter, supprimer ou bien encore générer des mots de passe.

3) Remplir automatiquement les formulaires

Pour remplir automatiquement les formulaires c’est simple: il suffit de sélectionner la couleur associé au site sur lequel vous êtes, placer votre curseur de souris sur le champs “Mot de Passe” puis de cliquer sur le bouton qui sert à écrire le mot de passe dans le formulaire. Arduino Password Box est simple d’utilisation car il ne dispose que de 3 boutons qui effectuent les actions suivantes (après avoir déverrouiller votre Arduino Password Box):

  • le premier bouton (le plus proche de la led): permet de sélectionner le premier mot de passe
  • le bouton du milieu permet de sélectionner le mot de passe suivant
  • le dernier bouton permet d’envoyer le mot de passe

Voici une vidéo montrant l’utilisation d’un Arduino Password Box:

Schématique de l’Arduino Password Box

La réalisation d’un Arduino Password Box est relativement simple: pas beaucoup de composants et peu d’expérience sont nécessaire pour le fabriquer:

arduino password box

arduino password box

Pour que le schéma de connectique de l’Arduino Password Box soit plus simple à comprendre, nous l’avons modélisé en utilisant un Arduino Leonardo. Pour la réalisation nous avons utilisé un Arduino Pro Micro basé sur le même microcontrôleur.

Code de l’Arduino Password Box

Le code est relativement simple. Il y a tout d’abord un fichier “userPassword.h” dans lequel on définit la structure d’un “userPassword”:

#ifndef userPassword_h
#define userPassword_h
 
#include <WString.h>
 
typedef struct {
  uint8_t r;
  uint8_t g;
  uint8_t b;
  String lbl;
  String pwd;
} userPassword;
 
#endif
  Puis il y a le fichier principal “PasswordBox.ino” dans lequel on va avoir l’ensemble du code de notre Arduino Password Box:  
/**********************************
 * Password Box by jhd             *
 * http://www.ZeM.fr               *
 ***********************************
 * BEFORE LOGIN:
 * -------------
 * RED: not logged
 * RED BLINK: bad login
 * RED BLINK ALWAYS: no passwords defined
 * ORANGE: waiting keypressed for login
 * GREEN BLINK: logged or saving keys finished
 * YELLOW: changing keys for login (after 3 clicks on first button)
 * NO COLOR: Receiving command from Serial
 * OTHER COLOR: password selected, waiting for user action
 ***********************************
 * AFTER LOGIN CLICKS:
 * -------------------
 * Button 0: select first password
 * Button 1: select next password
 * Button 2: send password to keyboard
 **********************************/
#include "userPassword.h"
#include <EEPROM.h>
#include <Entropy.h>
 
#define _EEPROM_LOGIN_OFFSET 0
#define _EEPROM_NBPWD_OFFSET 9
#define _EEPROM_DATA_OFFSET 10
#define _EEPROM_SIZE 1024
#define DEBUG 1
 
#define _PINBT_0 18
#define _PINBT_1 19
#define _PINBT_2 20
 
#define _PINLED_R 6
#define _PINLED_G 9
#define _PINLED_B 10
 
#define _NBKEYSFORLOGIN 6 //number of keys for login (max:10)
#define _MAXPWDTOSTORE 15 //maximum of pwd to store in eeprom
 
#define _SAVEMODE_ALL 0 //to save keylogin and passwords to eeprom
#define _SAVEMODE_LOGIN 1 //to save keylogin to eeprom
#define _SAVEMODE_PWD 2 //to save passwords to eeprom
 
const char passwordChars[] = {
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
  'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
  'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
  'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
  'y', 'z' //last normal as number 62 (idx 61)
};
 
bool VERBOSE = true;
 
userPassword passwords[_MAXPWDTOSTORE];
uint8_t nbPasswords = 0; //number of passwords available
uint8_t loginKeys[_NBKEYSFORLOGIN]; 	//good loginKeys combination
int isLogged = 0; //1 if user is logged
int nbBtStateForChangeLoginKeys = 0; //number of times BtState0 have been pressed - change mode when it hits 3
 
int curIdx = 0; //index position (use for login, current password, changing login keys, ...)
 
uint8_t loginKeysUser[_NBKEYSFORLOGIN]; //user loginKeys combination
 
String dataCmd = ""; //to store command data
 
int btPreviousState0 = LOW;
int btPreviousState1 = LOW;
int btPreviousState2 = LOW;
int btState0;
int btState1;
int btState2;
 
int led_R = 255;
int led_G = 0;
int led_B = 0;
 
//Function setup
void setup(void)
{
  Serial.begin(9600);
 
  Entropy.Initialize();
  while (!Entropy.available());
  randomSeed(Entropy.random());
 
  //Initialize Keyboard Control
  Keyboard.begin();
 
  //Initialize pins
  pinMode(_PINBT_0, INPUT);
  pinMode(_PINBT_1, INPUT);
  pinMode(_PINBT_2, INPUT);
 
  pinMode(_PINLED_R, OUTPUT);
  pinMode(_PINLED_G, OUTPUT);
  pinMode(_PINLED_B, OUTPUT);
 
  //Retrieving eeprom datas
  eepromDataLoad();
 
  //Checking if passwords are defined
  checkPasswords();
 
}
 
//Function loop
void loop(void)
{
 
  //set led color
  setRGB(0, led_R, led_G, led_B);
 
  //get buttons state
  btState0 = digitalRead(_PINBT_0);
  btState1 = digitalRead(_PINBT_1);
  btState2 = digitalRead(_PINBT_2);
 
  //test();
  if (isLogged == 0) {
    checkLogin();
  }
  else if (nbBtStateForChangeLoginKeys == 3) {
    changeLoginKeys();
  }
  else {
    //check if cmd if send to serial //todo a deplacer apres le login
    getCommand();
    if ((dataCmd != "") && (sizeof(dataCmd) > 0)) {
      return;  //exit loop if we are waiting for command
    }
    else {
      checkAction();
    }
  }
 
  //update btPreviousState
  btPreviousState0 = btState0;
  btPreviousState1 = btState1;
  btPreviousState2 = btState2;
}
 
void test() {
  if ((btState0 != btPreviousState0) && (btState0 == HIGH)) {
    Serial.println("bt1");
    setRGB(0, 255, 0, 0);
  }
  else if ((btState1 != btPreviousState1) && (btState1 == HIGH)) {
    Serial.println("bt2");
    setRGB(0, 0, 255, 0);
  }
  else if ((btState2 != btPreviousState2) && (btState2 == HIGH)) {
    Serial.println("bt3");
    setRGB(0, 0, 0, 255);
  }
}
 
//Function to erase eeprom data
void eepromDataErase() {
  if (VERBOSE == 1) {
    Serial.println("[EEPROM] Data Erase started");
  }
  for (int i = 0; i < _EEPROM_SIZE; i++) {
    EEPROM.write(i, 255);
  }
  if (VERBOSE == 1) {
    Serial.println("[EEPROM] Data Erase completed");
  }
}
 
//Function to load eeprom data
void eepromDataLoad() {
  //keys logins
  for (int i = 0; i < _NBKEYSFORLOGIN; i++) {
    uint8_t tmp = EEPROM.read(_EEPROM_LOGIN_OFFSET + i);
    if (tmp == 255) {
      tmp = 0;  //because empty eeprom is 255
    }
    loginKeys[i] = tmp;
  }
 
  //pwd
  nbPasswords = EEPROM.read(_EEPROM_NBPWD_OFFSET);
  if (nbPasswords == 255) {
    nbPasswords = 0;  //because empty eeprom is 255
  }
  int offset = _EEPROM_DATA_OFFSET;
  for (int i = 0; i < nbPasswords; i++) {
    int len_total = (int)EEPROM.read(offset);
    byte b[len_total];
    for (int j = 0; j < len_total; j++) {
      b[j] = EEPROM.read(offset + j);
    }
 
    userPassword upwd;
    int len_lbl = (int)b[1];
    int len_pwd = (int)b[2];
 
    upwd.r = b[3];
    upwd.g = b[4];
    upwd.b = b[5];
 
    int pos = 6;
 
    for (int i = 0; i < len_lbl; i++) {
      upwd.lbl += (char)b[pos];
      pos += 1;
    }
 
    for (int i = 0; i < len_pwd; i++) {
      upwd.pwd += (char)b[pos];
      pos += 1;
    }
 
    passwords[i] = upwd;
    offset += len_total;
  }
  if (VERBOSE == 1) {
    Serial.print("[EEPROM] Data Load finished: ");
 
    if (nbPasswords >= 1) {
      Serial.print(nbPasswords);
      Serial.println(" passwords stored");
    }
    else {
      Serial.println("no password defined");
    }
  }
}
 
//Function to save eeprom data (mode 0: All - mode 1: login - mode 2: pwd)
void eepromDataSave(int mode) {
  //keys logins
  if ((mode == _SAVEMODE_ALL) || (mode == _SAVEMODE_LOGIN)) {
    for (int i = 0; i < _NBKEYSFORLOGIN; i++) {
      EEPROM.write(_EEPROM_LOGIN_OFFSET + i, loginKeys[i]);
    }
  }
 
  //pwd
  if ((mode == _SAVEMODE_ALL) || (mode == _SAVEMODE_PWD)) {
    EEPROM.write(_EEPROM_NBPWD_OFFSET, nbPasswords);
    int offset = _EEPROM_DATA_OFFSET;
    for (int i = 0; i < nbPasswords; i++) {
 
      userPassword upwd = passwords[i];
      int len_lbl = upwd.lbl.length();
      int len_pwd = upwd.pwd.length();
      int len_total = (3 + 3 + len_lbl + len_pwd);
 
      uint8_t ret[len_total]; //header: total_len, len_lbl, len_pwd, r, g, b, lbl, pwd
 
      ret[0] = (uint8_t)len_total;
      ret[1] = (uint8_t)len_lbl;
      ret[2] = (uint8_t)len_pwd;
      ret[3] = upwd.r;
      ret[4] = upwd.g;
      ret[5] = upwd.b;
      int pos = 6;
 
      for (int i = 0; i < len_lbl; i++) {
        ret[pos] = (uint8_t)upwd.lbl[i];
        pos += 1;
      }
      for (int i = 0; i < len_pwd; i++) {
        ret[pos] = (uint8_t)upwd.pwd[i];
        pos += 1;
      }
      for (int j = 0; j < sizeof(ret); j++) {
        EEPROM.write(offset, ret[j]);
        offset += 1;
      }
    }
  }
  if (VERBOSE == 1) {
    Serial.println("[EEPROM] Data Save finished");
  }
}
 
//Function for change login keys
void changeLoginKeys() {
  if ((btState0 != btPreviousState0) && (btState0 == HIGH)) {
    loginKeys[curIdx] = 0;
    curIdx += 1;
  }
  if ((btState1 != btPreviousState1) && (btState1 == HIGH)) {
    loginKeys[curIdx] = 1;
    curIdx += 1;
  }
  if ((btState2 != btPreviousState2) && (btState2 == HIGH)) {
    loginKeys[curIdx] = 2;
    curIdx += 1;
  }
 
  if (curIdx == _NBKEYSFORLOGIN) { //all keys set. Saving to eeprom
    curIdx = 0;
    nbBtStateForChangeLoginKeys = 0;
    eepromDataSave(_SAVEMODE_LOGIN);
    blinkLed(3, 0, 255, 0);
    setRGB(1, passwords[curIdx].r, passwords[curIdx].g, passwords[curIdx].b); //set first password color
  }
}
 
//Function to check action
void checkAction() {
  int nextpwd = 0;
  if ((btState0 != btPreviousState0) && (btState0 == HIGH)) { //set to first password
    curIdx = 0;
    nextpwd = 1;
    nbBtStateForChangeLoginKeys += 1;
  }
 
  else if ((btState1 != btPreviousState1) && (btState1 == HIGH)) { //change to next password
    nbBtStateForChangeLoginKeys = 0;
    curIdx += 1;
    if (curIdx >= nbPasswords) {
      curIdx = 0;
    }
    nextpwd = 1;
  }
 
  else if ((btState2 != btPreviousState2) && (btState2 == HIGH)) { //send password to keyboard
    nbBtStateForChangeLoginKeys = 0;
    Keyboard.print(passwords[curIdx].pwd);
  }
  if (nbBtStateForChangeLoginKeys == 3) { //we blink to notify we enter in changing login keys
    curIdx = 0;
    blinkLed(3, 255, 242, 0);
    setRGB(1, 255, 242, 0);
  }
  else if (nextpwd == 1) { //we change to next pwd
    setRGB(1, passwords[curIdx].r, passwords[curIdx].g, passwords[curIdx].b);
  }
 
}
 
//Function to check if passwords are defined
void checkPasswords() {
  if (sizeof(passwords) == 0) {
    while (true) {
      blinkLed(10, 255, 0, 0);
    }
  }
}
 
//Function to check the login
void checkLogin() {
  if ((btState0 != btPreviousState0) && (btState0 == HIGH)) {
    loginKeysUser[curIdx] = 0;
    curIdx += 1;
  }
  if ((btState1 != btPreviousState1) && (btState1 == HIGH)) {
    loginKeysUser[curIdx] = 1;
    curIdx += 1;
  }
  if ((btState2 != btPreviousState2) && (btState2 == HIGH)) {
    loginKeysUser[curIdx] = 2;
    curIdx += 1;
  }
 
  if (curIdx == _NBKEYSFORLOGIN) {
    //check keys to valid login
    int isOk = 1;
    for (int i = 0; i < _NBKEYSFORLOGIN; i++) {
      if (loginKeysUser[i] != loginKeys[i]) {
        isOk = 0;
        break;
      }
    }
 
    curIdx = 0; //raz curIdx
 
    if (isOk == 1) {
      dataCmd = "";
      isLogged = 1;
      blinkLed(3, 0, 255, 0);
      setRGB(1, passwords[curIdx].r, passwords[curIdx].g, passwords[curIdx].b); //set first password color
    }
    else {
      blinkLed(3, 255, 0, 0);
      setRGB(1, 255, 0, 0);
    }
  }
  else if (curIdx == 1) {
    setRGB(1, 255, 106, 0); //set led to orange
  }
}
 
//Function to blink for alert
void blinkLed(int nbloop, int r, int g, int b) {
  if (nbloop < 1) {
    nbloop = 1;
  }
  for (int i = 0; i < nbloop; i++) {
    setRGB(0, r, g, b);
    delay(125);
    setRGB(0, 0, 0, 0);
    delay(125);
  }
}
 
//Function which split a string
String stringSplit(String s, char parser, int index) {
  String rs = "";
  int parserIndex = index;
  int parserCnt = 0;
  int rFromIndex = 0, rToIndex = -1;
 
  while (index >= parserCnt) {
    rFromIndex = rToIndex + 1;
    rToIndex = s.indexOf(parser, rFromIndex);
 
    if (index == parserCnt) {
      if (rToIndex == 0 || rToIndex == -1) {
        //return "";
      }
      return s.substring(rFromIndex, rToIndex);
    }
    else {
      parserCnt++;
    }
 
  }
  return rs;
}
 
//Function to handle command through Serial
void getCommand() {
  while (Serial.available() > 0) {
    //set led color
    setRGB(0, 0, 0, 0);
 
    char recv = Serial.read();
    // Process message when new line character is recv
    if (recv == '\n')
    {
      if (DEBUG == 1) {
        Serial.print("[CMD] ");
        Serial.println(dataCmd);
      }
      //run the command
      processCommand();
 
      /*
      if(dataCmd == "+++\n"){ // DON'T forget to add "\n" at the end of the string.
       	Serial.println("OK. Press h for help.");
       }
       */
 
 
      dataCmd = ""; // Clear recv buffer
    }
    else {
      dataCmd += recv;
    }
  }
}
 
//Function to process command
void processCommand() {
  dataCmd.trim();
  if (dataCmd.length() > 0) {
    if (dataCmd == "load") {
      eepromDataLoad();
    }
 
    else if (dataCmd == "save") {
      eepromDataSave(_SAVEMODE_ALL);
    }
 
    else if (dataCmd == "erase") {
      processCommandErase();
    }
 
    else if (dataCmd == "verbose") {
      processCommandVerbose();
    }
 
    else if (dataCmd == "list") {
      processCommandList();
    }
 
    else if (dataCmd.startsWith("gen")) {
      processCommandGenerateRandomPassword();
    }
 
    else if ((dataCmd.startsWith("add")) && (dataCmd.length() >= 5)) {
      if (nbPasswords < _MAXPWDTOSTORE) {
        processCommandAdd();
      }
      else {
        Serial.println("[ERROR] Maximum passwords already reached");
      }
    }
 
    else if ((dataCmd.startsWith("del")) && (dataCmd.length() >= 5)) {
      if (nbPasswords > 0) {
        processCommandDelete();
      }
      else {
        Serial.println("[ERROR] No password stored");
      }
    }
 
    else if ((dataCmd.startsWith("sel")) && (dataCmd.length() >= 5)) {
      if (nbPasswords > 0) {
        processCommandSelect();
      }
      else {
        Serial.println("[ERROR] No password stored");
      }
    }
    else {
      showHelp();
    }
  }
  else {
    showHelp();
  }
}
 
//Function to erase all data stored
void processCommandErase() {
  nbPasswords = 0;
  eepromDataErase();
  if (VERBOSE == true) {
    Serial.println("[ERASE] All data has been erased");
  }
}
 
//Function to change verbose output
void processCommandVerbose() {
  VERBOSE = !VERBOSE;
  if (VERBOSE == true) {
    Serial.println("[VERBOSE] output is now enabled");
  }
  else {
    Serial.println("[VERBOSE] output is now disabled");
  }
}
 
//Function to list all passwords
void processCommandList() {
  if (nbPasswords > 0) {
    Serial.println("[LIST] Displaying your password list:");
    for (int i = 0; i < nbPasswords; i++) {
      userPassword upwd = passwords[i];
      Serial.print("[");
      Serial.print(i + 1);
      Serial.print("] ");
      Serial.print(upwd.lbl);
      Serial.print(" - ");
      Serial.print(upwd.pwd);
      Serial.print(" - ");
      Serial.print(upwd.r, HEX);
      Serial.print(upwd.g, HEX);
      Serial.println(upwd.b, HEX);
    }
  }
  else {
    Serial.println("[LIST] No password to display");
  }
}
 
//Function to add a new password
void processCommandAdd() {
  bool showWarn = false;
  int nb = 0;
  for (int i = 0; i < dataCmd.length(); i++) {
    if (dataCmd[i] == ';') {
      nb += 1;
    }
  }
  if (nb == 2) {
    String tmp = dataCmd.substring(4);
    String tmpName = stringSplit(tmp, ';', 0);
    String tmpPass = stringSplit(tmp, ';', 1);
    String tmpHex = stringSplit(tmp, ';', 2);
    if ((tmpName.length() > 0) && (tmpPass.length() > 0) && (tmpHex.length() == 6)) {
      int r;
      int g;
      int b;
      char tc[2];
      tc[0] = tmpHex[0];
      tc[1] = tmpHex[1];
      r = hexToDec(tc);
      tc[0] = tmpHex[2];
      tc[1] = tmpHex[3];
      g = hexToDec(tc);
      tc[0] = tmpHex[4];
      tc[1] = tmpHex[5];
      b = hexToDec(tc);
 
      userPassword upwd;
      upwd.r = r;
      upwd.g = g;
      upwd.b = b;
      upwd.lbl = tmpName;
      upwd.pwd = tmpPass;
 
      passwords[nbPasswords] = upwd;
      nbPasswords += 1;
 
      if (VERBOSE == 1) {
        Serial.print("[ADD] New password added for ");
        Serial.println(tmpName);
      }
      eepromDataSave(_SAVEMODE_PWD); //saving data to eeprom
 
    }
    else {
      showWarn = true;
    }
  }
  else {
    showWarn = true;
  }
  if (showWarn == true) {
    Serial.println("[ERROR] Bad syntax (ex: add Facebook;mypassword;0000FF)");
  }
}
 
//Function to delete a password
void processCommandDelete() {
  bool showWarn = false;
  int pos = dataCmd.indexOf(" ");
  if (pos != -1) {
    String tmp = dataCmd.substring(pos);
    int idx = tmp.toInt() - 1;
    if ((idx >= 0) && (idx < nbPasswords)) {
      String tmpName = passwords[idx].lbl;
      int j = 0;
      for (int i = idx; i < nbPasswords; i++) {
        if (i < _MAXPWDTOSTORE) {
          passwords[i] = passwords[i + 1];
        }
      }
 
      nbPasswords -= 1;
      if (VERBOSE == 1) {
        Serial.print("[DEL] Password deleted for ");
        Serial.println(tmpName);
      }
      eepromDataSave(_SAVEMODE_PWD); //saving data to eeprom
    }
    else {
      Serial.println("[ERROR] Bad password number");
    }
  }
  if (showWarn == true) {
    Serial.println("[ERROR] Bad syntax (ex: del 8)");
  }
}
 
//Function to select a password
void processCommandSelect() {
  bool showWarn = false;
  int pos = dataCmd.indexOf(" ");
  if (pos != -1) {
    String tmp = dataCmd.substring(pos);
    int idx = tmp.toInt() - 1;
    if ((idx >= 0) && (idx < nbPasswords)) {
      curIdx = idx;
      setRGB(1, passwords[curIdx].r, passwords[curIdx].g, passwords[curIdx].b);
      if (VERBOSE == 1) {
        Serial.print("[SEL] ");
        Serial.print(passwords[curIdx].lbl);
        Serial.println(" selected");
      }
    }
    else {
      Serial.println("[ERROR] Bad password number");
    }
  }
  if (showWarn == true) {
    Serial.println("[ERROR] Bad syntax (ex: del 8)");
  }
 
}
 
//Function to generate a random password
void processCommandGenerateRandomPassword() {
  int sz = 32;
  if (dataCmd.length() >= 5 ) {
    int pos = dataCmd.indexOf(" ");
    if (pos != -1) {
      String tmp = dataCmd.substring(pos);
      int idx = tmp.toInt() - 1;
      if (idx >= 0) {
        sz = idx;
      }
    }
  }
 
  while (Entropy.available() != 8); //wait for entropy pool to fill
  String genpwd = "";
  for (int i = 0; i < sz; i++) {
    genpwd += passwordChars[Entropy.random(sizeof(passwordChars) - 1)];
  }
  Serial.print("[SEL] Random password: ");
  Serial.println(genpwd);
}
 
//Function which convert hexcolor 2L to decimal value
unsigned long hexToDec(char *a)
{
  int len = 2;
  int i;
  unsigned long val = 0;
 
  for (i = 0; i < len; i++)
    if (a[i] <= 57)
      val += (a[i] - 48) * (1 << (4 * (len - 1 - i)));
    else
      val += (a[i] - 55) * (1 << (4 * (len - 1 - i)));
  return val;
}
 
//Function to display help
void showHelp() {
  Serial.println("***********************");
  Serial.println("* Password Box by jhd *");
  Serial.println("* http://www.ZeM.fr   *");
  Serial.println("***********************");
  Serial.println("List of available commands: ");
  Serial.println("* add: add a new password configuration (ex: add Facebook;mypassword;0000FF)");
  Serial.println("* del: remove a password stored (ex: del 8)");
  Serial.println("* list: list all passwords defined");
  Serial.println("* sel: select a password stored (ex: sel 7)");
  Serial.println("* gen: generate a random password (ex: gen 32)");
  Serial.println("* load: load configuration from eeprom");
  Serial.println("* save: save current configuration to eeprom");
  Serial.println("* erase: erase all data stored: login keys and passwords (use with caution)");
  Serial.println("* verbose: change verbose output");
}
 
//Function to set RGB color for Led
void setRGB(int save, int r, int g, int b) {
  if (save == 1) {
    led_R = r;
    led_G = g;
    led_B = b;
  }
  analogWrite(_PINLED_R, 255 - r);
  analogWrite(_PINLED_G, 255 - g);
  analogWrite(_PINLED_B, 255 - b);
}
Vous noterez l’utilisation de la librairie “Entropy” qui permet de générer des chiffres aléatoires. Je mets à votre disposition l’ensemble des fichiers en téléchargement. Le code d’Arduino Password Box est donc disponible en téléchargement ici.

Photos de l’Arduino Password Box

Voici quelques photographies de mon prototype d’Arduino Password Box:

arduino password box back

arduino password box back

arduino micro password box

arduino micro password box

arduino password box front

arduino password box front

Plutôt propre pour une maquette non ? Et çà fonctionne du feu de dieu. Désormais il m’est impossible de me passer de mon Arduino Password Box.

Evolution de l’Arduino Password Box

Arduino Password Box est un périphérique de stockage de mots de passe totalement libre et évolutif. Il n’y a donc aucune limite concernant son évolution et sa modularité. Voici 3 évolutions qu’il est possible de réaliser sur un Arduino Password Box. Je réaliserai peut être ces évolutions si cela devient une demande fréquente.

1) Augmenter la capacité de stockage

Actuellement les paramètres et les mots de passe sont sauvegardés directement sur la mémoire du ATMega328 du Arduino Pro Micro. L’avantage est qu’il est aisé de lire et écrire des données, l’inconvénient étant la limite de stockage (1024 Bytes). Il est ainsi possible d’ajouter une mémoire externe (EEPROM) afin d’augmenter la capacité de stockage des mots de passe. Ainsi pour à peine 2€ et quelques modifications dans le code, vous pourrez sauvegarder des milliers de mots de passe. Je vous invite à consulter mon article sur l’extension de stockage d’un Arduino grâce à l’utilisation d’un eeprom 24LC512.

2) Sécuriser le stockage

Les données sont actuellement sauvées dans l’eeprom du Arduino Pro Micro en format brut (raw). Il est donc difficile mais pas impossible de venir lire et extraire les données en dessoudant la puce et en lisant l’ensemble de l’espace mémoire (bon courage quand même aux hackers !). Une solution consisterait donc à encrypter les données stockées en utilisant AES ou DES. Par chance, il existe des librairies Arduino qui s’occupent d’encrypter et décrypter des données. Cela ne doit donc pas être difficile d’implémenter cette fonctionnalité.

3) Réaliser un boitier

Enfin il peut être sympa d’avoir un boitier ergonomique et design pour protéger votre Arduino Password Box. Avec l’arrivée des imprimantes 3D, il devient possible de laisser libre cours à votre imagination 🙂

Supporter le projet Arduino Password Box

Si vous souhaitez nous aider dans notre développement d’Arduino Password Box ou bien si vous souhaitez nous encourager à lancer de nouveaux projets totalement gratuit, vous pouvez nous envoyer quelques bitcoins ou quelques litecoins:

  • Adresse BITCOIN: 1B4ncRoDfJWykgHUHsvosPQbts6u9bjRc4
  • Adresse LITECOIN: LQxXtRbh497AsBG76vqkNfBVVKp5Z6vsof

Il est également possible d’effectuer une donation Paypal afin de nous permettre d’investir dans de nouveaux composants pour mener à bien de nouveaux projets électroniques:

4 Responses to [DIY] Arduino Password Box: protéger vos mots de passe

  1. andro says:

    ce qui serait vraiement trop cool c est de faire ce project avec un attiny
    85 pour qui il fonctionne avec windows 8.1
    voici la version qui marche seulement avec windows 7
    http://www.cortex.lt/e107_plugins/content/content.php?content.62
    petit pas chere
    les mises a jours qui serait bien et que personne n as faite…
    -compatible windows 8 windows 8.1
    que l ont puis rajouter dans le main.c
    un password avec des caractere speciaux

    merci et super travail de la password box
    andro

  2. Bonjour,
    Excellente idée, j’ai justement rédigé un article sur mon blog sur un sujet similaire basé sur le DigiSpark (ATTiny85):
    http://blog.mister-bidouilles.fr/une-cle-usb-qui-saisit-votre-mot-de-passe-pour-moins-de-3-euros/

    Avec un peu de temps je pense qu’il est même possible de se lancer dans la génération d’un OTP (One Time PAssword) en s’appuyant sur l’algorithme “Rolling Code” utilisé dans certaines télécommandes à l’image de ce que fait la Yubikey (https://www.yubico.com/products/yubikey-hardware/yubikey-2/)

    Jérôme.

Leave a Reply

Your email address will not be published. Required fields are marked *