Python RSA Decryption Using OpenSSL Generated Keys - python

Does anyone know the simplest way to import an OpenSSL RSA private/public key (using a passphrase) with a Python library and use it to decrypt a message.
I've taken a look at ezPyCrypto, but can't seem to get it to recognise an OpenSSL RSA key, I've tried importing a key with importKey as follows:
key.importKey(myKey, passphrase='PASSPHRASE')
myKey in my case is an OpenSSL RSA public/private keypair represented as a string.
This balks with:
unbound method importKey() must be called with key instance as first
argument (got str instance instead)
The API doc says:
importKey(self, keystring, **kwds)
Can somebody suggest how I read a key in using ezPyCrypto? I've also tried:
key(key, passphrase='PASSPHRASE')
but this balks with:
ezPyCrypto.CryptoKeyError: Attempted
to import invalid key, or passphrase
is bad
Link to docs here:
http://www.freenet.org.nz/ezPyCrypto/detail/index.html
EDIT: Just an update on this. Successfully imported an RSA key, but had real problem decrypting because eqPyCrypto doesn't support the AES block cipher. Just so that people know. I successfully managed to do what I wanted using ncrypt (http://tachyon.in/ncrypt/). I had some compilation issues with M2Crypto because of SWIG and OpenSSL compilation problems, despite having versions installed that exceeded the minimum requirements. It would seem that the Python encryption/decryption frameworks are a bit of a minefield at the moment. Ho hum, thanks for your help.

The first error is telling you that importKey needs to be called on an instance of key.
k = key()
k.importKey(myKey, passphrase='PASSPHRASE')
However, the documentation seems to suggest that this is a better way of doing what you want:
k = key(keyobj=myKey, passphrase='PASSPHRASE')

It is not clear what are you trying to achieve, but you could give M2Crypto a try. From my point of view it is the best OpenSSL wrapper available for Python.
Here is a sample RSA encryption/decription code:
import M2Crypto as m2c
import textwrap
key = m2c.RSA.load_key('key.pem', lambda prompt: 'mypassword')
# encrypt something:
data = 'testing 123'
encrypted = key.public_encrypt(data, m2c.RSA.pkcs1_padding)
print "Encrypted data:"
print "\n".join(textwrap.wrap(' '.join(['%02x' % ord(b) for b in encrypted ])))
# and now decrypt it:
decrypted = key.private_decrypt(encrypted, m2c.RSA.pkcs1_padding)
print "Decrypted data:"
print decrypted
print data == decrypted

Related

Python library to encrypt files with a GnuPG v1.2.1 Elgamal key

I'm developping an Azure function that can encrypt/decrypt PGP messages given a key and a message.
It works fine for most keys using pgpy library but I have a public key Version: GnuPG v1.2.1 (GNU/Linux) that I can't use with pgpy since it returns :
NotImplementedError: PubKeyAlgorithm.ElGamal
I searched for library that would support this and could not find one, so I decided to implement it on my own, as it did not look too difficult and the algorithm is well described on multiple places. (I can even use the elgamal python lib)
My problem is the key format is
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.2.1 (GNU/Linux)
mQGiBEAGBfgR...4gjeSOrg5udxZPAY=
=DeVs
-----END PGP PUBLIC KEY BLOCK-----
And I need parse it to get the base values for the elgamal algorithm:
p is an n bit prime. The probability that p is actually prime is 1-(2^-t)
g is the square of a primitive root mod p
h = g^x mod p; x is randomly chosen, 1 <= x < p
So what I have tried this far is to b64decode the key, then encode the bytes to utf8, some informations are readable most stay gibberish ..
And also I'm struggling to return ASCII armored data once I'm done encrypting my message I will have something like this :
41155426744616094260320646117097177014417149694981800076578614840250750912799 21847662953868369697518400876143332991536427661010013455083791071327058182726 25533970261208196790800768492397193896597431865219430397358207004668354954697 98474109913310069178222115337497647685706488829152682996028960479235003620264 45737203823163192128318007724696648616950141941868449765480536839812674490077 75421156343349776013489675322340893073631187437555299960920254302344648207981 109276522387603521366364233791986000982319400223147578897126930221436966076170 18488401135401021688982958133975082823772861068940759564364820322251740709188 90827265910982362637936753464357413123014385175560975236907746789761396065512 26765031632882957792087095719232883256771264945602713064106822591208103463697 5564468107973560028527296626687480799230695290490266959809792867232976049666 71244794049103052356092181781178951887799420583195494031510496299648642048011 97413323791458315049498899102961692661892266857994849672602511682865645282605 71465106552027587076817289250198631699837182375059034449765014072810202331202 97056406518631644075542549218057999306283588715133100119527104765778879761699 110485038492534789098488263918059645033722124555228757157121582934391248102132 82139266370810299307518275070745017159045416343382734826251477396790862859930 109150852725244251194053374807744808523920933876515828341771567293006328719174 97953680579504996947384453783557976134604995097882075015898175236326262555884 7295684970455413822681788097881898822060140399584227196856446892730212890655
Should I just base64encode it ?

