Hereās my email response to their email.
Iām Abhi, the self-proclaimed CTO of Port. Ani forwarded your email about our cryptography to me. Believe me when I say that I appreciate it more than you know. Thereās a mixture of poor communication and lack of transparency on our part as well valid criticisms. Theres a few things coming together internally, all of which I hope goes towards addressing these.
Weāre hoping to publish our source code soon, at least for the important bits.
This will help people like you hold us accountable better as well as help make it easier for us to be transparent.
Unfortunately this is taking the wrong steps towards transparent security. Itās not about being able to see whatās going into the binary and then trusting the binary blindly. Itās about being able to build the binary for yourself if you need that. Ideally, in a reproducible way. Without the possibility to compile the program oneself, all you have is something that claims to be the source code. Sure, it lets you browse around and get a sense of code smell but thatās again not enough. Proprietary security products are not accepted on e.g. Redditās /r/privacy at all. PrivacyGuides is in that boat too. Also, when everyone and their mom is already on Signal thatās fully open source, you might run into tough competition and critique if you go that route.
After our recent burst of UX fixes, I have been afforded time to go back and work on things needed to improve our core infrastructure, including out security.
OpenSSL, which we use for our cryptographic primitives, added support for a few new algorithms accepted by NIST in 3.5.0 (which is in LTS which I also like). Iāve been casually observing this unfold for a bit. This has given me further inspiration to upgrade our protocol and encryption.
Weāre reaching a point of frustration with react nativeās ability to interface with native code, leading us be frustrated by some core architectural decisions weāve made due to the limitations of our framework.
This is coming together as me rewriting the core of our app to make it easier to publish, audit and contribute to (internally as well as externally). Iām looking to improve our protocol, our responsiveness, and our background/killed state processing abilities. This is a fairly large undertaking, and Iām sure to have scope that Iām not seeing creep up on me.
So with the upstream changes in OpenSSL, some rework is planned. Thatās good to hear.
Now to respond directly to your observations:
Yes. We do not claim not, nor do implement forward secrecy. This will be changing soon.
Why not implement it properly from the get-go is a bit strange, but better late than never!
You do rightly point out that RADā == RAD =/=> not MITM. To clarify, we assume that Alice and Bob (excuse the overuse of these parties) both have good copies of the app.
Alice creates a Port and shows it to Bob, who scans it effectively transferring the Port directly from Aliceās to Bobās phone. Bob now has a peer_public_key that he will use to derive a shared secret using DH.
Ideally youād deliver a long term identity key over the QR key exchange, which is then used to sign ephemeral X25519 public keys. This gives you forward secrecy and with proper X25519 ratcheting, future secrecy (i.e. break-in key recovery).
Alice on the other hand is the party that relies on the RAD. Bob sends a message to Alice containing his public key (used for DH) as well as the RAD encrypted using the derived (not yet shared shared) secret. Alice can now mix her private key generated for the port (correlated locally with the line_link) with the peer_public_key from bob, establishing the shared part of the secret.
Using this shared secret she decrypts the ciphertext and confirms that the RAD matches the RAD she shared with Bob. Since she is certain that bob is the only one who has a copy of the plaintext RAD she generated for inclusion in her Port, she is confident that she is communicating with Bob. If a man-in-the-middle attempts to connect with Bob to steal the RAD, they would be unable to decrypt the ciphertext sent by Bob since they donāt have the private key corresponding to the public key in the Port.
Oh I see, so the RAD is a challenge the purpose of which is to allow safe key exchange in the opposite direction after a single public key QR-code is scanned in a trustworthy way. Yeah thatās a valid mechanism. (Iād like to propose opportunistic post-quantum security by also scanning a symmetric key inside the QR-code that gets mixed in. If it leaks because the user sends the QR-code over insecure medium, it doesnāt compromise all security, and if it doesnāt leak, no amount of Shor is going to break the security.)
The protocol that youāre referring to only talks about setting up an initial context that peers can then communicate over. We, at this point, just need to invalidate the Port after the first attempted use. To do so we simply mark the Port as consumed or delete it. This results in the line_link being invalidated and disallows any further uses of the public key in said Port.
If the packet(s) to form a new connection are replayed, they are ignored by the client since they will receive a line_link as part of the packet and will note that no such valid line_link exists locally.
So the port is effectively a ~one-time token allowing client to accept certain types of packets related to key exchange?
If youāre concerned about replayed encrypted messages having un-intended consequences, those are protected against one level up. Every time we decrypt a message, we find the included message_id, a UUID4. We save every message and if we detect a message being re-sent, we ignore it.
Why use UUID4 when you have to store it for every received message and perform a lookup to see if itās a used one? Wouldnāt a running counter reduce both time and space requirements? Sure, the counter tells exactly how many messages have been sent, but so does a large database of used UUID4s.
This was something we had to build I due to the nature of mobile notifications. We are pessimistic about the reliability of delivery, so we overcompensate and tend to deliver more often than we need to (most of the time).
With running counter youād also be able to detect packet drops and request re-transmission of specific packets. Hard to request UUIDs that never arrived.
The client has had to become robust at ignoring duplicates. We also canāt be super confident about in-order delivery.
Again, running counter would work better with ordered packet processing. You can cache too early packets until the one matching current counter position arrives.
As a result, we felt uneasy using an incrementing counter. Itās not the most efficient, but itās efficient enough, especially with the indices weāve set up on the local database.
Iām really puzzled about the logic here. The UUIDs have time complexity of O(n) for linear search, and O(1) when using hash maps. But UUID always has O(n) space complexity. A counter has both space and time complexity at O(1). Disk based hashmaps might work but the relocation quite expensive, even with SSDs. Why go with the UUIDs?
Our implementation is gratefully taken from OpenSSL documentation. I canāt claim to know more than the maintainers of the project. I believe we chose an AEAD scheme. Regardless, this will definitely be something we consider in this upcoming enhancement.
I find it strange you know which one you should pick (an AEAD scheme), but not that AES-CBC isnāt one. Not even with HMAC-SHA256. Youād want XChaCha20-Poly1305 or AES-GCM for that. My advice is ChaCha, as unlike AES, it doesnāt have cache timing vulnerabilities on hardware without AES-NI.
As Iāve said before, we use OpenSSL. Iāll be completely honest, I didnāt check that it implemented whitening.
Iām not well enough versed in C to say myself, but given that pyca, that has OpenSSL bindings for Python, recommends using a HKDF to ādestroy any structure that may be presentā, itās very likely OpenSSL isnāt doing the whitening by default. I wasnāt checking OpenSSL before, as your documentation The Port Protocol does not mention which libraries you are using. You should add that as it adds to your credibility. I was only checking whether you were explicitly mentioning hashing of the X25519 shared secret, which wasnāt mentioned.
I will ensure I do this when choosing my next scheme.
Hopefully Iāve answered some of your questions. Please poke more holes in our encryption and our protocol. I hope you will examine our source code when we publish it. If youāre interested, I can give you advanced access to our re-written source once Iāve fleshed it out a bit.
I like your attitude! You should really run the protocol by professional cryptographers, theyāll probably find some more. Trail of Bits and NCC Group are both solid choices.