python-gnupg always returning empty decryption result - python

I am using this piece of code to generate a key, encrypt some content and then decrypt it
with tempfile.TemporaryDirectory() as tmpdir:
gpg = gnupg.GPG(gnupghome=str(tmpdir), verbose=True)
gpg.encoding = 'utf-8'
input_data = gpg.gen_key_input(
key_type='RSA',
key_length=2048,
name_real='Atfinity',
name_comment='Generated by Atfinity',
name_email='no-reply#atfinity.ch',
passphrase='test',
)
key = gpg.gen_key(input_data)
content = 'Encrypt this please'
encrypted = gpg.encrypt_file(
StringIO(content),
recipients=key.fingerprint,
always_trust=True,
passphrase='test',
sign=False
)
decrypted = gpg.decrypt(str(encrypted), always_trust=True, passphrase='test')
self.assertEqual(content, str(decrypted))
However, decrypted is always an empty string. What am I doning wrong?

Related

How do i encrypt and decrypt files with PyCryptodome? (RSA)

I'm trying to encrypt and decrypt a file with PyCryptodome but without success. I can encrypt strings and data just fine but when trying to encrypt files it fails. I have 2 problems, first is that I can't encrypt larger strings. Witch i tried to solve by reading the file with a buffer. Second is that when I try to encrypt it as smaller buffers it just gives me an error "raise ValueError("Ciphertext with incorrect length.")"
My code looks like this:
from Crypto.Cipher import PKCS1_OAEP
import binascii
import ast
file_to_encrypt = "file_example_MP3_700KB.mp3"
buffer_size = 65536 # 64kb
input_file = open(file_to_encrypt, "rb")
output_file = open(file_to_encrypt + ".encrypted", "wb")
# Import keys
pub = open("publickey.txt", "rb")
pubKey = RSA.importKey(pub.read())
pub.close()
priv = open("privatekey.txt", "rb")
keyPair = RSA.importKey(priv.read())
priv.close()
# --------------------------------------------------------------
# Encrypt
encryptor = PKCS1_OAEP.new(pubKey)
buffer = input_file.read(buffer_size)
while len(buffer) > 0:
encrypted = encryptor.encrypt(buffer)
output_file.write(encrypted)
buffer = input_file.read(buffer_size)
input_file.close()
output_file.close()
# --------------------------------------------------------------
input_file = open(file_to_encrypt + ".encrypted", "rb")
output_file = open(file_to_encrypt + ".decrypted", "wb")
# Decrypt
decryptor = PKCS1_OAEP.new(keyPair)
buffer = input_file.read(buffer_size)
while len(buffer) > 0:
decrypted = decryptor.decrypt(ast.literal_eval(str(buffer)))
output_file.write(decrypted)
buffer = input_file.read(buffer_size)
input_file.close()
output_file.close()
# --------------------------------------------------------------
And generating the keys looks like this:
from Crypto.Cipher import PKCS1_OAEP
import binascii
import ast
# key generation
keyPair = RSA.generate(3072*2)
pubKey = keyPair.publickey()
# --------------------------------------------------------------
# Export keys
pub = open("publickey.txt", "wb")
pub.write(pubKey.exportKey('PEM'))
pub.close()
priv = open("privatekey.txt", "wb")
priv.write(keyPair.exportKey('PEM'))
priv.close()
# --------------------------------------------------------------
# Import keys
pub = open("publickey.txt", "rb")
pubKey = RSA.importKey(pub.read())
pub.close()
priv = open("privatekey.txt", "rb")
keyPair = RSA.importKey(priv.read())
priv.close()
# --------------------------------------------------------------
# encryption
msg = '550011'
encryptor = PKCS1_OAEP.new(pubKey)
encrypted = encryptor.encrypt(msg.encode())
# --------------------------------------------------------------
# decryption
decryptor = PKCS1_OAEP.new(keyPair)
decrypted = str(decryptor.decrypt(ast.literal_eval(str(encrypted))))[2:-1]
# --------------------------------------------------------------
print("Encrypted:", binascii.hexlify(encrypted))
print("Decrypted:", decrypted)
if msg == decrypted:
print("PASSED!")
else:
print("FAILED!")
Changing buffer_size fixes the first problem (that the data I'm trying to encrypt is too large.)
But I still can't decrypt my file after encrypting it.
Generating and importing keys works just fine. And encrypting and decrypting with them works just fine as well. As long as I'm only encrypting small strings and not files.

TypeError: can't concat str to bytes - Python + pycryptodome

I'm receiving a TypeError when trying to encrypt + decrypt a file using pycryptodome. I've looked around but can't find much relevant to pycryptodome regarding this. The error is:
Error Image
The code I'm using is:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import binascii
print("Now executing RSA")
# generate the RSA keys and print them on the console (as hex numbers and in the PKCS#8 PEM ASN.1 format)
keyPair = RSA.generate(3072)
pubKey = keyPair.publickey()
print(f"Public key: (n={hex(pubKey.n)}, e={hex(pubKey.e)})")
pubKeyPEM = pubKey.exportKey()
print(pubKeyPEM.decode('ascii'))
print(f"Private key: (n={hex(pubKey.n)}, d={hex(keyPair.d)})")
privKeyPEM = keyPair.exportKey()
print(privKeyPEM.decode('ascii'))
# encrypt the message using RSA-OAEP encryption scheme (RSA with PKCS#1 OAEP padding) with the RSA public key
# msg = b'A message for encryption'
f = open("plaintext.txt", "r")
f = f.read()
encryptor = PKCS1_OAEP.new(pubKey)
encrypted = encryptor.encrypt(f)
print("Encrypted:", binascii.hexlify(encrypted))
# decrypt the message using RSA-OAEP with the RSA Private key
decryptor = PKCS1_OAEP.new(keyPair)
decrypted = decryptor.decrypt(encrypted)
print('Decrypted:', decrypted)
You need to convert plaintext into bytes or read file as binary data. add b to read file as binary data.
f = open("plaintext.txt", "rb")
A side note You should consider closing the file after finishing using it
file = open("plaintext.txt", "rb")
f = file.read()
encryptor = PKCS1_OAEP.new(pubKey)
encrypted = encryptor.encrypt(f)
print("Encrypted:", binascii.hexlify(encrypted))
file.close()
Make sure both data types are equal. You can try converting the text file to bytes so the data types are equal, and hence can be concatenated.

Decrypt a encrypted secret using PyCrypto AES & sha256

I have a encrypted message in a file, encrypted by the following code.
I wrote a function to decrypt this message. I know the password used to encrypt it.
But I got the following error:
python3 decrypt.py enim_msg.txt
Traceback (most recent call last):
File "decrypt.py", line 45, in <module>
print(":: Decrypted: \n" + bytes.decode(decrypted))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x88 in position 2: invalid start byte
How can I fix this problem pls ?
Is My decrypt function wrong ?
My code :
Encrypt function
import os
from Crypto import Random
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
def encrypt(key, filename):
chunksize = 64*1024
outputFile = "en" + filename
filesize = str(os.path.getsize(filename)).zfill(16)
IV = Random.new().read(16)
encryptor = AES.new(key, AES.MODE_CBC, IV)
with open(filename, 'rb') as infile:
with open(outputFile, 'wb') as outfile:
outfile.write(filesize.encode('utf-8'))
outfile.write(IV)
while True:
chunk = infile.read(chunksize)
if len(chunk) == 0:
break
elif len(chunk) % 16 != 0:
chunk += b' ' * (16 - (len(chunk) % 16))
outfile.write(encryptor.encrypt(chunk))
def getKey(password):
hasher = SHA256.new(password.encode('utf-8'))
return hasher.digest()
Decrypt function I wrote
def decrypt(enc, password):
#print(":: enc => " + enc)
private_key = hashlib.sha256(password.encode("utf-8")).digest()
iv = enc[:16]
cipher = AES.new(private_key, AES.MODE_CBC, iv)
return cipher.decrypt(enc[16:])
How I call this function
password = "azerty123"
secret_file_path = sys.argv[1]
the_file = open(secret_file_path, "rb")
encrypted = the_file.read()
decrypted = decrypt(encrypted, password)
the_file.close()
print(":: Decrypted: \n" + bytes.decode(decrypted))
The bytes.decrypt() function by default expects an UTF-8 encoded string. But not every sequence of bytes is a valid UTF-8 sequence. In your case cipher.decrypt() (which may return any sequence of bytes) returned a byte-sequence, which is not a valid UTF-8 sequence. Thus the bytes.decode() function raised an error.
The actual reason why cipher.decrypt() returned a non-UTF-8 string is a bug in your code:
Your encrypted file format contains non-utf-8 data. Its format is like:
16 bytes len info (unencrypted, UTF-8 encoded)
16 bytes IV (unencrypted, binary i.e. non-UTF-8 encoded)
n bytes payload (encrypted, UTF-8 encoded)
You have to ensure that on decryption you only decode parts of your file, that are UTF-8 encoded. Furthermore you have to ensure that you decrypt only encrypted parts of your file (as mentioned in your comments)

Python - Decrypt S3 image file, encrypted with CSE KMS

Is there a way to decrypt jpg or png file in Python, which is encrypted CSE KMS using JAVA - AmazonS3EncryptionClient and stored in S3 ? It looks like boto3 and aws ecryption clients only supports cipher text and not file.
I tried below code but it fails ,
def get_decrypted_stream(s3_object):
region_name = 'us-east-1'
encryptedImageBytes = s3_object.get()['Body'].read()
print("Decoded file : {}".format(encryptedImageBytes))
client = boto3.client('kms', region_name=region_name)
response = client.decrypt( CiphertextBlob=encryptedImageBytes)
data = meta[u'Plaintext']
return io.BytesIO(data)
Error:
It fails on "client.decrypt( CiphertextBlob=encryptedImage)" with { "errorMessage": "An error occurred (413) when calling the Decrypt operation: HTTP content length exceeded 200000 bytes.", "errorType": "ClientError", }
References :
https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html https://github.com/aws/aws-encryption-sdk-python/ https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/python-example-code.html https://aws-encryption-sdk-python.readthedocs.io/en/latest/
As per the documentation you shared, Encrypt and Decrypt API are limited to payload of 4k Maximum : https://docs.aws.amazon.com/kms/latest/APIReference/API_Encrypt.html
When using KMS keys to encode files, the philosophy is to generate a symetric key, encode the payload with the symetric key, encode the symetric key with KMS encrypt API and store the crypted symetric key in the envelope, as a meta-data on S3 for example.
Here is a code sample for S3 file encryption:
#
# Generate a Data Key (encoded with my Master Key in KMS)
#
key = kms.generate_data_key(KeyId=MASTER_KEY_ARN,KeySpec='AES_256')
keyPlain = key['Plaintext']
keyCipher = key['CiphertextBlob']
#
# Encode a file with the data key
#
print ("Initializing encryption engine")
iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16))
chunksize = 64*1024
encryptor = AES.new(keyPlain, AES.MODE_CBC, iv)
print ("KMS Plain text key = %s " % base64.b64encode(keyPlain))
print ("KMS Encrypted key = %s " % base64.b64encode(keyCipher))
in_filename = os.path.join(DIRECTORY, FILENAME)
out_filename = in_filename + '.enc'
filesize = os.path.getsize(in_filename)
print ("Encrypting file")
with open(in_filename, 'rb') as infile:
with open(out_filename, 'wb') as outfile:
outfile.write(struct.pack('<Q', filesize))
outfile.write(iv)
chunk = infile.read(chunksize)
while len(chunk) != 0:
if len(chunk) % 16 != 0:
chunk += ' ' * (16 - len(chunk) % 16)
outfile.write(encryptor.encrypt(chunk))
chunk = infile.read(chunksize)
#
# Store encrypted file on S3
# Encrypted Key will be stored as meta data
#
print ("Storing encrypted file on S3")
metadata = {
"key" : base64.b64encode(keyCipher)
}
#client = boto3.client('s3', 'us-west-2')
s3 = session.client('s3')
transfer = S3Transfer(s3)
transfer.upload_file(out_filename, S3_BUCKET, out_filename, extra_args={"Metadata" : metadata})
os.remove(out_filename)
and sample code to decrypt :
#
# Download Encrypted File and it's metadata
#
print ("Download file and meta data from S3")
transfer.download_file(S3_BUCKET, out_filename, out_filename)
#retrieve meta data
import boto3
s3 = boto3.resource('s3')
object = s3.Object(S3_BUCKET, out_filename)
#print object.metadata
keyCipher = base64.b64decode(object.metadata['key'])
#decrypt encrypted key
print ("Decrypt ciphered key")
key = kms.decrypt(CiphertextBlob=keyCipher)
keyPlain = key['Plaintext']
print ("KMS Plain text key = %s " % base64.b64encode(keyPlain))
print ("KMS Encrypted key = %s " % base64.b64encode(keyCipher))
#
# Decrypt the file
#
print("Decrypt the file")
in_filename = out_filename
out_filename = in_filename + '.jpg'
filesize = os.path.getsize(in_filename)
with open(in_filename, 'rb') as infile:
origsize = struct.unpack('<Q', infile.read(struct.calcsize('Q')))[0]
iv = infile.read(16)
decryptor = AES.new(keyPlain, AES.MODE_CBC, iv)
with open(out_filename, 'wb') as outfile:
chunk = infile.read(chunksize)
while len(chunk) != 0:
outfile.write(decryptor.decrypt(chunk))
chunk = infile.read(chunksize)
outfile.truncate(origsize)

