BeechatNetworkSystemsLtd / BeechatNetwork-Android

Android version of the open source, encrypted, peer-to-peer, Beechat app.
GNU General Public License v3.0
13 stars 2 forks source link

Messages are not encrypted #26

Closed markqvist closed 1 year ago

markqvist commented 1 year ago

The website for Beechat Network states that:

Beechat is the world's first quantum-proof mesh network

Additionally, the README.md seems to imply that messages sent over Beechat are encrypted, signed and verified, by stating that these features are already implemented (they are marked as Complete) in the feature list.

The above leads me to an understanding, that messages sent with Beechat should be encrypted by default, providing such a secure system, that even future quantum computers will be unable to break the encryption of exchanged messages.

From reading the code, the above does not seem to be the case. No traffic is encrypted, signed or verified by the Beechat client. Can any of the developers clarify what the actual, real-world situation is currently?

I was very interested to buy a couple of your devices to try out the system, but currently a bit uncertain what the status of the project is.

If I completely missed something obvious (or unobvious) here, would you mind directing me to the right parts of the implementation? I would love to know what primitives were used, and where in your implementation they are invoked, since I am very interested in reading your implementation, and would be happy to provide feedback.

Cheers, Mark

BeechatNetworkSystemsLtd commented 1 year ago

Hi Mark, please check the crypto branch. Indeed, the main branch is deprecated and used for unencrypted testing purposes.

markqvist commented 1 year ago

Thanks! This was the crypto branch I was reffering to actually. After reading that, I also checked the code in the main branch, and realised that was older and completely without crypto ;)

I see there is the beginnings of a key exchange mechanism based on Kyber-512 and Dilithium, but no actual encryption.

Am I missing something?

BeechatNetworkSystemsLtd commented 1 year ago

When building Beechat we wanted to make it quantum-resistant. As you point out, that means messages are protect with post quantum cryptography. For this we are using PQ-CRYSTALS. Since the code is written in C and C++ but our app is written in Java, we created wrappers (located here: https://github.com/BeechatNetworkSystemsLtd/BNS-CryptoLib ). The spec is defined here: https://beechat.network/docs/beechat-network-cryptosystem/ It mostly revolves around a simple challenge-response protocol. An identity on Beechat is defined as a Dilithium signature keypair. The username is the BLAKE3 hash of the public key. Kyber512 is used to establish AES-256 encrypted conversations and a new Kyber keypair is used with each user. A typical key exchange takes about 2-5 seconds at the standard 9600 baud.

markqvist commented 1 year ago

Yeah, I see that a key exchange method based on Kyber-512 was implemented in https://github.com/BeechatNetworkSystemsLtd/BeechatNetwork-Android/commit/d343d2e5e176dad076f8612c528f525044538efc, but nowhere is the exchanged key actually used to set up an AES cipher.

As far as I can see, the keys are stored in the apps database, but the stored keys are never used to actually encrypt messages.

There also seems to be some problems regarding forward secrecy, in the way the key exchange scheme is implemented, but I didn't go to much into detail with that when I couldn't find the actual encryption implementation.

markqvist commented 1 year ago

Or maybe I have just gone blind ;) Can you point me to where in the code the messages are encrypted with AES-256?

BeechatNetworkSystemsLtd commented 1 year ago

AES is part of the reference Kyber implementation, so the AES code lies within the Kyber codebase.

For example: https://github.com/BeechatNetworkSystemsLtd/BNS-CryptoLib/blob/master/modules/kyber/arm/ref/aes256ctr.c

markqvist commented 1 year ago

Sure, there is an AES implementation in that library, but just having an AES-256 function in a library somewhere does not encrypt anything, as I am sure you know ;) You need to actually call those functions with the data you need to encrypt.

The Beechat app never once uses AES encryption or decryption methods from that library, as far as I can see.

