简体   繁体   中英

Arduino to Android secure bluetooth connection

I'm using an Arduino Uno and a nRF8001 board from Adafruit to connect to an Android phone over bluetooth. I will be using it to lock and unlock a lock and I need to make sure only verified devices are able to initiate the locking and unlocking. I've searched around a bunch and I'm having trouble finding a clear example of what I should do to verify the connecting device. Currently I have the Arduino hooked up to the lock and whenever the Android phone connects, it is allowed to lock and unlock.

The process I had in mind is as follows.

  1. Android tries to connect to the Arduino
  2. Arduino sees the request and sends a random string to the Android device
  3. The Android encrypts the string with a shared secret key and sends it back to the Arduino
  4. The Arduino decrypts the encrypted string and verifies it matches the original it sent if it does it it goes ahead and connects/continues with locking or unlocking.

[EDIT] I've done a lot more research and work and from advice from security.stackexchange I decided to use AES to do the encryption. I am using this Arduino library and this Android library I'm a little confused on what configuration I should use on the two libraries I am using from programming an Arduino and Android.

My Arduino code I set up to test encrypting an decrypting:

#include <AES.h>

AES aes ;

byte key[] = 
{
  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
} ;

byte plain[] =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
} ;

byte my_iv[] = 
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
} ;

char PassString[] = "This is hard to believe but true";
char Message[] = "We, the Fairies, blithe and antic Of dimensions not gigantic, Th";

byte cipher [4*N_BLOCK] ;
byte check [4*N_BLOCK] ;

int bits = 128;
int blocks = 4;

void loop () 
{}


void setup ()
{
  Serial.begin (9600) ;
  Serial.println ("Starting encryption...") ;

  byte iv [N_BLOCK] ;

  // Pass the key into the byte array
  for (int i = 0; i < 32; i++) {
    key[i] = PassString[i];
  }

  print_value ("KEY = ", key, 256) ;

  for (int i = 0; i < 64; i++) {
    plain[i] = Message[i];
  }

  // Set Key
  byte succ = aes.set_key (key, bits) ;

  // Encrypt
  for (byte i = 0 ; i < 16 ; i++)
    iv[i] = my_iv[i] ;
  succ = aes.cbc_encrypt (plain, cipher, blocks, iv) ;

  // Decrypt
  for (byte i = 0 ; i < 16 ; i++)
    iv[i] = my_iv[i] ;
  succ = aes.cbc_decrypt (cipher, check, blocks, iv) ;

  // Prints the plain, ciper, decrypted, and IV
  for (byte ph = 0 ; ph < (blocks == 1 ? 3 : 4) ; ph++)
  {
    for (byte i = 0 ; i < (ph < 3 ? blocks*N_BLOCK : N_BLOCK) ; i++)
    {
      byte val = ph == 0 ? plain[i] : ph == 1 ? cipher[i] : ph == 2 ? check[i] : iv[i] ;
      Serial.print (val>>4, HEX) ; Serial.print (val&15, HEX) ; Serial.print (" ") ;
    }
    Serial.println () ;
  }  

}

char * hex = "0123456789abcdef" ;
void print_value (char * str, byte * a, int bits)
{
  Serial.print (str) ;
  bits >>= 3 ; //bits goes from decimal 128 to decimal 16
  for (int i = 0 ; i < bits ; i++)
    {
      // of ex. 0xb9 prints b then 9
      byte b = a[i] ;
      Serial.print (hex [b >> 4]) ;
      Serial.print (hex [b & 15]) ;
    }
  Serial.println () ;
}

My Android program is almost verbatim from the link above.

I can get both of them to encrypt and decrypt their own messages, but their set ups seem very different and haven't been able to encrypt each others. The Android code seems to have quite a bit more involved like creating keys and salts. Both libraries are pretty versatile and I'm not sure how to make them encrypt the same way.

