FiSH/SMP update/notes/observations:
FiSH uses NOTICE for the key exchange, so it needs both NOTICE and PRIVMSG to work. I can understand why this was chosen at the time but if I was going to implement it today, for an IRC client, just using a PRIVMSG would make more sense and perhaps CTCP, which was designed for direct client-to-client messages to distinguish them from normal messages. OTR, for example, sends a PRIVMSG with the ?OTR? prefix, so everything takes place in the same message context. This format could then also have been used in DCC Send/Chat.
Another issue is that a NOTICE is usually meant to get attention. An unrecognized CTCP message is often just printed quietly in the server window. If a non-keyexchange/encryption supporting client receives an unrecognized NOTICE, this will be a lot more annoying than a CTCP message. This is important because one of the FiSH features that can be enabled is to send a key exchange request automatically if a user tries to message you and you do not have keys set up for them.
Another issue is that with the current protocol, the initiating client sends DH1080_INIT and the receiving client sends DH1080_FINISH. For any number of reasons, the initiating client may reject the DH_1080_FINISH, causing the key exchange to fail, but only they will know this. The receiving client can only assume that everything went well. It would have made sense for the initiating client to send one more DH1080_FINISH as a final confirmation. From a user point of view, the initiating client will print "*** Key exchange: successful" or "*** Key exchange: fail". The receiving client can only display "*** Key exchange: sent reply" without confirmation of success. That said, at worst (assuming this wasn't an intentional failure/downgrade forced by an MITM), the receiving client will send encrypted messages that the sending client cannot decrypt.
FiSH uses named events DH1080_INIT / DH1080_FINISH for key exchange. To add a new key exchange method, we have to add more named events, eg. X25519_INIT / X25519_FINISH (like some newer FiSH implementations). It might have been better to use a generic named event such as FISH_INIT/FISH_FINISH which could then be used to negotiate both key exchange and encryption methods. Or just an OTR-style prefix like ?FiSH?. As it is, I have added new X25519_INIT / X25519_FINISH events. But this means that we will need to add even more events if we want to add new key exchange / encryption methods. Ideally, FiSH would be updated to use a new, forward-looking key exchange / encryption protocol but this would break backward compatibility.
One other option is to just extend DH1080_INIT. We can avoid adding more events and just treat the DH1080_INIT / DH1080_FINISH as generic events. A client can send DH1080_INIT as usual but append tags, such as X25519 CHAHCA20-POLY1305 AES-GCM, to the message, just like "CBC" is appended currently. If a client wants to use a particular encryption method, it includes its tag in the reply to DH1080_FINISH. If it wants to use a different key exchange method, it can restart the key exchange by replying with DH1080_INIT X25519, and the initiating client will resend DH1080_INIT with an X25519 key. As far as I can see, this should be fully backward compatible while supporting new key exchange / encryption methods. At the cost of being a bit of a hack :-]
SMP notes:
Socialist Millionare Protocol (SMP) requires five steps of back and forth messages and I had to choose to use either NOTICEs or PRIVMSGs. Ideally, this would have used CTCP PRIVMSGs but seeing as FiSH uses NOTICE for key exchange, I have opted for NOTICE as well. One thing to note is that FiSH encrypts PRIVMSGs by default post-key exchange but not NOTICEs. Technically, SMP does not need to be encrypted. I created new events SMP_INIT / SMP_REPLY / SMP_FINISH. SMP uses the group 2 1536-bit prime from RFC 3526, which is 192-bytes long. During the SMP exchange between clients, each message can be much longer the standard 512 byte limit. So this requires multiple NOTICEs per message, each containing part of the encoded message, that are assembled at the end of that sequence to be used in that SMP computation step. Since SMP requires five steps, each of which need 2-5 NOTICEs to transmit the full line, the total number of NOTICEs sent can be fifteen or more. That's... not great.
Note that this is different to how OTR uses SMP. OTR first creates private/public DSA keys that it then uses to establish long-term identification of parties and binding/signing of the initial session (Trust On First Use) and securing the SMP (if the user chooses to use it by verifying a secret) to prevent MITM. In mIRC's case, we are not generating private/public keys and the SMP is not secure - an MITM could simply pass it unchanged between parties to make us think they are not there. What SMP does, even with MITM, is verify a shared secret. I could add support for DSA keys but, at that point, I would essentially be re-inventing OTR. Considering that I was only planning on adding support for FiSH...
An alternative to SMP: CPace, which is a recommended modern balanced PAKE, that integrates authentication with key exchange, and requires fewer messages/steps than SMP. A user supplies a password, the key exchange is initiated, the other user supplies a password, if they match, both key exchange and authentication complete and the keys are secure. The difference here is that users are required to perform password authentication from the start. With OTR, authentication with SMP is optional after key exchange, to make the process user-friendly. Technically, we could still implement this as 1) perform a normal DH1080 key exchange without password authentication, which is susceptible to MITM and then 2) allow password authentication using CPace which guarantees secure keys.
Perhaps establishing a well thought out, standardised protocol for key exchange / encryption negotiation for IRC clients might be something for IRCv3.
Using SMP/CPace leads to another issue: these require the receiving client to answer a question to complete verification. A dialog suddenly popping up in your client on request from another user is probably not a good idea, so this needs to be implemented in a way that can't be spammed but is easy for non-techies to use. The developers of OTR already went through this entire process and published papers about it. The Pidgin OTR plugin adds visual cues/buttons to the chat window to let a user know that their chat is/is not secure/verified. I have intentionally tried to keep mIRC's GUI/windows minimalist / unencumbered by visual weight (which admittedly is not user-friendly - I expect most users have to be told that they can find window settings in the System menu), so adding a secure/verify visual button/cue to a query/chat window is going to be a challenge - there is no point in adding it if it isn't at least a little bit annoying and doesn't stand out. Users have to know that their session, even though encrypted, is actually not secure.
In any case, I am currently working on a CPace implementation.
Last edited by Khaled; 29/03/26 06:57 PM.