Convert .key formatted private key into .pem format with python3 - python

I am trying to convert .key formatted private key into .pem formatted key using python3. Before using python3 I was able to convert private key into .pem format by simply running openssl command as:
openssl rsa -in <private_key_file> -outform PEM -out <new_file>
I would like to know how people are using python3 to convert it private keys into .pem or other formats. So far I've tried running subprocess.run() command to execute openssl command from python. It would be nice to know if there is python way of converting into .pem format.
I also tried following using pycryptodrome library https://pycryptodome.readthedocs.io/en/latest/index.html as per this thread pyOpenSSL creating a pem file which creates in pem format but wasn't successful.
def convert_key_to_pem_format(key_file):
print("Converting to pem/rsa format")
pv_key_string = key_file.exportKey()
with open ("private.pem", "w") as prv_file:
print("{}".format(pv_key_string.decode()), file=prv_file)
This is my code. Any help would be appreciated.

From the Cryptodome library, you can use the import_key method, which supports the following formats for an RSA private key:
PKCS#1 RSAPrivateKey DER SEQUENCE (binary or PEM encoding)
PKCS#8_ PrivateKeyInfo or EncryptedPrivateKeyInfo DER SEQUENCE (binary or PEM encoding)
Here's how you could use it:
from Cryptodome.PublicKey import RSA
key = RSA.import_key(open('private.key', "rb").read(), passphrase="(passphrase in case you have one)")
pv_key_string = key.exportKey()
with open ("private.pem", "w") as prv_file:
print("{}".format(pv_key_string.decode()), file=prv_file)

Related

Decoding EC keys into Binary Format

I'm trying to write a python function that will take a PEM formatted private key file and convert it into the raw binary representation, similar to what the following openssl function does:
openssl ec -in ec_private.pem -noout -text
read EC key
Private-Key: (256 bit)
priv:
7a:f6:73:2f:58:1d:00:5a:fc:f2:16:f6:38:5f:f6:
37:10:29:24:2c:c6:08:40:dd:7d:2a:7a:55:03:b7:
d2:1c
pub:
04:11:5b:3f:a3:9f:ae:41:b4:e3:2f:77:21:ca:72:
f8:c1:78:14:83:64:7d:ab:d5:14:f0:8e:66:12:8b:
d4:7f:ce:90:67:b9:0e:04:88:c9:c2:a9:f3:0f:5a:
26:6a:07:84:1d:6c:07:74:13:ba:07:e7:45:69:b9:
9d:4f:d3:ce:c6
ASN1 OID: prime256v1
NIST CURVE: P-256
But with the priv key formatted as a more code friendly format, like so
0x7A, 0xF6...
I've been trying to use the pyOpenSSL library, cryptography library, and PyNaCl libraries without any success.
Is there a way to do this, or do I have to write a wrapper around the command line function that does this formatting for me?
Thanks!
I ended up just doing the wrapper around the openssl system library:
import os
def convert_key(keyfile):
stream = os.popen('openssl ec -in {} -noout -text'.format(keyfile))
output = stream.read().strip()
keylines = output.splitlines()
keystring = keylines[2].strip() + keylines[3].strip() + keylines[4].strip()
formatted_key = "0x" + keystring.replace(":", ", 0x")
return formatted_key
Which is a likely very brittle way to create the desired outcome, but I can't find a more pythonic way to do it.

Download.pfx certificate from Azure KeyVault with Python

I've imported a valid .pfx certificate into a keyvault in Azure. When I try to download it with Python using the SecretClient object, I get a value with no "BEGIN CERTIFICATE" or "END CERTIFICATE" footer. My understanding is that this value should contain the public certificate and private key, but I can't seem to convert this string value into anything I can then use or read with openssl.
I can download the certificate fine with az keyvault secret download and then read it correctly with openssl
I've tried writing the string to a file and manually adding headers etc. but I feel I am missing something fundamental. The example I've seen here: https://github.com/Azure/azure-sdk-for-js/issues/7647 appears to show the value being directly written to a file and read with openssl. This does not work for me and I get the following error:
error:0D07803A: asn1 encoding routines : ASN1_ITEM_EX_D2I : nested asn1 error
So the fundamental question is: how to convert KeyVaultSecret.value into an x509 object or how to write it to a file in such a way that openssl can succesfully read it
Error was in converting to base64. Code below for future interested parties:
import base64
from azure.keyvault.secrets import SecretClient
secret = SecretClient(keyvaulturl,credentials)
secret_b64 = base64.b64decode(secret.value)
with open('test.pfx','wb') as fopen:
fopen.write(secret_b64)
This can be interrogated with openssl succesfully.

Reading the certificate of PKCS#7 Signed Data using pure python

There is already a lot of questions out there but the problem is, none of them have sufficient answers how to do it, especially when using python3.
Basically, I want to read JAR/APK certificates, like this one: Link to ASN1 Decoder, with Android Test Signing Key
There are now several alternatives:
pyasn1: seems to work, but only can parse the raw ASN.1 format
M2Crypto: only works on py2
Chilkat: Not free, although CkCert seems to be free
cryptography: Can not load the certificate, as the X509 certificate is inside the PKCS#7 container
I found a way to use pyasn1 to unpack the cert from the pkcs#7 message, then use cryptography to read it:
from pyasn1.codec.der.decoder import decode
from pyasn1.codec.der.encoder import encode
from cryptography import x509
from cryptography.hazmat.backends import default_backend
cdata = open("CERT.RSA", "rb").read()
cert, rest = decode(cdata)
# The cert should be located there
realcert = encode(cert[1][3])
realcert = realcert[2 + (realcert[1] & 0x7F) if realcert[1] & 0x80 > 1 else 2:] # remove the first DER identifier from the front
x509.load_der_x509_certificate(realcert, default_backend())
which gives
<Certificate(subject=<Name([<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.6, name=countryName)>, value='US')>, <NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.8, name=stateOrProvinceName)>, value='California')>, <NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.7, name=localityName)>, value='Mountain View')>, <NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.10, name=organizationName)>, value='Android')>, <NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.11, name=organizationalUnitName)>, value='Android')>, <NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value='Android')>, <NameAttribute(oid=<ObjectIdentifier(oid=1.2.840.113549.1.9.1, name=emailAddress)>, value='android#android.com')>])>, ...)>
Is there no other way to have it clean and tidy?
There are now libraries to do this in pure python. One is asn1crypto: https://github.com/wbond/asn1crypto#readme
This is also impemented in androguard, including examples how to use it: https://androguard.readthedocs.io/en/latest/intro/certificates.html

RSA decrypt returns extra data

I can decrypt some data encrypted via openssl command line tool, but some 'extra' data is returned with the original data.
I've created a encrypted file like this:
$ echo this is it >file.txt
$ openssl rsautl -encrypt -pubin -inkey public.pem -in file.txt -out encrypted.txt
And I can access the original data with:
from Crypto.PublicKey import RSA
key = open('/tmp/.private.key').read()
rsakey = RSA.importKey(key, 'MyPassphrase')
data = open('/tmp/encrypted.txt', 'rb').read()
original = rsakey.decrypt(data)
But some extra data is returned and the output is something like this:
\x02h\x83\xcfx\x84,\xb1\xa6 [...] \xcf5\x9f\xbbG\xf1\x14\xd0\x8d\x1f\xfe\x9c4\xbb\x1aB\xfa\xc3b\xc2\xe0K\x85\xb5\x10y\xe1\x8e\x00this is this\n
Can I avoid to receive this raw data before the decrypted data?
Obs.: The keys were created with openssl tool
Tks.
You are getting PKCS#1 v1.5 padded plaintext back. You need to remove the PKCS#1 v1.5 padding first. Currently you are performing textbook (or "raw") RSA decryption, which is little more than modular exponentiation. Try a PKCS#1 v1.5 capable class instead, like this one

How to encrypt a file with python but can be decrypted using the shell?

I need to encrypt a file, send it to another person, who then can only decrypt it using shell.
I usually encrypt the file with the openssl command: openssl enc -aes-256-cbc -salt -in [filename] -out [file out name] -pass file:[direct path to key file], then send the file.
The other person then would decrypt the file again with the openssl command: openssl enc -d -aes-256-cbc -in [encrypted file] -out [file out name] -pass file:[direct path to key file]
I would use os.system to do this, but I feel like there has to be another way to encrypt the file with python which then could be decrypted on the shell side.
Do you need to use openssl?
I use command line GnuPG and there is very nice Python library: python-gnupg . It is a wrapper over command line gpg so they work simply the same.
Instead of key file (I think it contains password) you can use asymmetric cryptography. Create private/public pairs of keys for each part and then encrypt message using recipient public key and sigg it using sender private key. Recipient will check signature of sender using sender public key and recipient will decrypt message using her private key. Private keys can be protected by password but if you are sure your environments are safe you can use empty passwords.

Categories