Making your smart home a little safer

    In recent times, the world of “smart home” has become closer to beginner enthusiasts, due to the presence of a large number of hardware solutions with a low threshold of entry (we are talking about the Arduino platform and a considerable set of modules / sensors for it) and ready-made libraries and frameworks for working with them . As a rule, they have default settings (poppy addresses, channels, etc.) that are untouched and remain in the hands of these very beginners ... For example, the MySensors framework , mentioned not so long ago on Habré, has the settings file "MyConfig.h" which many (my unlucky neighbor in particular) do not even rule.

    On the one hand, I don’t care that in a multi-storey building someone can “eavesdrop” on the temperature in the kitchen (or even call with the question “What are you cooking?”), But on the other hand, I don’t want anyone to be able ( theoretically) manage power loads (turn on your favorite coffee machine, for example). I would like to be a little more confident that the command comes from my control device, and not from a fake one (in cryptography, this is known as “authentication”).

    Implementing such an approach is relatively simple ...

    The interaction between the control and the executive device is based on the "signature" of a random phrase with an internal key known to both devices. This can be demonstrated more clearly as follows:

    image

    Three functions can be implemented. One for generating a random phrase:

    byte alphabet[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a }; // a, b, c, d, etc
    void getPhrase(byte *phrase) {
    	for (int i = 0; i < 8; i++) {
    		phrase[i] = alphabet[random(0, 26)];
    		phrase[i + 1] = '\0';
    	}
    }
    


    The second is actually creating an MD5 hash ( MD5 library for the Arduino ):

    #include 
    byte sessionPhrase[9];
    byte salt[] = { 0x4c, 0x39, 0x78, 0x36, 0x73, 0x4c, 0x39, 0x78 }; // L9x6sL9x - внутренний ключ
    void signPhrase(byte *phrase, char *signedPhrase) {
    	byte localPhrase[17];
    	for (int i = 0; i < 16; i++) {
    		if (i < 8) localPhrase[i] = salt[i];
    		else localPhrase[i] = sessionPhrase[i - 8];
    		localPhrase[i + 1] = '\0';
    	}
    	unsigned char* hash = MD5::make_hash((char *)localPhrase);
    	char *md5str = MD5::make_digest(hash, 16);
    	for (int i = 0; i < 16; i++) {
    		signedPhrase[i] = md5str[i];
    		signedPhrase[i + 1] = '\0';
    	}
    	free(hash);
    	free(md5str);
    }
    


    The third one for reconciling the “signed” phrase of the initiator with the “self-signed” phrase of the performer:

    bool compareSignedPhrases(char *signedPhrase) {
    	if (strcmp(signedPhrase, (char *)sessionMD5Phrase) == 0) {
    		return true;
    	}
    	return false;
    }
    


    Short code for checking the generation of a phrase, its signing and comparison
    #include
    #include
    #include

    #define DEBUG 1

    byte sessionPhrase [9];
    char sessionMD5Phrase [17];
    byte salt [] = {0x4c, 0x39, 0x78, 0x36, 0x73, 0x4c, 0x39, 0x78}; // L9x6sL9x - internal key
    byte alphabet [] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x72 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a}; // a, b, c, d, etc

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

    void loop () {
    / * Generate a random phrase * /
    getPhrase (sessionPhrase);
    signPhrase (sessionPhrase, sessionMD5Phrase); // Remember for further comparison

    / * Sign * *
    char signedPhrase [17];
    signPhrase (sessionPhrase, signedPhrase);

    #ifdef DEBUG
    Serial.print ("signedPhrase:„);
    Serial.println ((char *) signedPhrase);
    Serial.print (“copmpare:„);
    Serial.println (compareSignedPhrases (signedPhrase));
    Serial.println (“”);
    #endif

    delay (1000);
    }

    void getPhrase (byte * phrase) {
    for (int i = 0; i <8; i ++) {
    phrase [i] = alphabet [random (0, 26)];
    phrase [i + 1] = '\ 0';
    }

    #ifdef DEBUG
    Serial.print ("sessionPhrase:„);
    Serial.println ((char *) sessionPhrase);
    #endif
    }

    void signPhrase (byte * phrase, char * signedPhrase) {
    byte catPhrase [17];
    for (int i = 0; i <16; i ++) {
    if (i <8) catPhrase [i] = salt [i];
    else catPhrase [i] = sessionPhrase [i - 8];
    catPhrase [i + 1] = '\ 0';
    }

    #ifdef DEBUG
    Serial.print (“catPhrase:„);
    Serial.println ((char *) catPhrase);
    #endif

    unsigned char * hash = MD5 :: make_hash ((char *) catPhrase);
    char * md5str = MD5 :: make_digest (hash, 16);

    for (int i = 0; i <16; i ++) {
    signedPhrase [i] = md5str [i];
    signedPhrase [i + 1] = '\ 0';
    }

    free (hash);
    free (md5str);
    }

    bool compareSignedPhrases (char * signedPhrase) {
    if (strcmp (signedPhrase, (char *) sessionMD5Phrase) == 0) {
    return true;
    }
    return false;
    }


    This approach can be performed both in your “bicycles” and in other frameworks (such as MySensors) and gives an additional plus to the security of your Internet of things.

    By the way, authentication will be in MySensors, currently it is implemented in the development version .

    PS: If it is interesting to the community, I will update my notes using the example of MySensors with examples of listings for Serial Gateway and Relay ...

    Also popular now: