Convert PEM file to DER

Viewed 14686

I am currently trying to write a script that allows me to compute the Tor HS address from the hiddens service's private key file. In order to do this the file needs to be brought into the DER format.

Using OpenSSL this can be done with:

openssl rsa -in private_key -pubout -outform DER

Piping this into python with:

base64.b32encode(hashlib.sha1(sys.stdin.read()[22:]).digest()[:10]).lower()'

will return the address correctly.

However I would like to perform the same using only python. My problem is that using the pycrypto module the DER output is different and the address therefore incorrect.

key = RSA.importKey(keyfile.read()).publickey()
print(key.exportKey(format='DER'))

Will result in a different output than the openssl call. Is this just a matter of implementation that allows different results? Or am I making a mistake somewhere?

Any help would be appreciated

4 Answers

I was looking for something similar and, as of March 2019, OpenSSL recommends using pyca/cryptography instead of the crypto module. (source)

Here after is then what you intend to do: convert PEM to DER

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization

with open("id_rsa", "rb") as keyfile:
    # Load the PEM format key
    pemkey = serialization.load_pem_private_key(
        keyfile.read(),
        None,
        default_backend()
    )
    # Serialize it to DER format
    derkey = pemkey.private_bytes(
        serialization.Encoding.DER,
        serialization.PrivateFormat.TraditionalOpenSSL,
        serialization.NoEncryption()
    )
    # And write the DER format to a file
    with open("key.der", "wb") as outfile:
        outfile.write(derkey)

I want Convert Certificate file not the key file from DER to PEM, but Google took me here. thanks @alleen1's answer, I can convert certificate or key from DER to PEM and vice versa.

Step one, load the file.

Step two,save it to the format you want.

I ommit the process to get the "pem_data" and "der_data",you can get it from file or anywhere else. they should be bytes not string, use method .encode() when needed.

from cryptography import x509
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend

# Step one, load the file. 

# Load key file
# PEM 
key = serialization.load_pem_private_key(pem_data, None, default_backend())
# DER
key = serialization.load_pem_private_key(der_data, None, default_backend())

# Load cert file
# PEM
cert = x509.load_pem_x509_certificate(pem_data, default_backend())
# DER
cert = x509.load_der_x509_certificate(der_data, default_backend())

# Step two,save it to the format you want.
# PEM key
key_val = key.private_bytes(
              serialization.Encoding.PEM,
              serialization.PrivateFormat.TraditionalOpenSSL,
              serialization.NoEncryption()
          )
# DER key
key_val = key.private_bytes(
              serialization.Encoding.DER,
              serialization.PrivateFormat.TraditionalOpenSSL,
              serialization.NoEncryption()
          )

# PEM cert
cert_val = cert.public_bytes(serialization.Encoding.PEM)
# DER cert
cert_val = cert.public_bytes(serialization.Encoding.DER)

The inital question is: "Exact the public key from private key", this because the openSSL command states "pubout" in initial question.

Using OpenSSL this can be done with: (note that "pubout" defines OUTPUT as public key only)

openssl ALGORITHM_USED -in private_key -pubout -outform DER

But with Python cryptography module you can exact the public key from private key (note this seems applicable for RSA and EC based cryptography).

With Python:

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

    # Create private key (example uses elliptic curve encryption)

    priv_key = ec.generate_private_key(ec.SECP256K1, default_backend())

    pub_key = priv_key.public_key()

    pub_key_pem = pub_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
        )

    with open('public_key.pem', 'wb') as outfile:
        outfile.write(public_key_pem)

More info on cryptography documentation: https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ec/#cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey

Related