AES encryption demo and secure TCPClient usage

Here’s a little demo that you can paste into Spark Build that shows how to use the AES-128-CBC encryption already available in the Spark Core firmware.

Put that on a Core and watch what it says on Serial.

Once every 10 seconds it will create a random encryption key and will print a message plain, then encrypted, then decrypted.

The open source AES implementation is from tropicssl in the core-communication-lib if you’re curious, and typical usage internal to the communication library is through wrap, which calls encrypt.

Things to know about AES-128-CBC in general

The key should remain the same throughout one session, e.g., downloading one file with TCPClient in your firmware. The key must remain secret. Next time you download a file, generate a new key. You can trust that sending through our API as an argument to a Spark.function is a secret transmission line for such a key.

The IV (initialization vector) however, should change with every call to either encrypt or decrypt, e.g., each buffered chunk of the downloaded file. It’s OK if the IV is publicly transmitted on the wire; it just needs to change for every single crypto operation.

Take a look at the encrypt method in the communication library—we use the first 16 bytes of each encrypted message as the IV for the next message. We keep two separate IVs—one for Core-to-Cloud communication, another for Cloud-to-Core communication. Both sides need to agree on the scheme for predictably changing the IV.

Suggestion for encrypted download with secure handshake

The Core could thus download an encrypted file from your server like this:

  • Your server calls a Spark.function where the string argument is 64 hex characters. The first 32 (parsed to 16 bytes) represent the key, the next 32 (parsed to 16 bytes) represent the starting IV. The server should generate these with a cryptographically secure PRNG. Examples: node, ruby, python
  • The Spark.function parses the hex string into binary bytes, saves the key and IV, and sets a flag meaning “on the next loop, start downloading”, and then returns.
  • On the next loop, seeing the flag is set, the Core sets up a TCPClient to open a socket to your server. I recommend the server write directly on the socket, like telnet, rather than HTTP. You don’t need hypertext links, CSS, images, javascript, metadata, or browser compatibility. Just write the file to the socket.
  • You should add a simple little authentication layer on the socket, like the Core has to write the first half of the IV hex string it received to the socket before the server will say OK, sure, I know who you are, here’s a file.
  • The Core should read a chunk of the file into a buffer, decrypt it, save it to flash, and then let loop finish. The next time loop is called, the TCPClient should read more. Rinse, repeat. Do this rather than trying to read the whole file in one call of loop, because if it takes longer than about 15 seconds, you’ll drop the network connection.

Happy encipherment!

20 Likes

Hi @zachary,

I must say I have came a long way using the information you have posted here. We are trying to accomplish aes ecb encryption on our project so I am calling that using aes_crypt_ecb to encrypt my data before sending. If my data is a const char with 16 characters it works beautifully. However if it is 17 then the first 16 characters are encrypted and the last is not. I understand this is because this is a block encryption which encrypts 16 bytes or characters. However in development of the aes.c the method for cbc takes this into account for you and everything works great. How can I make ecb work with arrays which are not exactly 16? Would I use the pad method like in your demo some how? If you could provide an example I will forever be in your debt!

Thank you,
Travis Elliott

You can learn more about the different modes on Wikipedia’s block cipher modes article, but the short answer is that ECB is not secure. You should not use it.

1 Like

Thank you @zachary

We will not be using ECB for normal data exchanges with our server. Only for the initialization of a session. We plan to store a master AES key on both our server and the device(Spark based). This key will be programmed into the module prior to sale along with a unique device ID. The AES key will be stored on our server at that time along with the device’s unique id as a key value pair. When the Spark device powers up it will initialize a session with our server by sending an ECB encoded packet. The server will then use this packet to create a cbc encoded packet and reply to the device with information on session parameters such as keep alives. This is really the most secure way we could determine to accomplish our goal. The Master AES key will never be transmitted, it will only be stored on the device and the server.

We have big plans for the Spark modules and we are no strangers to creating control devices. You can take a look at our site here if you would like: www.controlanything.com

Thank you very much Zachary,
Travis Elliott

You know your product best of course, and I don’t have all the detail. However, if I can help you prevent a security hole I want to. :smile:

Regarding the ECB encoded packet that the device sends each time it powers up—if the plaintext is the same every time and the key is the same every time, then the ciphertext will be the same every time. That would mean that anyone recording traffic can later pretend to be that device by replaying the recorded ciphertext.

Depending on what other information you require at other points in the process and how these values change over time, you might be fine in a practical sense if not a perfect security sense. Just be aware of your vulnerabilities, which, from a business perspective, may be acceptable.

Cheers!

1 Like

Thank you @zachary

Yes you are absolutely correct in that the session initialization packet must change. We will change it each time with a session id which will increase for each initialization attempt so the cypher text will change each time session initialization is made. We planned on just incrementing 1 but we could even do more than that like exponential change of the session id. Your thoughts on this? I would love to discuss in further details but do not want to expose our security protocol to much publicly. I am creating a google doc right now outlining how we plan to handle security between the devices and our server. Is there a way I can send that to you privately and you could just do a quick check on my ideas?

We are extremely excited about this new line and are building a really cool prototyping device we have nick named the Spark Plug around here. Id love to send you a couple if possible for your help :smiley:

Thanks again @zachary

Hey @zachary

Hope your vacation is going great!

I have pretty much completed the ecb initialization of session on my project and am now working on cbc decryption. I have tried to follow your demo as closely as possible but am running into a problem I am not sure how to solve.

I am sending encrypted data via HTTP get to a PHP server which then replys back with a cbc encrypted packet. The return packet contains 32 characters. I take this raw encrypted return from the server and pass it to my function to decrypt. It is working well except for one problem. I call cbc decrypt and pass the 32 character string and it decrypts but only the first 16 characters correctly. The second chunk of 16 characters comes back as “gobilty goop”. Here is my decrypt fuction:

void cbcDecrypt(String messageBody){
	const char *message = messageBody.c_str();
	int length = strlen(message)+1;

	//Create input and output buffers for encryption.
	unsigned char buf[length];
	unsigned char oBuf[strlen(message)];
	
	//Make sure buffers are empy
	memset(buf, 0, length);
	memset(oBuf, 0, strlen(message));
	
	//Copy message into input buffer
	memcpy(buf, message, length);

	size_t paddedLength = pad(buf, length);

	//Get IV out of memory
	unsigned char iv[16];
	memset(iv, 0, 16);
	for(int i = 0; i < 16; i++){
		iv[i] = EEPROM.read(i+20);
	}

	//Decrypt message into output buffer
	aes_setkey_dec(&aes, key, 128);
	aes_crypt_cbc(&aes, AES_DECRYPT, paddedLength, iv, buf, oBuf);

	//Store first 16 decrypted characters as round key for next cbc encrypted send
	for(int i = 0; i < 16; i++){
		EEPROM.write(i+36, oBuf[i]);
	}

	//Print out the decrypted message and the length of the encrypted message received
	Serial.print("Decrypted return: ");
	Serial.println((char *)oBuf);
	Serial.print("Return length+1 = ");
	Serial.println(length);
} 

Does anything about this stand out to you? Feel like I am doing it as safely as possible but that second 16 character chunk just is not getting decrypted correctly.

Thank you,
Travis

I’m working on an combination of Spark making HTTP (using rest_client library) calles to an PHP with JSON info. The idea is to encrypt the JSON data based on AES 128 CBC. The PHP to which the Spark is talking to must in return decrypt the JSON and return and encrypt JSON as its response.

The communication part between Spark en PHP using JSON is already finisched. now I want some encryption in between :slight_smile:

Who knows maybe someone already created something like that or I will be the first to try?

Hi @bartjenniskens

I have been working on the very same thing and have it working pretty well.

There are a few caveats to this type of system which need to be dealt with.

The first is that an HTTP get request which will be used to pass the encrypted data to the server must be in string format. The problem is AES 128 encryption will output data that is not ASCII string friendly. I resolved this by encrypting my data via AES, then I Base 64 encode that data, then send it to the server. The server decodes the base 64 packet, then decrypts the packet.

Have you determined an AES encrypt/decrypt strategy? Do you plan on using cbc with a master and round key(IV) or will you just use simple ecb encrypting only with a static master key?

I can share some examples. I have been meaning to post this information for a while now.

1 Like

Just to reiterate: ECB is very unsafe. Replay attacks are trivial as are offline attacks to recover the key.

It obviously depends on who you are trying to keep secrets from.

Hi @zachary,

I recently got to know about a new hack in SSL/TLS based security systems.
Links : http://thehackernews.com/2015/03/freak-openssl-vulnerability.html
http://blog.cryptographyengineering.com/2015/03/attack-of-week-freak-or-factoring-nsa.html

