PGP encryption in azure databrick - python

I need your help badly :D
I wrote a code in python with PGP , I have a trusted public key and I could perfectly encrypt my massage with this code, but when I run it on data brick I faced problem :
gnupghome should be a directory and it isnt
I would like to know how can I access to a directory in databrick.
import gnupg
from pprint import pprint
import os
gpg = gnupg.GPG(gnupghome='/root/.pnugp')
key_data = open("/dbfs/mnt/xxxx/SCO/oracle/xxx/Files/publickey.asc").read()
import_result = gpg.import_keys(key_data)
pprint(import_result.results)
with open("/dbfs/mnt/xxxxx-storage/SCO/oracle/xxx/Files/FileToEncrypt.txt",'rb') as f:
status = gpg.encrypt_file(
f, recipients=['securxxxxfertuca#xx.ca'],
output='my-encrypted.txt.gpg')
print( 'ok: ', status.ok)
print ('status: ', status.status)
print ('stderr: ', status.stderr)

I suspect that this ran successfully locally. It doesn't work on databricks because it is looking for the .pnugp in the root which data bricks does not allow you to access.
I use the below snippet of code which doesn't need you to access anything from any directory other than the files you plan to encrypt and the keys.
In the code, I have my public key stored in the key vault as a secret named 'publicb64'. If you want to read the asc version from somewhere you can just read it into KEY_PUB. Don't forget to install pgpy using pip install pgpy.
#Encrypting a file using public key
import pgpy
from pgpy.constants import PubKeyAlgorithm, KeyFlags, HashAlgorithm, SymmetricKeyAlgorithm, CompressionAlgorithm
from timeit import default_timer as timer
import base64
import io
KEY_PUB = base64.b64decode(publicb64).decode("ascii").lstrip()
#print(KEY_PUB)
pub_key = pgpy.PGPKey()
pub_key.parse(KEY_PUB)
pass
# -READ THE FILE FROM MOUNT POINT-----------------
with io.open('/dbfs/mnt/sample_data/california_housing_test.csv', "r",newline='') as csv_file:
input_data = csv_file.read() # The io and newline retains the CRLF
t0 = timer()
#PGP Encryption start
msg = pgpy.PGPMessage.new(input_data)
###### this returns a new PGPMessage that contains an encrypted form of the original message
encrypted_message = pub_key.encrypt(msg)
pgpstr = str(encrypted_message)
with open('/dbfs/mnt/sample_data/california_housing_test.csv.pgp', "w") as text_file:
text_file.write(pgpstr)
print("Encryption Complete :" + str(timer()-t0))

Related

Redirect the output to a file in python

In python, I need to redirect the o/p of the list to a file.
I have the configuration file in json format (test_conf), which i am reading and adding the required commands. At the end, i need to create a file and redirect the output there.
Please suggest how can i redirect the o/p at the end to a file ?
Here is the snippet of the code :
#!/usr/bin/env python
import sys
import re
import time
import json
####### Reading json test_conf ###########
with open('test_conf') as file:
data = json.load(file)
cert = data["cert"]
key = data["key"]
service_config = []
priority = 100
service_config.append('add patset api_auth_ps')
service_config.append('add patset api_unauth_ps')
service_config.append('add patset api_unauth_filetypes_ps')
service_config.append('add ssl certkey api_cert -cert '+cert+' -key '+key)
######## set of configuration here ###########
### Now, i need to redirect the o/p of the created service_config list to a file.
######## Opening file to apply the config ######
sys.stdout = open('output.text', 'w')
for i in service_config :
### How can I add the content to the output.text ??
Something like this should work. Over here, we are adding each list item in each line of the text file, we can obviously change the format of the output according to our requirements.
my_list=[1,2,3,4]
with open('sample.txt', 'w') as f:
for item in my_list:
f.write(str(item)+"\n")

encrypt password in python