I have a few questions that hopefully will help me get this solved:

  1. How do the "blocks" in the Arduino code relate to the Android implementation?
  2. From what I've read, to decrypt the cipher text on the Arduino from Android I will need to send, the cipher text, the IV, and the PBE iteration count. Is that correct and everything?
  3. Android code takes my key and uses a bunch of SecretKeys functions on it to I think randomize it and make it more secure. If I'm having to store the key on the Arduino, do I need to even bother with this?
  4. Where is the PBE iteration count in the Arduino code? I don't really see anything in the library. Do I need to implement that myself? I saw in the "test_vectors" example of the library a section that had the following bit of code. Is this the iteration?

     for (int j = 0 ; j < 1000 ; j++) { succ = aes.encrypt (plain, cipher) ; aes.copy_n_bytes (plain, cipher, 16) ; }

If you want to send encrypted messages from Android to Arduino, you have to make sure that you use the same parameters in both ends.

I took some test vectors from Vladimir Klykov and then encrypted and decrypted with Arduino (using AES library ) and Java.

Both libraries can be set to CBC, use 16 bytes hex vectors in both ends and you won't have padding issues.

Arduino

#include <AES.h>

AES aes ;

//2b7e151628aed2a6abf7158809cf4f3c
byte key[] = {
  0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, 
};

//6bc1bee22e409f96e93d7e117393172a
byte plain[] = {
  0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 
};

//000102030405060708090A0B0C0D0E0F
byte my_iv[] = {
  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 
};

byte cipher [N_BLOCK] ;
byte check [N_BLOCK] ;

void loop () 
{
}

void setup () 
{
  Serial.begin (115200) ;

  while (!Serial) ;
  Serial.println ("Ready") ;

  Serial.print("N_BLOCK: ") ;
  Serial.println (N_BLOCK) ;

  prekey (128, 2) ;
}

void prekey (int bits, int blocks)
{
  byte iv [N_BLOCK] ;

  long t0 = micros () ;
  byte succ = aes.set_key (key, bits) ;
  long t1 = micros()-t0 ;
  Serial.print ("set_key ") ; Serial.print (bits) ; Serial.print (" ->") ; Serial.print ((int) succ) ;
  Serial.print (" took ") ; Serial.print (t1) ; Serial.println ("us") ;
  t0 = micros () ;
  if (blocks == 1)
    succ = aes.encrypt (plain, cipher) ;
  else
  {
    for (byte i = 0 ; i < 16 ; i++)
      iv[i] = my_iv[i] ;
    succ = aes.cbc_encrypt (plain, cipher, blocks, iv) ;
  }
  t1 = micros () - t0 ;
  Serial.print ("encrypt") ; Serial.print (" ->") ; Serial.print ((int) succ) ;
  Serial.print (" took ") ; Serial.print (t1) ; Serial.println ("us") ;

  t0 = micros () ;
  if (blocks == 1)
    succ = aes.decrypt (cipher, plain) ;
  else
  {
    for (byte i = 0 ; i < 16 ; i++)
      iv[i] = my_iv[i] ;
    succ = aes.cbc_decrypt (cipher, check, blocks, iv) ;
  }
  t1 = micros () - t0 ;
  Serial.print ("decrypt") ; Serial.print (" ->") ; Serial.print ((int) succ) ;
  Serial.print (" took ") ; Serial.print (t1) ; Serial.println ("us") ;

  for (byte ph = 0 ; ph < 5 ; ph++)
  {
    Serial.print(ph == 0 ? "plain:  " : ph == 1 ? "key:    " : ph == 2 ? "iv:     " : ph == 3 ? "enc:    " : "dec:    ") ;
    for (byte i = 0 ; i < (blocks-1)*N_BLOCK ; i++)
    {
      byte val = ph == 0 ? plain[i] : ph == 1 ? key[i] : ph == 2 ? my_iv[i] : ph == 3 ? cipher[i] : check[i] ;
      Serial.print (val>>4, HEX) ; Serial.print (val&15, HEX) ;
    }
    Serial.println () ;
  }  
}

Java

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import java.math.*;

public class Encryptor3 {

  public static byte[] hexStringToByteArray(String hexInputString){
    byte[] bts = new byte[hexInputString.length() / 2];

    for (int i = 0; i < bts.length; i++) {
      bts[i] = (byte) Integer.parseInt(hexInputString.substring(2*i, 2*i+2), 16);
    }

    return bts;
  }