pycrypto encrypt/decrypt, losing part of encrypted string when decrypting

I am trying to encrypt/decrypt with pycrypto in python. for the most part things have worked smooth but I am getting an odd problem when decrypting data.I have tried to encrypt/decrypt some jpgs for testing and although they encrypt/decrypt without issue, the decrypted files cannot be opened/are corrupted. To try to find the problem I saved a textfile with a random sentence similar to "test this file for integrity blah blah blah" and it decrypts correctly only after ".... integrity blah blah blah", everything before integrity is still in garbled characters. I'm not that knowledgable on AES, but im assuming that this is an encoding/decoding or padding error.
Here is my code:
#encryption
iv = Random.new().read( AES.block_size)
filePath = input("Path to file for encryption: ")
selFile = open(filePath, 'rb')
getBytes = bytes(selFile.read())
encPW = input("Enter password: ")
hashpw = hashlib.sha256(encPW.encode('UTF-8').digest())
destination = input("Destination path for encrypted file: ")
aes = AES.new(hashpw, AES.Mode_CFB, iv)
encFile = base65.b64encode(aes.encrypt(getBytes))
writetofile = open(destination, 'wb')
writetofile.write(encFile)
writetofile.close()
print("Encryption successful")
#Decryption
iv = Random.new().read( AES.block_size)
filePath = input("Path to file for decryption: ")
selFile = open(filePath, 'rb')
getBytes = bytes(selFile.read())
decPW = input("Enter password: ")
hashdecpw = hashlib.sha256(encPW.encode('UTF-8').digest())
destination = input("Destination path for decrypted file: ")
aes = AES.new(hashdecpw, AES.Mode_CFB, iv)
decFile = aes.decrypt(getBytes)
writetofile = open(destination, 'wb')
writetofile.write(decFile)
writetofile.close()
print("Decryption successful")
Any ideas on what could be causing the loss of the first characters, and preventing me from encrypting/decrypting files correctly?
You have at least three issues:
You probably mean hashlib.sha256(encPW.encode('UTF-8')).digest() instead of hashlib.sha256(encPW.encode('UTF-8').digest()) (the closing brace is at the wrong position)
You're encoding the ciphertext with Base64 before writing it to a file. You've forgot to decode it after reading it back from the file before decrypting it. For example:
getBytes = base64.b64decode(bytes(selFile.read()))
This is the big one: You need the exact same IV during the decryption that you've used for encryption. The IV is not secret, but it needs to be unique for every encryption that you've done with the same key. Commonly the IV is written in front of the ciphertext and read back for decryption.
#encryption
encFile = base64.b64encode(iv + aes.encrypt(getBytes))
#decryption
getBytes = base64.b64decode(bytes(selFile.read()))
iv = getBytes[:16]
aes = AES.new(hashdecpw, AES.Mode_CFB, iv)
decFile = aes.decrypt(getBytes[16:])
You're generating a new IV for encryption and decryption seperately, which comes to yield such problems. Here's what I recommend doing:
def encrypt(inpath, outpath, password):
iv = Random.new().read(AES.block_size)
with open(inpath, "rb") as f:
contents = f.read()
# A context manager automatically calls f.close()
key = pbkdf2.crypt(password, "")
# See notes
aes = AES.new(key, AES.Mode_CFB, iv)
encrypted = aes.encrypt(contents)
with open(outpath, "wb") as f:
f.write(iv + b":")
f.write(encrypted)
print("Encryption successful")
def decrypt(inpath, outpath, password):
with open(inpath, "rb") as f:
contents = f.read()
iv, encrypted = contents.split(b":")
key = pbkdf2.crypt(password, "")
aes = AES.new(key, AES.Mode_CFB, iv)
decrypted = aes.decrypt(contents)
with open(outpath, "wb") as f:
f.write(decrypted)
print("Decryption successful")
Some notes:
An IV is not meant to be secret, so it can be randomly generated once and then written to a file to be used later for decryption (as shown in this example)
A hashing algorithm is not strong enough for deriving keys, which is why there are special tools called key derivation algorithms (like PBKDF2 in python). Use those instead!
I have not tested this code myself, so it may not work properly.

Categories

Resources