Messages are not encrypted :(

BeechatNetworkSystemsLtd commented 1 year ago

Messages are indeed encrypted. Our app does not need to call AES as Kyber calls it to generate the shared secret. Feel free to test it out for yourself in our Python wrapper.

markqvist commented 1 year ago

Creating a shared secret does not encrypt a message. Kyber-512 cannot encrypt anything by itself.

Our app does not need to call AES as Kyber calls it to generate the shared secret.

I don't understand this sentence, would you mind specifying when and why your Kyber-512 implementation calls AES to generate a shared secret? To me that sounds completely meaningless, but maybe this crypto system that you have made is just completely over my head, or I am missing some detail somewhere.

As far as I can see, all message data leaves the users device completely unencrypted.

ChatScreen.java, line 255:

message = inputField.getText().toString();
[...]
Message m = new Message(Packet.Type.MESSAGE_DATA, message.getBytes());
m.send(SplashScreen.myXbeeDevice, remote, SplashScreen.hasher);

Message.java, line 91:

public void send(XBeeDevice dev, RemoteXBeeDevice remote, Blake3 hasher) throws XBeeException {
    int packetRemain = result.length % Packet.getMaxLen();
    int packetCount = result.length / Packet.getMaxLen() + (packetRemain != 0 ? 1 : 0);
    byte[] bs = new byte[Packet.getMaxLen()];

    for (int i = 0; i < packetCount; i++) {
        packetRemain = result.length - i * Packet.getMaxLen();
        if (packetRemain < Packet.getMaxLen()) {
            bs = new byte[packetRemain];
        } else {
            packetRemain = Packet.getMaxLen();
        }
        System.arraycopy(result, i * Packet.getMaxLen(), bs, 0, packetRemain);
        byte[] toSend = new Packet(
            this.type
          , (int)i
          , (int)(packetCount)
          , bs
          , hasher
        ).getData();

        if (remote != null) {
            dev.sendData(remote, toSend);
        } else {
            dev.sendBroadcastData(toSend);
        }
    }
}

Edit: And just to be verbose here, dev is a reference to an XBeeDevice instance created via the XBee Java/Android SDK, which means that the purpoted AES-256 encryption would somehow need to be handled in the XBeeDevice class, which it does not do by standard, and I see no modifications to the class anywhere that would hack in this functionality.

Plaintext message data from user input field reaches the XBee device API unencrypted.

Messages are sent unencrypted.

markqvist commented 1 year ago

Looking at your code again, and mulling this over a bit more, I really encourage you to re-open this and investigate the issue.

Call me old-fashioned, but being able to point to the specific lines in your code where the claimed AES-256 encryption is taking place should be a very easy thing to do for the apps own maintainers/developers.

While I am completely open to the possibility that I have gone blind and dumb, and just can't locate the encryption calls, right now it is really not looking that way. You seemingly can't locate them either. Are they really there?

Just rejecting this with a "messages are indeed encrypted", when you can't even link to where that encryption is taking place looks really disconcerting from the outside, for something that claims to offer "post-quantum security".

The code path I posted above is not very complex, and pretty much proves that message text input by the user leaves the app (and thereby the users device) unencrypted. This should definitely not be happening.

I came across your system by chance and found it interesting enough to look into your implementation, which then lead to me discovering the seeming lack of encryption. I really just want to help you out here.

simonows commented 1 year ago

@markqvist This is my mistake. I stashed a couple of lines during debugging and then updated the branch. The key exchange mechanism works. After pairing both devices have the same key and it is not difficult add .doFinal() call into the project. I will update the repository today. Thank you for your vigilance!

markqvist commented 1 year ago

No problem @simonows, glad you see it :) I thought it was problably something like that which had happened. Looking forward to trying this out in the future.

I don't know at what level you have launched this to the public, but at this point it, notifying your users/customers that this issue existed, and that their messages have left devices unencrypted so far, would probably be the right thing to do.

Btw, unrelated question, but does the app work with any XBee radios? I might have some lying around somewhere, and could probably hack together a board just for testing. I see your "official" radios are out of stock on your page. Do you put any special configuration on them, or are they just in default XBee DigiMesh mode and ready to go?

BeechatNetworkSystemsLtd commented 1 year ago

Thanks, Mark, appreciate it! Yes indeed, it works with any XBee DigiMesh radio as we're using the XBee API.

markqvist commented 1 year ago

Interesting, thanks! I'll see if I can dig up a couple of radios. Do you know when your own radio modules with USB-C will be back in stock?

BeechatNetworkSystemsLtd commented 1 year ago

Please send an email at sales@beechat.network for an estimate. Best regards, The Beechat team