  public static String byteArrayToString(byte[] byteArray) {
    StringBuilder str = new StringBuilder();

    for (int i = 0; i < byteArray.length; i++) {
      str.append((char) byteArray[i]);
    }

    return str.toString();
  }

  public static String byteArrayToHexString(byte[] arg) {
    int l = arg.length * 2;
    return String.format("%0"+l+"x", new BigInteger(1, arg));
  }

  public static byte[] encrypt(byte[] key1, byte[] key2, byte[] value) {
    try {
      IvParameterSpec iv = new IvParameterSpec(key2);
      SecretKeySpec skeySpec = new SecretKeySpec(key1, "AES");

      Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

      byte[] encrypted = cipher.doFinal(value);

      return encrypted;

    } catch (Exception ex) {
      ex.printStackTrace();
    }

    return null;
  }

  public static byte[] decrypt(byte[] key1, byte[] key2, byte[] encrypted) {
    try {
      IvParameterSpec iv = new IvParameterSpec(key2);
      SecretKeySpec skeySpec = new SecretKeySpec(key1, "AES");

      Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
      cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);

      byte[] original = cipher.doFinal(encrypted);

      return original;

    } catch (Exception ex) {
      ex.printStackTrace();
    }

    return null;
  }

  public static String toHex(String arg) {
    int l = arg.length() * 2;

    return String.format("%0"+l+"x", new BigInteger(1, arg.getBytes()));
  }

  public static String HexStringToString (String arg) {
    StringBuilder output = new StringBuilder();
    for (int i = 0; i < arg.length(); i+=2) {
      String str = arg.substring(i, i+2);
      output.append((char)Integer.parseInt(str, 16));
    }

    return output.toString();
  }


  public static void main(String[] args) {
    // source: http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors#aes-cbc-128
    String message = "6bc1bee22e409f96e93d7e117393172a"; // 16 byte = 128 bit key
    //String message = toHex("Hello00000000000");
    String key1 =    "2b7e151628aed2a6abf7158809cf4f3c";
    String iv =      "000102030405060708090A0B0C0D0E0F";
    String match =   "7649abac8119b246cee98e9b12e9197d";

    System.out.print("message (hex):         "); System.out.println(message);
    System.out.print("key (hex):             "); System.out.println(key1);
    System.out.print("iv (hex):              "); System.out.println(iv);
    System.out.print("match (hex):           "); System.out.println(match);
    System.out.println();

    byte[] enc_message_ba = encrypt(hexStringToByteArray(key1), hexStringToByteArray(iv), hexStringToByteArray(message));
    System.out.print("Encrypted (hex):       "); System.out.println(byteArrayToHexString(enc_message_ba));
    System.out.println();

    byte[] dec_message_ba = decrypt(hexStringToByteArray(key1), hexStringToByteArray(iv), enc_message_ba);
    System.out.print("Decrypted (hex):       "); System.out.println(byteArrayToHexString(dec_message_ba));
  }
}

Arduino output

Install AES library in Arduino and run as usual

Ready
N_BLOCK: 16
set_key 128 ->0 took 596us
encrypt ->0 took 1136us
decrypt ->0 took 1548us
plain:  6BC1BEE22E409F96E93D7E117393172A
key:    2B7E151628AED2A6ABF7158809CF4F3C
iv:     000102030405060708090A0B0C0D0E0F
enc:    7649ABAC8119B246CEE98E9B12E9197D
dec:    6BC1BEE22E409F96E93D7E117393172A

Java output

Put the code in Encryptor.java, then from command line

javac Encryptor.java 
java Encryptor
message (hex):         6bc1bee22e409f96e93d7e117393172a
key (hex):             2b7e151628aed2a6abf7158809cf4f3c
iv (hex):              000102030405060708090A0B0C0D0E0F
match (hex):           7649abac8119b246cee98e9b12e9197d

Encrypted (hex):       7649abac8119b246cee98e9b12e9197d

Decrypted (hex):       6bc1bee22e409f96e93d7e117393172a

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM