This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Quartz101's profile picture

Secure Ring LWE / ChaCha20 over modem

Started by Quartz101, 21 April 2018 - 11:34 PM
Quartz101 #1
Posted 22 April 2018 - 01:34 AM
So, I decided to try out the Ring LWE PoC today. It works.


Dependencies (these are auto-downloaded upon running the API):
My modified Ring LWE API
Anavrins' ChaCha20 API
Anavrins' PBKDF2/HMAC API

Features:
  • Key exchange using Ring LWE
  • Fast yet secure ChaCha20 encryption
  • Replay attack protection via HMAC
  • Authentication via public/private keys generated via Ring LWE
Get the API:
pastebin get tUe94t9J ringnet

Functions:

--something encased in [ ] means it's optional.
-- HID = 8-character hexadecimal "handshake ID"
-- CID = long hexadecimal "session" or "connection" ID.

-- Starts a loop that listens for Ring LWE messages and converts them into events. Needs to be run on server AND client.
connectionHandler([client mode])

-- Initiates a handshake with targetID, over frq. Needs connectionHandler open to be any good.
-- Auto calculates frequency, which is used for sendData
openTunnel(targetHID, frequency)

-- Sends encrypted data to targetID, over frq
-- A handshake must have already been initiated for this!
sendData(targetCID, data)

-- Opens a channel on the API's modem object
openChannel(channel)

Events:

-- Occurs when handshake is finished
local ev, cid_from = os.pullEvent("tunnel_finish")
-- Occurs upon receiving encrypted data.
local ev, cid_from, data, distance = os.pullEvent("secure_receive")
Edited on 09 June 2018 - 09:28 PM
Anavrins #2
Posted 22 April 2018 - 05:46 AM
A few notes about this,
KillaVanilla's implementation of AES is known to be broken as it fails AES's test vectors,
it'd be better to use SquidDev's AES, or even better my Chacha20 for more speed and same security level.
You're also not doing any kind of message authentication (MAC), meaning any altered message sent to a receiver will be decrypted which might lead to many problems.
SquidDev #3
Posted 22 April 2018 - 08:29 AM
It'd be better to use SquidDev's AES, or even better my Chacha20 for more speed and same security level.
I'd echo the recommendation to use Anavrin's ChaCha20 implementation - it's both a smaller implementation, and runs substantially faster.
Quartz101 #4
Posted 22 April 2018 - 10:58 AM
A few notes about this,
KillaVanilla's implementation of AES is known to be broken as it fails AES's test vectors,
it'd be better to use SquidDev's AES, or even better my Chacha20 for more speed and same security level.
You're also not doing any kind of message authentication (MAC), meaning any altered message sent to a receiver will be decrypted which might lead to many problems.

Yes, but Ring LWE generates 512 length keys.
Quartz101 #5
Posted 22 April 2018 - 11:34 AM
A few notes about this,
KillaVanilla's implementation of AES is known to be broken as it fails AES's test vectors,
it'd be better to use SquidDev's AES, or even better my Chacha20 for more speed and same security level.
You're also not doing any kind of message authentication (MAC), meaning any altered message sent to a receiver will be decrypted which might lead to many problems.

Sadly I don't think ChaCha20 will work, due to Ring LWE exchanging 512 bit keys.
Quartz101 #6
Posted 22 April 2018 - 12:02 PM
anyways it uses SquidDev's API now
Anavrins #7
Posted 22 April 2018 - 06:53 PM
Sadly I don't think ChaCha20 will work, due to Ring LWE exchanging 512 bit keys.
Neither does AES with it's same maximum keylength of 256-bits.
Easy solution, split the RLWE key in half, use first 256-bits for encryption and the second half for message authentication.

Since it's not recommended to use a shared secret out of any kind of handshake directly, an alternative solution would be to use the RLWE shared secret to derive multiple other keys.
Something like:
enckey   = sha256.pbkdf2(rlwe_secret, "1", 50, 32) #-- generates a 32 bytes (256-bits) long key, with 50 pbkdf2 iterations, based of the RLWE secret
mackey   = sha256.pbkdf2(rlwe_secret, "2", 50, 32) #-- use different salts to get a different 256-bits keys
sendkey  = sha256.pbkdf2(rlwe_secret, "3", 50, 32)
recvkey  = sha256.pbkdf2(rlwe_secret, "4", 50, 32)
morekeys = sha256.pbkdf2(rlwe_secret, "5", 50, 32)
Edited on 22 April 2018 - 05:08 PM
Quartz101 #8
Posted 22 April 2018 - 07:33 PM
Sadly I don't think ChaCha20 will work, due to Ring LWE exchanging 512 bit keys.
Neither does AES with it's same maximum keylength of 256-bits.
Easy solution, split the RLWE key in half, use first 256-bits for encryption and the second half for message authentication.

Since it's not recommended to use a shared secret out of any kind of handshake directly, an alternative solution would be to use the RLWE shared secret to derive multiple other keys.
Something like:
enckey   = sha256.pbkdf2(rlwe_secret, "1", 50, 32) #-- generates a 32 bytes (256-bits) long key, with 50 pbkdf2 iterations, based of the RLWE secret
mackey   = sha256.pbkdf2(rlwe_secret, "2", 50, 32) #-- use different salts to get a different 256-bits keys
sendkey  = sha256.pbkdf2(rlwe_secret, "3", 50, 32)
recvkey  = sha256.pbkdf2(rlwe_secret, "4", 50, 32)
morekeys = sha256.pbkdf2(rlwe_secret, "5", 50, 32)

I'll implement this tomorrow since I don't trust myself to code right now due to lack of sleep.
Quartz101 #9
Posted 22 April 2018 - 07:38 PM
Also, I can't find a pbkdf2 API for CC?
Anavrins #10
Posted 22 April 2018 - 08:44 PM
Sorry, here it is: https://pastebin.com/6UV4qfNF
Quartz101 #11
Posted 22 April 2018 - 09:58 PM

Thanks! Anyways, i'll get a good night's sleep and probably then rewrite a decent portion of this API so my code looks like it WASN'T written by a drunken monkey who just got out of a poop throwing contest.
Quartz101 #12
Posted 24 April 2018 - 09:09 PM
Ok, I rewrote the entire API. It is now mostly event-based, and uses PBKDF2/ChaCha20.
Quartz101 #13
Posted 25 April 2018 - 10:49 PM
Thanks to @Anavrins, replay attack protection via HMAC is now implemented!
Quartz101 #14
Posted 05 June 2018 - 05:03 PM
Pinging is also now implemented!
Quartz101 #15
Posted 08 June 2018 - 07:54 PM
Rewrote it again. No more pinging for now, however, numeric IDs are gone. Servers have a "handshake ID", an 8-character hex, which is generated from the computer ID and a random large number. This is just used to start a handshake with it. Anyways, after you're connected and the handshake is complete, a random frequency is calculated between the two and they now have a "session ID", which is a long hexadecimal string which uniquely identifies the connection between the server/client.
Quartz101 #16
Posted 09 June 2018 - 11:29 PM
rewrote it again. no outwards facing changes. it's mostly the same, i just changed the handshake to use public/private keys to authenticate. RLWE will generate keys and store them in .rlwe_privkey and .rlwe_pubkey on first run.