Similar to this:
gnupg: There is no assurance this key belongs to the named user
But I want to set the trust level of an imported key pair within Python. Is this possible? And if so, how?
At the moment after trying to encrypt a file with the public key, I'm receiving the message:
"There is no assurance this key belongs to the named user\r\n[GNUPG:] INV_RECP 10 TestUser#Company.Com\r\n[GNUPG:] FAILURE sign-encrypt 53\r\ngpg: [stdin]: sign+encrypt failed: Unusable public key\r\n"
This is after running the following:
with open('Test.txt', 'rb') as f:
status = gpg.encrypt_file(
f,sign=public_key_fingerprint,
recipients=private_key_recipient,
output = output_file
)
status.status returns:
'invalid recipient'
EDIT:
private_key_recipient = 'TestUser#Company.Com'
Looking at pydoc gnupg I see:
trust_keys(self, fingerprints, trustlevel)
It's not documented, but it sounds like what you want.
Related
Im trying to import a public key, read a csv file, encrypt that file and store that encrypted file in a folder/ directory. The program runs but nothing seems to be generated, created or outputed after I run the script. Any suggestions.
import gnupg
gpg = gnupg.GPG(gnupghome='./gnupghome')
key_data = open('./datafiles/public_key.txt').read()
import_result = gpg.import_keys(key_data)
encrypted_ascii_data = gpg.encrypt('./datafiles/myFile.csv', key_data, output="./datafiles/myFile.csv.gpg")
The second parameter is a list of recipients. You're passing it the key_data. If you check the the result of your call to gpg.encrypt(...), you'll see that you have:
>>> encrypted_ascii_data.status
'invalid recipient'
You need to either specify an explicit recipient (by fingerprint, email address, etc), or extract a recipient from your imported key, like this:
>>> encrypted_ascii_data = gpg.encrypt('./datafiles/myFile.csv',
... import_result.fingerprints[0],
... output="./datafiles/myFile.csv.gpg")
But this will still probably fail with:
>>> encrypted_ascii_data.stderr
'[GNUPG:] KEY_CONSIDERED ... 0\ngpg: 426D9382DFD6A7A9: There is no assurance this key belongs to the named user\n[GNUPG:] INV_RECP 10 ...\n[GNUPG:] FAILURE encrypt 53\ngpg: [stdin]: encryption failed: Unusable public key\n'
It looks like you need to set up a trust for that key. Before attempting to use the key:
gpg.trust_keys(import_result.fingerprints, 'TRUST_ULTIMATE')
Once you've done this:
>>> encrypted_ascii_data = gpg.encrypt('./datafiles/myFile.csv',
... import_result.fingerprints[0],
... output="./datafiles/myFile.csv.gpg")
>>> encrypted_ascii_data.status
'encryption ok'
I'm trying to use pgpy to decrypt a text file with a private key.
I can load the file and it seems decrypt it OK, but after decryption the contents is still a PGP Message, and the object has is_compressed=true. There is no error on decryption.
Is there a decryption flag to decompress as well? Or am I missing something basic here?
import pgpy
key, _ = pgpy.PGPKey.from_file('/path/private_key_file')
with key.unlock('passphrase') as ukey:
file_name = 'encrypted_file.pgp'
# decrypt it
enc_content=pgpy.PGPMessage.from_file(file_name)
clr_content = key.decrypt(enc_content)
# Write the content to a file
# ...
I get a warning on the decryption line: UserWarning: Message was encrypted with this key's subkey: A85C839A50F35A9A. Decrypting with that...
At this point, clr_content.is_compressed = true and str(clr_content) looks like:
'-----BEGIN PGP MESSAGE-----\n\nyP8AAOEdAnicxL3NcuPash54Oxwd0eEIv4EHGF3fG8bmwf
/PzCAIERBBgBsgpaMa\n+AQkokRskYQMkqWteol+E0d41ENHOPphet4DT5258EMSwAIgqY7PiSssct
8qVa6F\nXPmfX/6//+7f/NP/9X/8t//vP/3f699///f/9F//6d/8P//u8S/G6rfF78LfJE74\nm7H6
...
zn+3/Zud///2t+j997Uf0x940/eQbX/f6lx7656+8y/2l2k+9\n74fe/t+P/NGXPvGRr2sf+uIHHnr
tpz598PFvvf3/AYHoIHI=\n=cI/q\n-----END PGP MESSAGE-----\n'
I've tried pushing it through gzip, but didn't get anywhere.
Thanks in advance
Mike
Something like this should work:
clr_content = (key.decrypt(enc_content)).message
Having experimented a lot with this recently it seems that a decrypted PGPMessage is still a PGPMessage (obvious in retrospect) and to get the "clear" contents you need to retrieve the .message attribute of the object.
I'm trying to validate XML message signature with given public key in Python which is validated fine on a PHP code with openssl.
Here's PHP code that's working fine.
$pubKey = openssl_pkey_get_public(file_get_contents("public_key.pem"));
$xmlDoc = new DOMDocument();
$xmlDoc->load("message.xml");
$signedInfo=$xmlDoc->getElementsByTagName("SignedInfo")->item(0)->C14N(true, true);
$signature = base64_decode($xmlDoc->documentElement->getElementsByTagName("SignatureValue")->item(0)->nodeValue);
$ok = openssl_verify($signedInfo, $signature, $pubKey, OPENSSL_ALGO_SHA1);
I've found different libraries in Python to achieve this but none of them are verifying fine. I've listed the libraries and the problems I've faced on. Is there any other preferred ways to achieve this?
1. pyOpenSSL
It fails with following message: [('rsa routines', 'INT_RSA_VERIFY', 'wrong signature length')]
import OpenSSL.crypto as c
from StringIO import StringIO
import xml.etree.ElementTree as xml_et
from myapp import settings
namespace = "{http://www.w3.org/2000/09/xmldsig#}"
xml_bytes = open(settings.STATIC_ROOT + '/file/test.xml', 'rt').read()
response_xml = xml_et.fromstring(xml_bytes.encode('utf-8'))
signature_elem = response_xml.find(namespace + 'Signature')
signature_value = signature_elem.find(namespace + 'SignatureValue').text
signed_info_output = StringIO()
signed_info_tree = xml_et.ElementTree(signature_elem.find(namespace + 'SignedInfo'))
signed_info_tree.write_c14n(signed_info_output)
signed_info = signed_info_output.getvalue()
# load certificate
cert = c.load_certificate(c.FILETYPE_PEM, open(settings.STATIC_ROOT + '/file/public.cert', 'rt').read())
# verify signature
try:
c.verify(cert, signature_value, signed_info, 'sha1')
print 'success'
except Exception, e:
print 'fail'
2. M2Crypto
Tried to install M2Crypto but it fails with cannot find openssl/err.h header file. So I've installed openssl 1.1.0e and copied lib and include directories to C:/pkg directory and it throws different error like:
SWIG/_m2crypto_wrap.c(3754) : error C2065: 'CRYPTO_NUM_LOCKS' : undeclared ident ifier
And found precompiled M2Crypto msi installer but during runtime it throws following error:
ImportError: DLL load failed: The specified module could not be found.
This library seems outdated and not enough documentation available.
3. signxml
So far it's the only library that works partially for me.
Xml verification works fine but it throws error on sign: ValueError: Could not unserialize key data.
from xml.etree import ElementTree
from signxml import XMLSigner, XMLVerifier
from myapp import settings
cert = open(settings.STATIC_ROOT + '/file/public.cert', 'rt').read()
key = open(settings.STATIC_ROOT + '/file/public.key', 'rt').read()
root = ElementTree.fromstring('<xml1>12</xml1>')
signed_root = XMLSigner().sign(root, key=key, cert=cert)
verified_data = XMLVerifier().verify(signed_root).signed_xml
print verified_data
The answer to the question in the title is signxml.
It is the library designed for the stated purpose. PyOpenSSL and M2Crypto operate on lower-level objects than XML signature; verifying the latter would involve canonicalizing XML, digesting proper parts of it, and comparing the provided signature over the digest. While possible, this is not trivial and provides much space for errors. For example in your code for PyOpenSSL you do not base64-decode the signature value.
With signxml, your example is mostly correct. For verification of the signature, you do not need the private key, so the error you get is not relevant to the question. You should in general read the certificate and the key in binary, not text mode (open(filename, "rb")) - even if the files are PEM-encoded.
The following is a working example:
from xml.etree import ElementTree
from signxml import XMLSigner, XMLVerifier
cert = open("cert.pem", "rb").read()
key = open("key.pem", "rb").read()
xml_obj = ElementTree.fromstring("<Example/>")
signed_xml_obj = XMLSigner().sign(xml_obj, key=key)
XMLVerifier().verify(signed_xml_obj, x509_cert=cert)
If your XML object has been serialized and de-serialized after signing, this simplest code might be not enough; the (complicated) details are described here.
Any idea how I can use the paramiko.RSAKey.from_private_key() function?
I know there is a from_private_key_file(), but I'm interested in using a function to parse a private key (like below) and use that private key for SSHClient.
Private key (sample):
-----BEGIN RSA PRIVATE KEY-----\nMIICXgIBAAKCAIEAmfgmlY95SHXhCeBNdkhSrsG4JVbqyew845yoZRX3wcS2/doz\niVQxgx0aiOwLi+/Rnkb3PLUIwoxb/LoD/W0YMS6/NSUMt+LdH+zsjeNF2iq4rDzU\nwDSqi27q/8u/egrK7H+9HNKEVXb/87utAAm3VTM9KqKaK3VuVFrNrnsDSuECAwEA\nAQKCAIBZn3y2KiGq8BLiMNJmO4sFdnW+Jm3cw8pdo17SGItzGxJ5iX3ePkfjzhkY\nAm5mMl6OBzj6+VX0CMeywIR6C/q8HwDYSmZcuU5v76/DoW5bI6xkPrroqEz6aRE5\nyN+2hf65RD3eoPATsdrP/kxiKjZg9uG9LhgIXyVwYFs1RcqewQJBAMCVJlEYXRio\neynUtyES9HNmUGUqHKmri1FZfO56/mFdG5ZXsKE48qURCAGVxI+goGQ4vtJIXB2J\nyTEr+5qYtE0CQQDMq9/iigk+XDOa9xGCbwxbLGdPawaEivezMVdPqVzH971L6kZ8\nhEnev1DqujgGCyR+QYPW1ZCXH05FY9CqWwrlAkATzYJyJlI0XebER2ZJVVyjnSq5\nLFpkLAqYY95P23/a3SsgC4ZTHbr9tEGhgBgFONwlUhx1HRGzy95PWxl1LSylAkBk\nwP93v8gJIM5urM27zfrhLxy0ZdVRji+d0N5QYuk/r19KbcvBJEZRFxE4W++UWgve\n81V5fqytGEYptpdUJXlZAkEArxZDiT1HXXGciIgzZbh53McogPCGHiKOOPSjpM41\npneDFVvwgezCWoDauxNDzu7Nl55qPJsmvfKZ+SKvCajrhQw==\n-----END RSA PRIVATE KEY-----\n
Code I wanted to run:
import paramiko
ssh = paramiko.SSHClient()
# how do I pass in the private_key, when my private_key (shown above) is in string?
mykey = paramiko.RSAKey.from_private_key(private_key)
ssh.connect('192.168.1.2', username = 'vinod', pkey = mykey)
Many thanks.
Lev's method worked for me:
>>> import paramiko
>>> f = open('/path/to/key.pem','r')
>>> s = f.read()
>>> import StringIO
>>> keyfile = StringIO.StringIO(s)
>>> mykey = paramiko.RSAKey.from_private_key(keyfile)
>>> ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
>>> ssh.connect('myserver.compute-1.amazonaws.com', username='ubuntu', pkey=mykey)
>>> stdin, stdout, stderr = ssh.exec_command('uptime')
>>> stdout.readlines()
[' 19:21:10 up 24 days, 42 min, 1 user, load average: 0.14, 0.06, 0.05\n']
This should do it:
import io
import paramiko
private_key_file = io.StringIO()
private_key_file.write('-----BEGIN RSA PRIVATE KEY-----\nlskjdflk\n...\n-----END RSA PRIVATE KEY-----\n')
private_key_file.seek(0)
private_key = paramiko.RSAKey.from_private_key(private_key_file)
from_private_key() apparently takes a file object:
from_private_key(cls, file_obj, password=None)
Create a key object by reading a private key from a file (or file-like) object. If the private key is encrypted and password is not None, the given password will be used to decrypt the key (otherwise PasswordRequiredException is thrown).
Parameters:
file_obj (file) - the file to read from
password (str) - an optional password to use to decrypt the key, if it's encrypted
Returns: PKey
a new key object based on the given private key
Raises:
IOError - if there was an error reading the key
PasswordRequiredException - if the private key file is encrypted, and password is None
SSHException - if the key file is invalid
So to feed it a key as a string you can use StringIO, something like:
private_key = StringIO.StringIO(key_string)
mykey = paramiko.RSAKey.from_private_key(private_key)
I have not tested this, though.
Here is where 'duck typing' comes in handy - it does not have to BE a duck (=file), it just has to BEHAVE like one.
A little experimentation shows that, any object that has a valid readlines() method is fine.
I faked it with:
def myfakefile(keystring):
myfakefile.readlines=lambda: keystring.split("\n")
return myfakefile
mykey = paramiko.RSAKey.from_private_key(myfakefile(keystring))
This is incredibly hacky, but it works.
What this does, is, when you call myfakefile(keystring), it creates myfakefile.readlines, which returns the (split) contents of keystrings.
Then, it returns the function.
The same function is passed to from_private_key. from_private_key, thinking it is a file, calls myfakefile.readlines(). This calls the newly created (lambda) function, which returns the sort of thing you would expect from file.readlines() - or, close enough, anyway.
Note that, saving the results will not work as expected:
k1=myfakefile(keystring1)
k2=myfakefile(keystring2)
# This will return keystring2, not keystring1!
paramkiko.RSAKey.from_private_keyfile(k1.readlines())
There are more robust methods of getting this to work as it should, but not worth the effort - just use StringIO if your needs are more complicated.
Very old question, but in case it helps some unfortunate soul: my sol'n to this problem was to generate a new key with default options, using
ssh-keygen -t rsa
My previous key was generated using
ssh-keygen -t rsa -b 4096 -a 100
which paramiko complained about as it did for OP.
M2Crypto package is not showing the 'recipient_public_key.pem' file at linux terminal.
How do I get/connect with recipient public key.
Exactly, I need to check how can I open this file through linux commands.
import M2Crypto
def encrypt():
recip = M2Crypto.RSA.load_pub_key(open('recipient_public_key.pem','rb').read())
print recip;
plaintext = whatever i need to encrypt
msg = recip.public_encrypt(plaintext,RSA.pkcs1_padding)
print msg;
after calling the function its not giving any output and even any error
i also tried as 'Will' said
pk = open('public_key.pem','rb').read()
print pk;
rsa = M2Crypto.RSA.load_pub_key(pk)
what is the mistake I am not getting?
I have never used M2Crypto, but according to the API documentation, load_pub_key expects the file name as the argument, not the key itself. Try
recip = M2Crypto.RSA.load_pub_key('recipient_public_key.pem')