Simple (but good) Message Encryption?

Posted on
Page
of 2
/ 2
Next
  • I'd like to transmit some data wirelessly over a low-bandwidth, insecure channel - maybe 433Mhz, NRF24, etc.

    The data would be:

    • Sent in one direction only
    • Encrypted
    • Checked to see if it was corrupted
    • Only a handful of bytes longer than the original message

    The transmitter could be pre-loaded with an encryption key that didn't change, and the receiver with a decryption key.

    Does anyone know of an algorithm/protocol suitable for this? I hear all the time of people implementing their own home-grown solutions with massive security holes, so really want something tried and tested.

  • Is XOR Encryption with the One-Time pad an option for you?
    If the key you use is random, this encryption will be uncrack-able.
    And the encrypted message isn't longer then the not-encrypted message.

    Here's some pseudo-code:

    var key = <random data>
    var message;
    function encryptMessage()
    {
      message ^= key;
    }
    
    function decryptMessage()
    {
       message ^= key;
    }
    
  • I guess the problem is how I'd go about changing that key - as I understand it, if I use it to encode multiple messages then it starts to be pretty easy to work out what the key was...

    For instance if I just sent 1000 packets and random data over the air using the same pad, you could listen in, take the average of all packets, and you've basically got the key :(

  • You are right. But this is actually not a problem if the data is 100% random, because the chance that the message is "Attack from the north" is the same as "Attack from the south", or "I like cats so much!!"
    But your key can be very large! You could pick different or random indexes from the key. Maybe that's a solution.
    Or come up with something else.

  • Take a look at:

    bitwiseshiftleft.github.io/sjcl/

    AES is a well tested standard, and has low resource requirements. I can't speak for the safety of that particular library, but they certainly have some good credentials. I think it would be possible to trim down that library to fit on an Espruino, especially since you already have some components implemented (SHA-256).

  • Thanks! That looks really interesting...

  • @Gordon With encryption, I think custom compiling an encryption library into the firmware like the one I mentioned in the "shiny ui" thread should run faster than using javascript. I've tried using other Aes javascript libraries in the past found them to be too memory intensive and I kept getting the out of memory error in the console.
    With the amount of ram the Pico has, I'm pretty sure AES128 cbc and then sign the encrypted string using sha(which is already implemented) should work if custom compiled into the espruino firmware. However, I'm no expert.

  • I tend to agree that this probably ought to be in the firmware, not JS... I get the impression that the JS implementation would be memory intensive, both in terms of code size and variables. We already use a lot of RAM for JS modules with AT and ESP8266WiFi. If we add JS encryption on top of that, I worry that there wouldn't be much ram left for user code.

  • I also think that Blowfish is a very good cipher. Fast, low resource requirements. And coming from a very well known and reliable source. There are many free implementations in all kinds of languages:

    schneier.com/blowfish-downlo­ad.html

  • There's an stm32 cryptographic library: st.com/web/en/catalog/tools/P­F259409

    It would be handy to have access to things like aes as a native module for performance reasons, but I guess it'd have to be an optional inclusion into the firmware add must people wouldn't use it.

  • @the1laz
    People should be taught to use encryption because IMHO, it's more secure than transmitting clear over the air. Someone could argue that sending trivial data such as temp and water level over the air shouldnt need encryption. But, what if you want to turn something on and off such as a light or pump by sending a command over the air?

    Encryption can be confusing and combursome for someone to implement or at least for me when I started reading about it. I think Encryption needs to be easy to use in order for more people to use it. Like handling keys and etc... automatically in the background.

    Maybe if more people requested encryption support for the espruino, someone could donate their time to add encryption?

    I currently offload encryption to the Intel Edison which also handles the network side. The only issue I have is how long the Edison takes to bootup. I like the instantaneous bootup and code execution feel that microcontrollers have. So, ya having encryption would be a major plus for the espruino :)

  • Thanks - I totally agree a firmware implementation seems like the best bet.

    That crypto library got posted before - it sure looks good (hopefully it's quite efficient)... I could swap the current SHA implementation over to it as well. I didn't realise AES could work on 16 byte blocks - it definitely makes it much more of an option for low power radio.

    However: I'm very conscious that even good encryption that's applied badly can be useless. It'd be interesting to see if there are any good examples of using something like AES in this area (low resources and a pre-shared key).

  • A simple but effective message encryption could be en.wikipedia.org/wiki/XTEA it is lightweight and should be fast enough.

  • Wow, thanks - that looks good. I guess it's not quite up to AES? but then the resource requirements are tiny... It seems like a perfect solution to this kind of problem.

  • If you like it, you could take a look to this js implementation movable-type.co.uk/scripts/te­a.html

  • @user54159 thanks for this on the moveable-type page there is a line to Block xxTEA
    ""The more recent Block TEA is simpler and more effective, especially for arbitrary-length strings."" movable-type.co.uk/scripts/te­a-block.html

    Would that be a better choice?

  • May be..., As I see both implementations are very easy to try, I suppose we can do both as a module.

  • I recommend Blowfish en.wikipedia.org/wiki/Blowfish_(c­ipher)
    It has supposedly the same security level as AES. It has even shorter blocks of 8 byte. Moreover it is significantly more efficient for long-term usage and requires very little code.

    It has however a significant initialization time (I expect 100 ms.) and quit a large RAM footprint 4k. If the initialization happens only once per boot the initialization time should not be an issue.

    You can run any block cipher in two parallel modes - Counter Mode for Encryption and CBC Mode for Message Authentication (Cryptographically Secure CRC). Note, I basically described here the CCM mode. The last block of the CBC output is used as MAC/CRC.

    Keep in mind that you should use a different initialization vector (basically a random value) for every new message to prevent static analysis of the data.
    The IV may be sent in clear and often precedes the payload of each message.

  • Sure blowfish is one of the strongest algorithms but it is a heavy resource consuming too and don't know if it is really useful for this kind of use.

  • While I initially also proposed Blowfish, I now think that maybe due to limited resources XXTEA is a better choice.

    As a test, I implemented a C library which can be used to encrypt / decrypt strings using XXTEA. The code consumes roughly 1500 bytes. A test with encoding 10000 strings of 1000 bytes each took about 20 seconds, leading to about 500 KB per second encoding speed - decoding should be the same. That sounds pretty nice for me.

  • @Stevie, Would you mind to share your C library?

    Thanks,

  • @user54159, sure. But it's not really much. I guess Gordon will do a much better version at some point. This was more for experimentation, quickly hacked together. Due to the fact that xxtea needs to have the data with a size of multiples of 4, this version can only treat strings which do not contain the 0 character. I use it as a padding and also to detect end of string when decoding.

    To include in the makefile put the following before "endif # BOOTLOADER":

    INCLUDE += -I$(ROOT)/libs/xxtea
    WRAPPERSOURCES += libs/xxtea/jswrap_xxtea.c
    
    

    Then you will be able to write something like this in JS:

    var encrypted = XXTEA.encrypt("Hello world!", "asdfghjk12345678");
    var decrypted = XXTEA.decrypt(encrypted, "asdfghjk12345678");
    

    The key needs to be exactly 16 characters, the data can be from 1 to 1024 bytes, because it will be copied to a char buffer.


    1 Attachment

  • Just to update this, here's an implementation in JavaScript. Just needed some minor tweaks for Espruino:

    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
    /*  Block TEA (xxtea) Tiny Encryption Algorithm         (c) Chris Veness 2002-2014 / MIT Licence  */
    /*   - http://www.movable-type.co.uk/scripts/te­a-block.html                                              */
    /*                                                                                                */
    /*  Algorithm: David Wheeler & Roger Needham, Cambridge University Computer Lab                   */
    /*             http://www.cl.cam.ac.uk/ftp/papers/djw-r­mn/djw-rmn-tea.html (1994)                 */
    /*             http://www.cl.cam.ac.uk/ftp/users/djw3/x­tea.ps (1997)                              */
    /*             http://www.cl.cam.ac.uk/ftp/users/djw3/x­xtea.ps (1998)                             */
    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
    
    /**
     * Tiny Encryption Algorithm
     *
     * @namespace
     */
    var Tea = {};
    
    /**
     * Encrypts text using Corrected Block TEA (xxtea) algorithm.
     *
     * @param   {string} plaintext - String to be encrypted (multi-byte safe).
     * @param   {string} password - Password to be used for encryption (1st 16 chars).
     * @returns {string} Encrypted text (encoded as base64).
     */
    Tea.encrypt = function(plaintext, password) {
        plaintext = String(plaintext);
        password = String(password);
    
        if (plaintext.length == 0) return('');  // nothing to encrypt
    
        //  v is n-word data vector; converted to array of longs from UTF-8 string
        var v = Tea.strToLongs(plaintext);
        //  k is 4-word key; simply convert first 16 chars of password as key
        var k = Tea.strToLongs(password.slice(0,16));
        var n = v.length;
    
        v = Tea.encode(v, k);
    
        // convert array of longs to string
        var ciphertext = Tea.longsToStr(v);
    
        // convert binary string to base64 ascii for safe transport
        return btoa(ciphertext);
    };
    
    
    /**
     * Decrypts text using Corrected Block TEA (xxtea) algorithm.
     *
     * @param   {string} ciphertext - String to be decrypted.
     * @param   {string} password - Password to be used for decryption (1st 16 chars).
     * @returns {string} Decrypted text.
     */
    Tea.decrypt = function(ciphertext, password) {
        ciphertext = String(ciphertext);
        password = String(password);
    
        if (ciphertext.length == 0) return('');
    
        //  v is n-word data vector; converted to array of longs from base64 string
        var v = Tea.strToLongs(atob(ciphertext));
        //  k is 4-word key; simply convert first 16 chars of password as key
        var k = Tea.strToLongs(password.slice(0,16));
        var n = v.length;
    
        v = Tea.decode(v, k);
    
        var plaintext = Tea.longsToStr(v);
    
        // strip trailing null chars resulting from filling 4-char blocks:
        var lastCh = plaintext.length-1;  
        while (plaintext[lastCh]===0) lastCh--;
        plaintext = plaintext.substr(0,lastCh+1);
    
        return plaintext;
    };
    
    
    /**
     * XXTEA: encodes array of unsigned 32-bit integers using 128-bit key.
     *
     * @param   {number[]} v - Data vector.
     * @param   {number[]} k - Key.
     * @returns {number[]} Encoded vector.
     */
    Tea.encode = function(v, k) {
        if (v.length < 2) v[1] = 0;  // algorithm doesn't work for n<2 so fudge by adding a null
        var n = v.length;
    
        var z = v[n-1], y = v[0], delta = 0x9E3779B9;
        var mx, e, q = Math.floor(6 + 52/n), sum = 0;
    
        while (q-- > 0) {  // 6 + 52/n operations gives between 6 & 32 mixes on each word
            sum += delta;
            e = sum>>>2 & 3;
            for (var p = 0; p < n; p++) {
                y = v[(p+1)%n];
                mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z);
                z = v[p] += mx;
            }
        }
    
        return v;
    };
    
    
    /**
     * XXTEA: decodes array of unsigned 32-bit integers using 128-bit key.
     *
     * @param   {number[]} v - Data vector.
     * @param   {number[]} k - Key.
     * @returns {number[]} Decoded vector.
     */
    Tea.decode = function(v, k) {
        var n = v.length;
    
        var z = v[n-1], y = v[0], delta = 0x9E3779B9;
        var mx, e, q = Math.floor(6 + 52/n), sum = q*delta;
    
        while (sum != 0) {
            e = sum>>>2 & 3;
            for (var p = n-1; p >= 0; p--) {
                z = v[p>0 ? p-1 : n-1];
                mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z);
                y = v[p] -= mx;
            }
            sum -= delta;
        }
    
        return v;
    };
    
    
    /**
     * Converts string to array of longs (each containing 4 chars).
     * @private
     */
    Tea.strToLongs = function(s) {
        // note chars must be within ISO-8859-1 (Unicode code-point <= U+00FF) to fit 4/long
        var l = new Array(0|Math.ceil(s.length/4));
        for (var i=0; i<l.length; i++) {
            // note little-endian encoding - endianness is irrelevant as long as it matches longsToStr()
            l[i] = s.charCodeAt(i*4)        + (s.charCodeAt(i*4+1)<<8) +
                  (s.charCodeAt(i*4+2)<<16) + (s.charCodeAt(i*4+3)<<24);
        }
        return l; // note running off the end of the string generates nulls since bitwise operators
    };            // treat NaN as 0
    
    
    /**
     * Converts array of longs to string.
     * @private
     */
    Tea.longsToStr = function(l) {
        var a = new Array(l.length);
        for (var i=0; i<l.length; i++) {
            a[i] = String.fromCharCode(l[i] & 0xFF, l[i]>>>8 & 0xFF, l[i]>>>16 & 0xFF, l[i]>>>24 & 0xFF);
        }
        return a.join('');  // use Array.join() for better performance than repeated string appends
    };
    
    
    var s;
    console.log(s=Tea.encrypt("Hello World!", "Bob"));
    console.log(s=Tea.decrypt(s, "Bob"));
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Simple (but good) Message Encryption?

Posted by Avatar for Gordon @Gordon

Actions