python symmetric encryption to binary without timestamp

I want to encrypt a .zip file using AES256 in Python. I am aware of the Python cryptography module, in particular the example given at:
https://cryptography.io/en/latest/fernet/
However, I have needs that are a bit different:
I want to output binary data (because I want a small encrypted file). How can I output in binary instead of armored ASCII?
I do not want to have the plaintext timestamp. Any way to remove it?
If I cannot fix those points I will use another method. Any suggestions? I was considering issuing gpg commands through subprocess.
Looking at Fernet module, seems it encrypts and authenticates the data. Actually its safer than only encrypting (see here). However, removing the timestamp, in the case of this module, doesn't make sense if you also want to authenticate.
Said that, seems you want to risky and only encrypt instead of encrypt and authenticate. You might follow the examples of the same module found at https://cryptography.io/en/latest/hazmat/primitives/symmetric-encryption/. Just make sure this is what you really want.
As you're worried about size and want to use AES, you could try AES in CTR mode, which does not need padding, avoiding extra bytes at the end.
import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
backend = default_backend()
key = os.urandom(32)
nonce = os.urandom(16)
cipher = Cipher(algorithms.AES(key), modes.CTR(nonce), backend=backend)
encryptor = cipher.encryptor()
ct = encryptor.update(b"a secret message") + encryptor.finalize()
print(ct)
decryptor = cipher.decryptor()
print(decryptor.update(ct) + decryptor.finalize())
So, answering your questions:
(1) The update method already returns a byte array.
(2) This way there will be no plaintext data automatically appended to the ciphertext (but be aware of the security implications about not authenticating the data). However, you'll need to pass the IV anyway, what you would have to do in either case.

Decrypt cipher text encrypted with PyCrypto using cryptopp

My server encrypts files using pycrypto with AES in CTR mode. My counter is a simple counter like this:
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03
I wanna decrypt the cipher text with c++'s cryptopp library in my clients. How should I do so?
Python code:
encryptor = AES.new(
CRYPTOGRAPHY_KEY,
AES.MODE_CTR,
counter=Counter.new(128),
)
cipher = encryptor.encrypt(plain_text)
C++ code so far:
byte ctr[] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
mDecryptor = new CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption(key, 32, ctr);
std::string plain;
CryptoPP::StringSource(std::string(data, len), true, new CryptoPP::StreamTransformationFilter(*mDecryptor, new CryptoPP::StringSink(plain)));
but after running this plain is garbage.
Update:
Sample encrypted data you can try to decrypt with crypto++ so that you can help me even if you don't know python and you're just experienced with crypto++:
Try to decrypt this base64 encoded text:
2t0lLuSBY7NkfK5I4kML0qjcZl3xHcEQBPbDo4TbvQaXuUT8W7lNbRCl8hfSGJA00wgUXhAjQApcuTCZckb9e6EVOwsa+eLY78jo2CqYWzhGez9zn0D2LMKNmZQi88WuTFVw9r1GSKIHstoDWvn54zISmr/1JgjC++mv2yRvatcvs8GhcsZVZT8dueaNK6tXLd1fQumhXCjpMyFjOlPWVTBPjlnsC5Uh98V/YiIa898SF4dwfjtDrG/fQZYmWUzJ8k2AslYLKGs=
with this key:
12341234123412341234123412341234
with counter function described in the beginning of this post using crypto++. If you succeed post the decrypted text (which contains only numbers) and your solution please.
Update2:
I'm not providing an IV in python code, the python module ignores IV. I the IV thing is what causing the problem.
As I read their source codes I can say PyCrypto and Crypto++ Both are perfect libraries for cryptography for Python and C++. The problem was that I was prefixing the encrypted data with some meta information about file and I totally forgot about that, after handling these meta data in client Crypto++ decrypted my files.
As I didn't find this documented explicitly anywhere (not even in Wikipedia) I write it here:
Any combination of Nonce, IV and Counter like concatenation, xor, or likes will work for CTR mode, but the standard that most libraries implement is to concatenate these values in order. So the value that is used in block cipher algorithm is usually: Nonce + IV + Counter. And counter usually starts from 1 (not 0).

