pyca / pynacl

Python binding to the Networking and Cryptography (NaCl) library
https://pynacl.readthedocs.io/
Apache License 2.0
1.06k stars 233 forks source link

How to do curve25519 ECDH with pynacl #720

Closed Sorunome closed 2 years ago

Sorunome commented 2 years ago

Hello, I am having trouble trying to use curve25519 ECDH with pynacl. Looking at the docs i'd want to invoke Box.shared_key, however, while consistent within pynacl, it does not seem to be consistent with other curve25519 implementations.

Given the following example code:

import donna25519
import nacl
from base64 import b64encode
from nacl.public import PublicKey, PrivateKey, Box

key_1 = donna25519.PrivateKey().private
key_1_pub = donna25519.PrivateKey.load(key_1).get_public().public
key_2 = donna25519.PrivateKey().private
key_2_pub = donna25519.PrivateKey.load(key_2).get_public().public

print('==== donna25519 exchanges ====')
print(b64encode(donna25519.PrivateKey.load(key_1).do_exchange(donna25519.PublicKey(key_2_pub))))
print(b64encode(donna25519.PrivateKey.load(key_2).do_exchange(donna25519.PublicKey(key_1_pub))))

print('==== pynacl exchanges ====')
print(b64encode(Box(PrivateKey(key_1), PublicKey(key_2_pub)).shared_key()))
print(b64encode(Box(PrivateKey(key_2), PublicKey(key_1_pub)).shared_key()))

Yields, for example, the following output:

==== donna25519 exchanges ====
b'NdlG6AGHHJkSAyQPPSymOudRUKSaBYY+mNR83LYlHF4='
b'NdlG6AGHHJkSAyQPPSymOudRUKSaBYY+mNR83LYlHF4='
==== pynacl exchanges ====
b'XdvkoERaaCWVmyWQ4Ek0EDf7oG1nGBrWLWgXw//M7g0='
b'XdvkoERaaCWVmyWQ4Ek0EDf7oG1nGBrWLWgXw//M7g0='

Of course the exact keys will be different every time it is run, but the important thing to note here is that the donna25519 exchange yields a different result from the pynacl result. The donna25519 one seems to be the correct one for just ECDH, though. Does shared_key do more than just ECDH? How could I use just ECDH with pynacl?

reaperhulk commented 2 years ago

shared_key ultimately calls crypto_box_curve25519xsalsa20poly1305_beforenm, which does not just perform an ECDH scalarmult operation: https://github.com/jedisct1/libsodium/blob/6d566070b48efd2fa099bbe9822914455150aba9/src/libsodium/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c#L35

If you're just looking for ECDH with curve25519 that's generally called X25519. cryptography has native APIs for this, but I think in PyNaCl you can do the scalarmult yourself if needed.

Sorunome commented 2 years ago

Great, thank you for the insight and the pointers, this helped a lot!