Since spark also used RSA, SSL/TLS security, can you share your thoughts on how secure it is when such hacks/threats exist.

@Akash

Hi @Akash

The most recent SSL vulnerability is all about forcing a low length RSA key into the connection using an old style of connecting that should have been removed long ago.

If you are asking if the Spark cloud to user connection could have this problem, I suppose it could but there will be a patch soon just like for every other web service.

If you are asking about the core to cloud connection, then no, it cannot have this problem. First off, this part of the connection does not use SSL, it uses something similar but less flexible with RSA keys used to set up an AES session key that is then used until the next time your core goes offline. Each core has a copy of its own RSA private key and the Spark cloud’s public in flash memory when it leaves the factory. It is not subject to a short-length key man-in-the-middle attack since the keys are not changeable other than by re-writing flash memory.

3 Likes

Thanks @bko. Nicely expained.

@Akash

2 Likes

In my project it will be only local traffic to a local web server. But the HTTP calls are used to unlock doors and my alarm system so a bit of encryption is an very nice to have.

I would like to do it right the first time. Like @bko said, ECB is not that secure but for me it is OK for local traffic.
If you could, please share my your code, that would be very helpful! :slight_smile:

Hi @bartjenniskens

It is very difficult to create a code library sample which would work for everyone. I have devised a communication method between the spark devices and my server which I believe is so secure it is “almost” un-hackable. However this is my take on secure client/server communications via AES. Let me explain briefly the routine and then you can let me know if it sounds like something you would be interested in.

Both the Spark module and server maintain a master key which does not change(16 bytes). This key is never under any circumstances transmitted between the devices. Also each spark module has a unique device ID(String).

Step 1(Initialization of Session between Client(spark) and server)
Spark module generates a 16 character array and populates the first characters in the array with it’s device ID. The rest of the characters in the array are populated with random characters.
This character array is then ECB encrypted with the master key.
The encrypted characters are then Base64 encoded so we do not have 00 bytes which can cause issues in an HTTP get request.
The Base 64 encoded packet is now appended to the end of an HTTP get request path which contains the device’s ID in the clear so the server can see who transmitted the packet. Also in the clear is an action. The action in initialization of the session is init
The server receives the packet.
The server sees this is an init session request by the action in the url, then sees the device’s ID in the url.
The server uses the device’s ID to look up the AES master key in a MySQL database.
The server then uses that key to ECB decrypt the packet.
To validate the server makes sure the device ID is properly there in the unEncrypted string.
The server now generates a string with 16 random characters and then a reply message appended to the end.
This string is now AES CBC encrypted using the AES Master key for the device as well as the deviceID+random characters sent by the device in the first transmission for the IV.
This CBC encrypted packet is now sent back to the Spark module.
Upon receiving this packet the Spark module decrypts it via CBC using it’s Master Key and the stored IV it put in the initial transmission.
The Spark module takes the first 16 characters out of the packet and stores that as the IV for its next transmission to the server.

Each sequential packet now is prepended with 16 random characters which the receiver uses to encrypt the reply via CBC. These random 16 characters are encrypted so the IV is never sent in the clear.

The device ID is always in the encrypted packet, if it is not in the decrypted packet then something went wrong and initialization is triggered again.

If you are interested in my method of secure communication please let me know and I can share my aes encryption library.

Thank you,
Travis Elliott

2 Likes

Hi Travis,

Thanks for that info and explanation.
I think that is a very nice way to setup encrypted communications. If you could share me the code of it than that would be very appreciated!

In this threat i’m talking about the project i’m working on; http://community.spark.io/t/http-post-and-return-body-handle/9977/12?u=bartjenniskens

Kind regards,
Bart

Hi @bartjenniskens

I am still in the polishing stages of my AES Encryption Client library. I do not have much left to finish though. Hopefully it will be ready by the end of the day.

As explained above this library is very proprietary to my usage of AES encryption so your server will have to handle encryption/decryption accordingly. I work with another guy here who develops the PHP server side, but he says it is not rocket science.

Will try to get this library up today or tomorrow.

Thank you,
Travis Elliott

2 Likes

Hey @bartjenniskens

As promised(a little late) Here is a link to my first submission of the AES Client I am working on:

I have not added an example use file yet. Will try to work on that today.

3 Likes

Looks very promising! I’ll dive into it this weekend. Thanks!

1 Like

No problem. If you have any questions please do not hesitate to ask.

1 Like