encryption for raw lora
I've been sending some short strings (eg 'rly2 on') over raw lora from one lopy4 to another. With sf=12 it takes about 992ms to send 'rly 2 on'. I decided to try encrypting the strings following https://docs.pycom.io/firmwareapi/pycom/aes/ The first thing I learned is that crypto is a strings in to bytes out routine, with the 'rly2 on' string encrypting to b'\x02q\xa65*\xbb\xfbR\xf1}#\x08\xd0\xd9\x13x,X\xf5\xce\xe9"\xf3' (or similar). Sending '\x02q\xa65*\xbb\xfbR\xf1}#\x08\xd0\xd9\x13x,X\xf5\xce\xe9"\xf3' over raw lora takes 1811ms (83% longer). Is there a more short string friendly encryption algorithm on the lopy4? Preferably a string in to string out routine that generates a different out string for the same in string each time I use it but without the bloat.
robert-hh last edited by robert-hh
@kjm You were right about CFB mode. The issue you have is that you initialize the cipher with every message and use a random IV. Then you have to re-transmit the IV with every message, which is then expanded by 16 bytes. So you must avoid sending the IV all the time. But if you still want to save against message replay, you have to use other means of message sequencing and modification. The way you do it now is NOT save against message replay, because you send the IV in clear with the message. There are several ways to do so, but none of them is simple.
a) Use a constant IV (like all 0) and CFB, but use an own counter, which is checked at the receiver side to be monotonic increasing (or decreasing). This counter will be added to message and encrypted with it. The size is up to you. Less than 2 bytes is maybe not helpful. That's what LoraWAN does.
b) Use CTR mode with constant iv or CFB with a iv which varies in a known way (e.g. increasing). Do not transmit that variable element with the message. That would implicitly work as counter
and so on. So far it's easy. The tricky part is synchronization ob both sides. That could be done with a challenge-response protocol (look that up: https://en.wikipedia.org/wiki/Challenge–response_authentication), where both side verify that the other side is authentic. As part of that protocol, new counter values can be set. The Kerberos example of the link above is a simple means, which could be used as part of that sync.
Can you define what you mean by 'native' Rob? According to https://docs.pycom.io/firmwareapi/pycom/aes/ their AES.MODE_CFB example is working as a stream cipher so I don't understand why the cipher text takes longer to send than the plain text.
Apart from changing MODE_CFB to MODE_CTR what other changes would I have to make to
def _encrypt(txt): from crypto import AES; import crypto; key=b'must be 16 chars' iv=crypto.getrandbits(128); cipher=AES(key, AES.MODE_CFB, iv) bytes=txt.encode('utf8') msg=iv+cipher.encrypt(bytes) print(txt, '-->', msg); return msg
to get CTR mode? I can't figure out how to implement the packet counter you mentioned.
robert-hh last edited by robert-hh
@kjm AES as a block cipher in native mode will output full blocks. There are different operating modes. In OFB or CTR mode the encrypted message has the same size as the clear message (see https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation). You might want to use the CTR mode. The challenge to solve is synchronization of the key stream. For that, having the packet counter available would be handy.
Edit: Better stick with byte strings, as these are not subject to any change by encoding/decoding.