I want to generate my Python code in a setup.exe. The user stores an email password in the script. My question: Do I have to additionally encrypt this password, even though I create an * .exe file.
def load_settings(self):
# print(__file__)
# print(os.path.dirname(__file__))
pf = os.path.dirname(__file__)
pa = os.path.join(pf, "settings.json")
# print(pa)
if os.path.exists(pa):
# print("Pfad existiert")
with open(pa, "r") as infile:
data = json.load(infile)
self.ein.pfadbez.setText(data["pfad"])
self.ein.name.setText(data["name"])
self.ein.mail.setText(data["mail"])
self.ein.ausgangserver.setText(data["smtp"])
self.ein.port.setText(data["port"])
self.ein.login.setText(data["login"])
self.ein.passwort.setText(data["pw"])
From the way you worded your question, it sounds like you want a user to store a password within the code itself, or in a text file. Variables are called variables because they vary - a password won't be saved between executions unless stored in plain text, which is where encryption will be needed.
Further, generating Python code from a Windows executable will still require that Python code to be put somewhere for execution, and since Python is fundamentally open-source, hiding it in a compiled package won't do much.
Going about text encryption is simple - since you're on Windows, you could use Pycryptodomex, which will simplify the process of encrypting text. This tutorial could help.
Here's my code:
from cryptography.fernet import Fernet
import pyperclip
print("For this program to work, please send the file named 'pwkey' and the encrypted code to the other user.")
key = Fernet.generate_key()
file = open('pwkey', 'wb')
file.write(key)
file.close()
print('File Generated')
original = input('Enter message>>>')
message = original.encode()
f = Fernet(key)
encrypted = f.encrypt(message)
encrypted = encrypted.decode("ascii")
print('Encrypted:', encrypted)
pyperclip.copy(encrypted)
print('Please tell the other user to input the encrypted code in the Decrypt program')
print('(Code copied to Clipboard)')
print("Note: Please delete the 'pwkey' file after sending it to the other user. It
is for one-time use only.")
And decrypting
# Decrypt
from cryptography.fernet import Fernet
print("For this program to work, make sure you have the file named 'pwkey' in your Python folder and the encrypted "
"code.")
file = open('pwkey', 'rb')
key = file.read()
file.close()
print('Key Retrieved')
encrypted = input('Please input your encrypted code>>>')
encrypted = bytes(encrypted, 'utf-8')
f = Fernet(key)
decrypted = f.decrypt(encrypted)
decrypted = decrypted.decode()
print('Decrypted Message:')
print(decrypted)
print("Note: Please delete the 'pwkey' file after getting the decrypted message.")

PGP encrypt an input file in Python given a public key

Thanks in advance!
I am new to Python.
I want to PGP encrypt a file named "input.csv" using a downloaded "pgp_keys.asc" file.
Here is my attempt:
def encrypt(key, src):
import requests
r = requests.get(key)
with open("/home/zzz/.gnupg/pgp_keys.asc",'wb') as f:
f.write(r.content)
f.close()
import gnupg
gpg=gnupg.GPG(homedir='/home/zzz/.gnupg/')
f = open(src,'rb')
status = gpg.encrypt(f)
print(status.ok)
print(status.status)
print(status.stderr)
But code fails with
False
None
gpg: Sorry, no terminal at all requested - can't get input
My use case is given an input file and public key, encrypt that file.

Problems to verify a file signed with python

I'm trying to create a signed file using OpenSSL and Python, and I'm not receiving any error mesage, but the proccess is not working properly and I can't find the reason.
Below is my step-by-step to sign the file and check the signature:
First I create the crt in command line
openssl req -nodes -x509 -sha256 -newkey rsa:4096 -keyout "cert.key" -out "cert.crt" -subj "/C=BR/ST=SP/L=SP/O=Company/OU=IT Dept/CN=cert"
At this point, I have two files: cert.key and cert.crt
Sign the file use a Python Script like below:
import os.path
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode, b64decode
def __init__(self):
folder = os.path.dirname(os.path.realpath(__file__))
file_path = os.path.join(folder, '../static/cert.key')
self.key = open(file_path, "r").read()
def sign_data(self, my_file):
rsakey = RSA.importKey(self.key) # I opened the cert.key in __init__
signer = PKCS1_v1_5.new(rsakey)
digest = SHA256.new()
digest.update(my_file)
sign = signer.sign(digest)
return sign, b64encode(sign)
All works fine and after save the files, I have other three files: my_file.csv (the original one), my_file.txt.sha256 and my_file.txt.sha256.base64. At this point, I can decode the base64 file and compare with the signed one and both are fine.
The problem is when I try to verify the signature using the following command:
`openssl dgst -sha256 -verify <(openssl x509 -in "cert.crt" -pubkey -noout) -signature my_file.txt.sha256 my_file.csv`
At this point I always receive the "Verification Failure" and don't understand why.
Maybe the problem is my lack of Python's Knowledge, because when I sign the file using the following command (after step 1 and before use the Python script described in 2), the same verification works fine.
openssl dgst -sha256 -sign "cert.key" -out my_file.txt.sha256 my_file.csv
Am I doing anything wrong?
UPDATE
Based on the comments, I tried the script in a local virtualnv with python 2.7 and it worked, so the problem must be in the read/write operations.
I'm updating this quetion with the complete script, including the read/write operations 'cause I can run it locally, but I still don't get any error in the GAE environment and can't understand why.
The first step is the CSV creation and storage in the Google Storage (Bucket) with the script below
import logging
import string
import cloudstorage as gcs
from google.appengine.api import app_identity
def create_csv_file(self, filename, cursor=None):
filename = '/' + self.bucket_name + filename
try:
write_retry_params = gcs.RetryParams(backoff_factor=1.1)
# the cursor stores a MySQL result set
if cursor is not None:
gcs_file = gcs.open(filename,
'w',
content_type='text/csv',
retry_params=write_retry_params)
for row in cursor:
gcs_file.write(','.join(map(str, row)) + '\n')
gcs_file.close()
except Exception as ex:
logging.critical("Problem to write in th GC Storage with the exception:{}".format(ex))
raise ex
It works fine and store a CSV in the correct path inside Google storage. After that part, the next read/write operation is the signature of the file.
def cert_file(self, original_filename):
filename = '/' + self.bucket_name + original_filename
cert = Cert() # This class just has one method, that is that described in my original question and is used to sign the file.
with gcs.open(filename) as cloudstorage_file:
cloudstorage_file.seek(-1024, os.SEEK_END)
signed_file, encoded_signed_file = cert.sign_data(cloudstorage_file.read()) #the method to sign the file
signature_content = encoded_signed_file
signed_file_name = string.replace(original_filename, '.csv', '.txt.sha256')
encoded_signed_file_name = string.replace(signed_file_name, '.txt.sha256', '.txt.sha256.base64')
self.inner_upload_file(signed_file, signed_file_name)
self.inner_upload_file(encoded_signed_file, encoded_signed_file_name)
return signed_file_name, encoded_signed_file_name, signature_content
The inner_upload_file, just save the new files in the same bucket:
def inner_upload_file(self, file_data, filename):
filename = '/' + self.bucket_name + filename
try:
write_retry_params = gcs.RetryParams(backoff_factor=1.1)
gcs_file = gcs.open(filename,
'w',
content_type='application/octet-stream',
retry_params=write_retry_params)
gcs_file.write(file_data)
gcs_file.close()
except Exception as ex:
logging.critical("Problem to write in th GC Storage with the exception:{}".format(ex))
raise ex
Here is the app.yaml for reference. The cert.key and cert.crt generated by command line are stored in a static folder inside the app folder (the same directory where is my app.yaml).
UPDATE 2
Following the comments, I tried to run the signature proccess locally and then compare the files. Below is the step-by-setp and results.
First, I adapted the signature process to run as python sign.py file_name.
#!/usr/bin/python
import sys
import os
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode, b64decode
file_path = 'static/cert.key'
key = open(file_path, "rb").read()
rsakey = RSA.importKey(key)
signer = PKCS1_v1_5.new(rsakey)
digest = SHA256.new()
file_object = open(sys.argv[1], "r")
digest.update(file_object.read())
sign = signer.sign(digest)
signed_path = "signed"
f = open(signed_path + '.txt.sha256', 'w')
f.write(sign)
f.close()
f2 = open(signed_path + '.txt.sha256.base64', 'w')
f2.write(b64encode(sign))
f2.close()
I ran the automatic proccess that saved the signed file in GCS's bucket (along with the original CSV file). After it I download both files through Google web panel for GCS.
I ran the command python sign.py gcs_file_original.csv in a virtualenv with python 2.7.10 using the CSV file I just downloaded.
After it, I compared the two signed files with cmp -b gcs_signed.txt.sha256 locally_signed.txt.sha256 resulting in:
gcs_signed.txt.sha256 locally_signed.txt.sha256 differ: byte 1, line 1 is 24 ^T 164 t
Using the VisualBinaryDiff, the result looks like two totally different files.
Now, I know the problem, but have no idea on how to fix it. This problem is beeing very trick.
I finally found the problem. I was so focused in find a problem in the openssl signature proccess and didn't pay attention to old Ctrl+C/Ctrl+V problem.
For test purposes, I copied the 'Read from GCS' example from this tutorial.
When I moved the test to the real world application, I didn't read the page again and didn't note the gcs_file.seek(-1024, os.SEEK_END).
As I said in the original question, I'm not Python specialist, but this line was reading just part of the GCS file, so the signature was indeed different from the original one.
Just cut that line of my reading methods and now all works fine.

Downloading .pdf file from FTP using a Python Script

I am able to download files from the FTP using the ftplib in Python, but this is like I hard code the name the name of the file(R.pdf) and this downloads only (R.pdf), is there a way to download all files in the FTP with the extension .PDF to my local system using Python. I am able to do this in Shell by just using *.pdf
Replace host, user and password with your credentials,
and 'public_html/soleil' with the address of the directory in which are the PDF files you want to be downloaded,
in the following code and it should be OK I think.
from ftplib import *
from os import listdir
from os.path import getsize
ftp_dt = FTP(host,user,password)
ftp_pi = FTP(host,user,password)
print '\n- Ouverture de connection et logging : OK'
ftp_dt.cwd('public_html/soleil')
ftp_pi.cwd('public_html/soleil')
def func(content, li = [0], la = [], si = [0], memname = ['']):
if name!=memname[0]:
memname[0],li[0:1],la[:],si[0:1] = name,[0],[],[0]
li[0] = li[0] + 1
si[0] = si[0] + len(content)
la.append(str(len(content)))
if li[0]%8==0:
print ' '.join(la) +\
' total: '+str(li[0])+' chunks, '+str(si[0])+' bytes'
la[:] = []
f.write(content)
li_files = []
for name in ftp_dt.nlst():
try:
ftp_dt.size(name)
if name not in ('.','..') and name[-4:]=='.pdf':
li_files.append(name)
except:
pass
if li_files:
for name in li_files:
print '\n- Downloading '+name
with open('E:\\PDF\\DOWNS\\'+name,'wb') as f:
ftp_pi.retrbinary('RETR '+name,func)
if getsize('E:\\PDF\\DOWNS\\'+name)==ftp_dt.size(name):
print ' OK ! Download of complete '+repr(name)+' SUCCEEDED'
else:
print ' FAILURE !! : '+name+' only partially downloaded'
else:
print '\nThere is no PDF file in this FTP directory'
ftp_dt.quit()
ftp_pi.quit()
Two connexions ftp_dt and ftp_pi are defined for “Data Transfers“ and “Protocol Interpretation“ because FTP protocol is based on two channels, one for the commands and the other for..... guess what ?
The func() function is used as callback in the fonction retrbinary()
It could be just
def func(content):
f.write()
but I played a bit with the possibilities of default variables of a function.
One thing I don’t understand well: how can this code work while the reference f in func() is only defined in the text of code after the definition of func() . But I tested it and it works !
I don't have access to an FTP server I can try this but a cursory look at the documentation indicates that this is not possible.
You can, however, obtain a list of files on the remote end with the dir or nlst commands and then fetch each file in a loop.
use two python modules glob and wget. Your snippet could look like this
import glob
import wget
list_to_download = glob.glob(url+'*.pdf')
for file in list_to_download:
wget.download(file)

Categories

Resources