Is there any way to export a public key from pycrypto with a rfc4716 subject or comment header?

I'm using pycypto but I don't mind using any library.
http://www.ietf.org/rfc/rfc4716.txt
I'd like to export a public key with a subject or comment header as defined in rfc4716 but I can't seem to see any functionality to do so.
Actually this code snippet simply works for me
import os
from Crypto.PublicKey import RSA
public_key = RSA.importKey(os.path.expanduser("~/.ssh/id_rsa.pub"))

How to encrypt a string using the key

I have a 'public key' in a variable named varkey, for getting the public key I used the urllib and stored that public key in a variable. Now I want to encrypt a msg/string using the public key.
It's ok if somebody could lead me to some library.
My blog post (the passingcuriosity.com link in John Boker's answer) does AES -- a symmetric encryption algorithm -- using the M2Crypto library. M2Crypto is a Python wrapper around OpenSSL. The API is pretty much a straight translation of OpenSSL's into Python, so the somewhat sketchy documentation shouldn't be too much of a problem. If the public key encryption algorithm you need to use is supported by M2Crypto, then you could very well use it to do your public key cryptography.
I found the M2Crypto test suite to be a useful example of using its API. In particular, the RSA (in test_rsa.py), PGP (in test_pgp.py), and EVP (in test_evp.py) tests will help you figure out how to set up and use the library. Do be aware that they are unit-tests, so it can be a little tricky to figure out exactly what code is necessary and what is an artefact of being a test.
PS: As I'm new, my posts can only contain one link so I had to delete most of them. Sorry.
Example
from M2Crypto import RSA
rsa = RSA.load_pub_key('rsa.pub.pem')
encrypted = rsa.public_encrypt('your message', RSA.pkcs1_oaep_padding)
print encrypted.encode('base64')
Output
X3iTasRwRdW0qPRQBXiKN5zvPa3LBiCDnA3HLH172wXTEr4LNq2Kl32PCcXpIMxh7j9CmysLyWu5
GLQ18rUNqi9ydG4ihwz3v3xeNMG9O3/Oc1XsHqqIRI8MrCWTTEbAWaXFX1YVulVLaVy0elODECKV
4e9gCN+5dx/aG9LtPOE=
Here's the script that demonstrates how to encrypt a message using M2Crypto ($ easy_install m2crypto) given that public key is in varkey variable:
#!/usr/bin/env python
import urllib2
from M2Crypto import BIO, RSA
def readkey(filename):
try:
key = open(filename).read()
except IOError:
key = urllib2.urlopen(
'http://svn.osafoundation.org/m2crypto/trunk/tests/' + filename
).read()
open(filename, 'w').write(key)
return key
def test():
message = 'disregard the -man- (I mean file) behind curtain'
varkey = readkey('rsa.pub.pem')
# demonstrate how to load key from a string
bio = BIO.MemoryBuffer(varkey)
rsa = RSA.load_pub_key_bio(bio)
# encrypt
encrypted = rsa.public_encrypt(message, RSA.pkcs1_oaep_padding)
print encrypted.encode('base64')
del rsa, bio
# decrypt
read_password = lambda *args: 'qwerty'
rsa = RSA.load_key_string(readkey('rsa.priv2.pem'), read_password)
decrypted = rsa.private_decrypt(encrypted, RSA.pkcs1_oaep_padding)
print decrypted
assert message == decrypted
if __name__ == "__main__":
test()
Output
gyLD3B6jXspHu+o7M/TGLAqALihw7183E2effp9ALYfu8azYEPwMpjbw9nVSwJ4VvX3TBa4V0HAU
n6x3xslvOnegv8dv3MestEcTH9b3r2U1rsKJc1buouuc+MR77Powj9JOdizQPT22HQ2VpEAKFMK+
8zHbkJkgh4K5XUejmIk=
disregard the -man- (I mean file) behind curtain
From my recent python experience, python doesn't do encryption natively. You need to use an external (3rd party) package. Each of these, obviously, offers a different experience. Which are you using? This will probably determine how your syntax will vary.
You might want to have a look at:
http://www.example-code.com/python/encryption.asp
or this
http://passingcuriosity.com/2009/aes-encryption-in-python-with-m2crypto/
Have you ever heard about "RSAError: data too large for key size"?
Try your sample with more long message:
encrypted = rsa.public_encrypt('My blog post (the passingcuriosity.com link in John Boker's answer) does AES -- a symmetric encryption algorithm -- using the M2Crypto library', RSA.pkcs1_oaep_padding)
You could use MD5 or SHA1 hashing along with your key...

Categories