(For everyone else: just because I'm playing along with this misissuance scenario doesn't mean I don't think ~everyone should trust WebPKI.)
> that’s much safer than using public key cryptography.
It's much harder to screw up than using PKC (thereby making it safer). It's something that is really important for UX - you want to make the easiest path the safest path.
Mail is another option, depending on how secure you think that is.
Cryptography is often not about "uncrackable" but about confidence in security over a foreseen interval.
On the 4th of June 1943 the details of Operation Neptune ("D-Day") were a priceless secret of the Allied Command, a break that allowed Berlin to know the plan could have resulted in the invasion force being expected by a heavily prepared and well-reinforced German defence. Those who made it back to England alive would have no reward for their efforts.
By the 7th of June 1943 plans for Neptune were a historical curiosity of little military value.
And I did mean Neptune, the Overlord plans would have remained valuable for several weeks as they included details of the immediate objectives in Normandy and how resupply would be done, Neptune was just the invasion and related actions.
However, just because you have a channel that can't be MitM-ed doesn't mean you can actually trust whoever is on the other end. The problem of "how do you know you trust the other end" requires some foundational source of trust, whether that's trusting the transportation medium (that the person you handed the USB key to is actually who he/she claims to be), the issuer (could be yourself), and so on.
Considering it took me 8 months to not even finish my own, making several serious mistakes in the process, even though I wrote my own goddamn crypto library and am standing on Noise's shoulders…
I tend to agree.
That said, we still have a problem: `crypto_box()` is nice, but it doesn't have any kind of forward secrecy, identity hiding, or key compromise impersonation resistance. Sure, offline protocols can't really have that (the best you can do is use signatures to avoid the key compromise impersonation issue, but then you loose some deniability). Online protocols however, can.
But then what do we do? We could use Noise, (the Noise explorer now generates code in several languages), but you at least have to chose a pattern. Which one? How can you even notice that XK1 maximises client anonymity, and IX (properly used) maximises server security? Even if you know that, which are you going to use?
And I'm not even talking about implementing your Noise pattern, should existing implementations not suffice (maybe you want to leverage a custom crypto library optimised for some embedded processor). Noise isn't simple. A serious drawback in my opinion.
This, if I guess correctly, is what led you to recommend that horror that is TLS for client/server security. Because the burden of choosing a reasonable TLS library, of properly configuring that TLS library to only use TLS 1.3 with a limited set of ciphers (possibly just Curve25519 and ChaPoly)… still remains less error prone than picking up a Noise protocol. <PKI matters conveniently left out>
That situation is deeply unsatisfactory. It's all well and good to tell people "don't make your own kex", but if you don't at the same time point them to an existing kex, they will be less likely to follow your advice. I mean, I didn't.
The confusion is that IES/ElGamal sometimes means a family of systems and sometimes someone literally means FFDH + AESCTR or something. The abstract concept is fine, but you should use a hardened implementation.
To answer your specific comments: firstly, you don't need public key crypto. If both you and your sender can agree on a secret key, you can use secret key crypto just fine. For that, use libsodium's secretbox.
If you really need public key crypto for some reason, libsodium's box is what you want.
What's the "untrusted channel" here? Is this really about encryption in transit, or encryption at rest?