1

I'm curently working on a project were i need to compute an hkdf symetric key. To do that i need to generate a shared secret from the private key and an ephemeral public key.

For the rest of my work i did use pycryptodome but i can't find in the doc if it allow generation of shared secret. I saw in the futur plan their intention to add Elliptic Curves (ECIES, ECDH) since ecdh is based on shared key it wouldn't be suprising if shared key generation is not implemented yet.

I tried using the cryptography lib too but impossible to load my ephemeral key.

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec

def __compute_shared_secret(ephemeral_public_key: bytearray) -> bytes:
    client_public_key = serialization.load_der_public_key(ephemeral_public_key)
    server_private_key = serialization.load_der_private_key(b"my_private", password=None)
    shared_secret = server_private_key.exchange(ec.ECDH(), client_public_key)
    return shared_secret
Could not deserialize key data. The data may be in an incorrect format or it may be encrypted with an unsupported algorithm.

ephemeral_public_key is base64 encoded and given by the gpay api.

i would like to know if i can do it with pycryptodome and if not if using the cryptography lib only for this part is a good idea.

Bastien B
  • 1,018
  • 8
  • 25
  • 2
    _PyCryptodome_ does currently not implement ECDH, so you need another library. _Cryptography_ is an option. The bug is, as the error message already says, probably caused by a wrong encoding or format. `load_der_public_key()` expects a DER encoded key, i.e. you should Base64 decode the key. If the key is PEM encoded there is also `load_pem_public_key()`, check the documentation (_Key Serialization_). But without a sample key, much more can not be said about this. – Topaco Nov 23 '21 at 11:37
  • Thanks for your reply, my imput is a public key in bytearray from an ec prime256v1 private key. example b64encode(): b'BGMXZBK2aDlWXfR89wHq9DMIG6WL7kxpsUWKjJlH1CxjpsaN4Sdp55wKMhLlCpM4TbOtkLpIRQT179GKZZB0Knw=' i did try load_der and load_pem but it doesn't work, Does it need header and footer like a real pem file ? – Bastien B Nov 23 '21 at 13:37
  • 1
    This is a raw key in uncompressed format: 0x04|x|y and not in X.509/SPKI format (i.e. neither PEM nor DER). – Topaco Nov 23 '21 at 14:05
  • 1
    S. [here](https://stackoverflow.com/a/67221788/9014097) for importing an uncompressed key with _Cryptography_. You have to use `base64.b64decode()` instead of `base64.urlsafe_b64decode()` though. secp256r1 is an alternative name for prime256v1 or NIST P-256 and fits. – Topaco Nov 23 '21 at 14:21
  • yes thank you for your help, juste the loading of the private key that i use that i don't like. I would have prefer to load it as PKCS #8 rether that a pem file. – Bastien B Nov 23 '21 at 17:42

1 Answers1

1

With help of @Topaco i ended up making this function:

from cryptography.hazmat.primitives.asymmetric.ec import ECDH
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1
from cryptography.hazmat.primitives.serialization import load_pem_private_key

def __compute_shared_secret(ephemeral_public_key: bytes) -> bytes:
    curve = SECP256R1()
    public_key = EllipticCurvePublicKey.from_encoded_point(curve, ephemeral_public_key)
    server_private_key = load_pem_private_key(b'<private_key>', password=None)
    shared_secret = server_private_key.exchange(ECDH(), public_key)
    return shared_secret

It work juste fine

Bastien B
  • 1,018
  • 8
  • 25