Arduino Bluetooth клавиатура с шифрованием Speck

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017
Приветствую!
 
Задумался я как то после разговора с шефом, который пожаловался что
никакой конспирации в сети не осталось, о создании железки для шифрования
переписки в интернете. После поисков остановил свой выбор на алгоритме Speck.
 
В библиотеке реализовал самую слабую комбинацию алгоритма,
32 бита блок шифрования, 64 бита ключ. Думал мощности Arduino будет не хватать,
оказалось что всего хватает и для параноиков можно увеличить алгоритм
до максимума Speck 128/256.
 
Для реализации мне понадобилось: Arduino UNO, LCD Keypad shield, HC-05.
 
К Arduino подключена PS/2 клавиатура, все набираемые символы отображаются
на LCD дисплее, подключив HC-05 к Android смартфону и используя любой
BT Terminal (я использую Serial Bluetooth Terminal т.к. он умеет весь
выводимый текст отправлять или копировать) мы получаем шестнадцатиричный текст,
который например отправляем по почте и потом расшифровываем.
 
С клавиатуры выбираются режимы работы:
Escape - основной режим шифрования (по умолчанию) - на дисплее Ready
F1 - шифрование тестового блока из документации по Speck
F3 - нет шифрования - все набираемые символы идут в Bluetooth
 в кодировке русских символов UTF-8 - на дисплее OFF
F8 - переключение русский/английский - на дисплее RUS/ENG
F12 - ввод ключа шифрования - Enter key на дисплее - система
 ждет ввода 16 шестнацатиричных символов (0..9,a..f) - 8 байт
 
Ниже ссылка на Гугл диск - библиотека Speck для Arduino,
библиотека на Паскале, и программа декодирования для ПК.
 
 
andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017
#include <EEPROM.h>
// address 0..7 - Crypto KEY
// address 8..183 - Generated Key 0..21
#include <SoftwareSerial.h>
#include <PS2Keyboard.h>
#include <LiquidCrystal_1602_RUS.h>
#include <Speck.h>

#define BTRXD 11 // orange
#define BTTXD 12 // yellow
#define BTSTATUS A5 // red
// BT - GND green +5V blue

const int PS2DataPin = 2; // white
const int PS2IRQpin =  3; // yellow
// PS2 - GND blue +5V red

PS2Keyboard KBD;

SoftwareSerial BT(BTTXD, BTRXD);
Speck speck;

LiquidCrystal_1602_RUS LCD(8, 9, 4, 5, 6, 7 );//For LCD Keypad Shield

word BufBlock32[2] = {0x0, 0x0};
byte IndexBufBlock = 0; // 0..3 bytes
byte WorkMode = 0;
// 0 - encode all bytes and Send HEX crypto text to BT
// 1 - enter crypto key
// 2 - without crypt - send byte to BT
// 3 - encode test text
byte Buf1byte[2];
byte IndexEnterKey = 0; // 0...15 char = 0..7 bytes
boolean setfc = false;
boolean entfc = false;
boolean EngKeys = true;
byte Rus1251keys[66] = {70, 60, 68, 85, 76, 84, 58, 80, 66, 81, 82, 75, 86, 89, 74, 71, 72, 67, 78, 69, 65, 123, 87, 88, 73, 79, 125, 83, 77, 34, 62, 90, 102, 44, 100, 117, 108, 116, 59, 112, 98, 113, 114, 107, 118, 121, 106, 103, 104, 99, 110, 101, 97, 91, 119, 120, 105, 111, 93, 115, 109, 39, 46, 122};
byte IdxLCD = 0; // 0..31 - char on LCD

void setup() {
  delay(1000);
  // put your setup code here, to run once:
  KBD.begin(PS2DataPin, PS2IRQpin);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.begin(9600);
  BT.begin(9600);
  KBD.clear;
  LCD.begin(16, 2);
  LCD.clear();
  LCD.setCursor(0, 0);
  SendTextToLCD("Ready ");
  SendByteToLCD(195, false);
  SendByteToLCD(238, false);
  SendByteToLCD(242, false);
  SendByteToLCD(238, false);
  SendByteToLCD(226, false);
  SendByteToLCD(32, true);
  SendTextToLCD("Ready ");
  SendByteToLCD(195, false);
  SendByteToLCD(238, false);
  SendByteToLCD(242, false);
  SendByteToLCD(238, false);
  SendByteToLCD(226, false);
  SendByteToLCD(32, true);
  if (EngKeys == true) {
    Serial.println("KEYS = English");
    SendTextToLCD("ENG ");
  }
  LCD.cursor();
  LCD.blink();
}

byte RusKeyTo1251(byte inByte) {
  switch (inByte) {
    case 126 : {
        return 168;
        break;
      }
    case 96 : {
        return 184;
        break;
      }
    default: {
        for (int i = 0; i <= 63; ++i) {
          if (inByte == Rus1251keys[i]) {
            return (i + 192);
          }
        }
        return inByte;
      }
  }
}

String byteToHEXstr(byte inByte) {
  byte p1 = inByte >> 4;
  byte p2 = inByte % 16;
  String s1, s2;
  if (p1 > 9) {
    s1 = char(p1 + 0x37);
  } else {
    s1 = char(p1 + 0x30);
  }
  if (p2 > 9) {
    s2 = char(p2 + 0x37);
  } else {
    s2 = char(p2 + 0x30);
  }
  return (s1 + s2);
}

String wordToHEXstr(word inWord) {
  word p1 = inWord >> 8;
  word p2 = inWord % 256;
  String s1, s2;
  s1 = byteToHEXstr(p1);
  s2 = byteToHEXstr(p2);
  return (s1 + s2);
}

// send win1251 byte to LCD
void SendByteToLCD(byte inByte, boolean ET) {
  if (inByte == 13) {
    if (IdxLCD < 16) {
      LCD.setCursor(0, 1);
      LCD.print("                ");
      LCD.setCursor(0, 1);
      IdxLCD = 16;
    } else {
      LCD.setCursor(0, 0);
      LCD.print("                ");
      LCD.setCursor(0, 0);
      IdxLCD = 0;
    }
    return;
  }
  if (ET == false) {
    if ((inByte == 168) || (inByte == 184) || ((inByte >= 192) && (inByte <= 255))) {
      LCD.print(LCD.asciiutf8(inByte));
    } else {
      LCD.print(char(inByte));
    }
  } else {
    LCD.print(char(inByte));
  }
  switch (IdxLCD) {
    case 15: {
        LCD.setCursor(0, 1);
        LCD.print("                ");
        LCD.setCursor(0, 1);
        ++IdxLCD;
        break;
      }
    case 31: {
        LCD.setCursor(0, 0);
        LCD.print("                ");
        LCD.setCursor(0, 0);
        IdxLCD = 0;
        break;
      }
    default : {
        ++IdxLCD;
      }
  }
}

// send text to LCD
void SendTextToLCD(String s) {
  for (int i = 0 ; i < s.length(); ++i) {
    SendByteToLCD(s[i], true);
  }
}

// send byte to crypto
void SendByteToOUT(byte inByte) {
  // save to buffer
  switch (IndexBufBlock) {
    case 0 : {
        word ww = BufBlock32[0];
        ww = ww << 8;
        ww = ww >> 8;
        BufBlock32[0] = ww + (inByte * 256);
        ++IndexBufBlock;
        break;
      }
    case 1 : {
        word ww = BufBlock32[0];
        ww = ww >> 8;
        ww = ww << 8;
        BufBlock32[0] = ww + inByte;
        ++IndexBufBlock;
        break;
      }
    case 2 : {
        word ww = BufBlock32[1];
        ww = ww << 8;
        ww = ww >> 8;
        BufBlock32[1] = ww + (inByte * 256);
        ++IndexBufBlock;
        break;
      }
    case 3 : {
        word ww = BufBlock32[1];
        ww = ww >> 8;
        ww = ww << 8;
        BufBlock32[1] = ww + inByte;
        IndexBufBlock = 0;
        // - crypt and send block
        speck.EnCrypt_32_64(BufBlock32);
        Serial.print(wordToHEXstr(BufBlock32[0])); Serial.print(' '); Serial.println(wordToHEXstr(BufBlock32[1]));
        if (analogRead(BTSTATUS) > 500) {
          BT.print(wordToHEXstr(BufBlock32[0])); BT.print(' '); BT.println(wordToHEXstr(BufBlock32[1]));
        }
        //--
        break;
      }
  }
}

