Migrate to a cross-platform, well-established crypto library
Closed this issue · 5 comments
Currently we are using python-ecdsa for the DH operations, while we are using libsodium for the symmetric encryption. We originally chose a native python library so that we could edit and debug the crypto primitives. With the recent changes, and the protocol now using only established and available primitives, we should be able to use libsodium (or even openssl) only.
A lot of porting is already in the libsodium-only branch.
Currently, the message fetching mechanism does not work: I tried to implement it using only the higher level functions in the following way:
re = nacl.public.PrivateKey.generate()
me = nacl.public.PrivateKey.generate()
jc = nacl.public.PrivateKey.generate()
nacl.public.Box(re, nacl.public.PublicKey(nacl.public.Box(me, jc.public_key).shared_key())).shared_key() == nacl.public.Box(jc, nacl.public.PublicKey(nacl.public.Box(re, me.public_key).shared_key())).shared_key()
However, the comparison returns False
, meaning that the server and the fetching party are currently not able to compute the same shared secret. It can be worth investigating why, or try to implement the mechanism using the lower level crypto_scalarmult().
Edit: it is probably because the result of the multiplication is hashed or expanded (with also other parameters) before the usage in Box, losing the commutative property of DH.
import nacl.bindings.crypto_scalarmult as scalarmult
re = nacl.public.PrivateKey.generate()
me = nacl.public.PrivateKey.generate()
jc = nacl.public.PrivateKey.generate()
assert(scalarmult(re.encode(), scalarmult(me.encode(), jc.public_key.encode())) == scalarmult(jc.encode(), scalarmult(me.encode(), re.public_key.encode())))
assert(nacl.public.Box(re, nacl.public.PublicKey(scalarmult(me.encode(), jc.public_key.encode()))).shared_key() == nacl.public.Box(jc, nacl.public.PublicKey(scalarmult(me.encode(), re.public_key.encode()))).shared_key())
The manual version seems to work, even if just in the intermediate step.
With 41594ec the core parts now fully work with libsodium only. Also we can drop both ecdsa
and gmpy2
as requirements.
Just realized that libsodium crypto-box automatically sign the messages that it encrypts. While we might want to do that from journalist->source, we probably do not want that on submission as it provides non-repudiability, which in case of a source it is not a desirable property.
I have ported the server to OpenResty, using luasodium
. Reusing the same bindings in different languages is quitye fast, even if there are sometimes syntax or abstraction differences. For istance, luasodium
always expects a nonce and expect the programmer to share it, while PyNaCl
automatically does that and assume the nonce is prepended to the ciphertext.
https://gist.github.com/lsd-cat/721313dc54578f04553ffa9c39852f9d