// operate press key
void InputKey(byte inByte)
{
  // - select function key
  switch (inByte) {
    case PS2_ESC : {
        Serial.println();
        Serial.println("Main mode is ON");
        WorkMode = 0;
        setfc = true;
        SendTextToLCD(" Ready ");
        break;
      }
    case 0xC3 : {
        setfc = true;
        entfc = true;
        break;
      }
    case 0xBA : {
        if (entfc != true) {
          break;
        }
        Serial.println();
        Serial.println("Encode test text");
        WorkMode = 3;
        setfc = true;
        entfc = false;
        SendTextToLCD(" Test crypto ");
        break;
      }
    case 0xBB : {
        if (entfc != true) {
          break;
        }
        Serial.println();
        Serial.println("NO CRYPT!!! jast send text");
        WorkMode = 2;
        setfc = true;
        entfc = false;
        SendTextToLCD(" OFF ");
        break;
      }
    case 0xBC : {
        if (entfc != true) {
          break;
        }
        Serial.println();
        EngKeys = !EngKeys;
        if (EngKeys == true) {
          Serial.println("KEYS = English");
          SendTextToLCD(" ENG ");
        } else {
          Serial.println("KEYS = Russian");
          SendTextToLCD(" RUS ");
        }
        setfc = true;
        entfc = false;
        delay(500);
        break;
      }
    case 0xBD : {
        if (entfc != true) {
          break;
        }
        Serial.println();
        Serial.println("Enter crypto key");
        WorkMode = 1;
        setfc = true;
        entfc = false;
        SendTextToLCD(" Enter Key ");
        break;
      }
    default: {
        setfc = false;
        entfc = false;
      }
  }
  if (setfc == true) {
    return;
  }
  // -
  switch (WorkMode) {
    case 1 : {
        if (((inByte >= 0x30) && (inByte <= 0x39)) || ((inByte >= 0x41) && (inByte <= 0x46))  || ((inByte >= 0x61) && (inByte <= 0x66))) {
          byte bb;
          if ((inByte >= 0x30) && (inByte <= 0x39)) {
            bb = inByte - 0x30;
          }
          if ((inByte >= 0x41) && (inByte <= 0x46)) {
            bb = inByte - 0x37;
          }
          if ((inByte >= 0x61) && (inByte <= 0x66)) {
            bb = inByte - 0x57;
          }
          if (((IndexEnterKey + 2) % 2) == 0) {
            Buf1byte[0] = bb;
          } else {
            Buf1byte[1] = bb;
            EEPROM.write((IndexEnterKey / 2), ((Buf1byte[0] * 16) + (Buf1byte[1])));
          }
          ++IndexEnterKey;
        }
        if (IndexEnterKey > 15) {
          IndexEnterKey = 0;
          WorkMode = 0;
          speck.Generate22keys();
          Serial.print("NewKey = ");
          for (int i = 0 ; i <= 7 ; ++i) {
            Serial.print(byteToHEXstr(EEPROM.read(i)));
          }
          Serial.println();
          SendTextToLCD(" Ready ");
        }
        break;
      }
    case 2 : {
        // convert rus key to win1251
        if (EngKeys == false) {
          inByte = RusKeyTo1251(inByte);
        }
        SendByteToLCD(inByte, EngKeys);
        // convert WIN1251 to UTF-8
        if (inByte > 127) {
          if ((inByte == 168) || (inByte == 184) || ((inByte >= 192) && (inByte <= 255))) {
            word ww;
            switch  (inByte)  {
              case 168 : {
                  ww =  53349;
                  break;
                }
              case 184 : {
                  ww =  53649;
                  break;
                }
              default : {
                  if (inByte <= 239 ) {
                    ww = 53200 + inByte;
                  } else {
                    ww = 53392 + inByte;
                  }
                }
            }
            byte bb = ww >> 8;
            Serial.write(bb);
            if (analogRead(BTSTATUS) > 500) {
              BT.write(bb);
            }
            bb = ww % 256;
            Serial.write(bb);
            if (analogRead(BTSTATUS) > 500) {
              BT.write(bb);
            }
          } else {
            Serial.write(inByte);
            if (analogRead(BTSTATUS) > 500) {
              BT.write(inByte);
            }
          }
        } else {
          Serial.write(inByte);
          if (analogRead(BTSTATUS) > 500) {
            BT.write(inByte);
          }
        }
        break;
      }
    case 3 : {
        BufBlock32[0] = 0x6574;
        BufBlock32[1] = 0x694C;
        Serial.print("Test Encode Block = "); Serial.print(wordToHEXstr(BufBlock32[0])); Serial.print(' '); Serial.println(wordToHEXstr(BufBlock32[1]));
        speck.EnCrypt_32_64(BufBlock32);
        Serial.print("Result Block = "); Serial.print(wordToHEXstr(BufBlock32[0])); Serial.print(' '); Serial.println(wordToHEXstr(BufBlock32[1]));
        SendTextToLCD(wordToHEXstr(BufBlock32[0]));
        SendTextToLCD("  ");
        SendTextToLCD(wordToHEXstr(BufBlock32[1]));
        WorkMode = 0;
        SendTextToLCD(" Ready ");
        break;
      }
    default : {
        // mode 0
        // convert rus key to win1251
        if (EngKeys == false) {
          inByte = RusKeyTo1251(inByte);
        }
        SendByteToLCD(inByte, EngKeys);
        // convert WIN1251 to UTF-8
        if (inByte > 127) {
          if ((inByte == 168) || (inByte == 184) || ((inByte >= 192) && (inByte <= 255))) {
            word ww;
            switch  (inByte)  {
              case 168 : {
                  ww =  53349;
                  break;
                }
              case 184 : {
                  ww =  53649;
                  break;
                }
              default : {
                  if (inByte <= 239 ) {
                    ww = 53200 + inByte;
                  } else {
                    ww = 53392 + inByte;
                  }
                }
            }
            byte bb = ww >> 8;
            SendByteToOUT(bb);
            bb = ww % 256;
            SendByteToOUT(bb);
          } else {
            SendByteToOUT(inByte);
          }
        } else {
          SendByteToOUT(inByte);
        }
        // - end mode 0
      }
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  // wait press keys
  if (KBD.available())
    while (KBD.available()) {
      byte bb = KBD.read();
      //Serial.print(bb); Serial.print(' '); Serial.println(RusKeyTo1251(bb));
      InputKey(bb);
      delay(50);
    }
  /*// - test Crypro functions
    Serial.println("test key FFFF FFFF FFFF FFFF");
    for (int i = 0 ; i <= 7 ; ++i)
    {
    EEPROM.write(i, 255);
    }
    Serial.println("gen 22 keys");
    speck.Generate22keys();
    speck.ShowToSerial22keys();
    Serial.println("un gen 22 keys");
    speck.UnGenerate22keys();
    speck.ShowToSerial22keys();
    Serial.println("test block = FFFF FFFF");
    word Block32[2] = {0xFFFF, 0xFFFF};
    speck.EnCrypt_32_64(Block32);
    Serial.print("result encrypt = "); Serial.print(Block32[0], HEX); Serial.print(' '); Serial.println(Block32[1], HEX);
    speck.DeCrypt_32_64(Block32);
    Serial.print("result decrypt = "); Serial.print(Block32[0], HEX); Serial.print(' '); Serial.println(Block32[1], HEX);
    Serial.println("test key 1918 1110 0908 0100");
    EEPROM.write(0, 0x19); EEPROM.write(1, 0x18);
    EEPROM.write(2, 0x11); EEPROM.write(3, 0x10);
    EEPROM.write(4, 0x09); EEPROM.write(5, 0x08);
    EEPROM.write(6, 0x01); EEPROM.write(7, 0x00);
    speck.Generate22keys();
    Serial.println("test block = 6574 694C");
    Block32[0] = 0x6574;
    Block32[1] = 0x694C;
    speck.EnCrypt_32_64(Block32);
    Serial.print("result encrypt = "); Serial.print(Block32[0], HEX); Serial.print(' '); Serial.println(Block32[1], HEX);
    speck.DeCrypt_32_64(Block32);
    Serial.print("result decrypt = "); Serial.print(Block32[0], HEX); Serial.print(' '); Serial.println(Block32[1], HEX);
    delay(20000);*/
  /*// - test connection and configure BT device
    // - by AT command
    if (analogRead(BTSTATUS) > 500) {
    digitalWrite(LED_BUILTIN, HIGH);
    //BT.println("AT"); // AT+ORGL AT+ROLE=0 AT+UART=9600,0,0 AT+NAME=BTKEYS AT+PSWD=****
    } else {
    digitalWrite(LED_BUILTIN, LOW);
    }
    if (Serial.available()) {
    while (Serial.available()) {
      BT.write(Serial.read());
      delay(10);
    }
    }
    if (BT.available()) {
    while (BT.available()) {
      Serial.write(BT.read());
      delay(10);
    }
    }
    // - end test and configure BT*/
}