How to save and load rsa keys - python

I'm trying to encrypt some text and then save the ciphertext and the keys in separate files, then decrypting the "file" file (ciphertext) using the "keys" (keys in json)
Breakdown of my code
Creating keys
Opening keys file
Converting keys to json
Saving file
Getting text from user
Encrypting it
Writing ciphertext to file
Loading keys
Taking e, n, d, p, q values and assigning them
Opening and reading ciphertext from file
Decripting and outputting
All of the code works except when I try to assign the keys from my json file,
I get:
Traceback (most recent call last):
File "C:\Users\user\Desktop\python projects\encrption\test.py", line 48, in <module>
text = rsa.decrypt(cyphertext, loadkedkeys[1]).decode()
File "C:\Users\user\Desktop\python projects\encrption\.venv\lib\site-packages\rsa\pkcs1.py", line 249, in decrypt
decrypted = priv_key.blinded_decrypt(encrypted)
TypeError: blinded_decrypt() missing 1 required positional argument: 'encrypted'
My code:
import rsa
import json
#make keys
print("new keys")
loadkedkeys = rsa.newkeys(256)
print("file")
#turn keys into json
keysfile = open(file=("kes"), mode="w")
keys = {"keys": []}
keys["keys"].append(((loadkedkeys[0].e), (loadkedkeys[0].n)))
keys["keys"].append(
(((loadkedkeys[1].e), loadkedkeys[1].n, (loadkedkeys[1].d), (loadkedkeys[1].p),
(loadkedkeys[1].q))))
keysfile.write(str(json.dumps(keys)))
keysfile.close()
text = input("message: ")
#encrypt
cyphertext = rsa.encrypt(text.encode(), loadkedkeys[0])
keysFile = open(file="kes", mode="r")
keysfilecontents = keysFile.read()
try:
keys = json.loads(keysfilecontents)
except:
print("json error")
loadkedkeys = (rsa.key.PublicKey, rsa.key.PrivateKey)
# setting public key
loadkedkeys[0].e = keys["keys"][0][0]
loadkedkeys[0].n = keys["keys"][0][1]
# setting private key
loadkedkeys[1].e = keys["keys"][1][0]
loadkedkeys[1].n = keys["keys"][1][1]
loadkedkeys[1].d = keys["keys"][1][2]
loadkedkeys[1].p = keys["keys"][1][3]
loadkedkeys[1].q = keys["keys"][1][4]
keysFile.close()
print(loadkedkeys[0])
print(loadkedkeys[1])
open("text.txt", "wb").write(cyphertext)
text = open("text.txt", "rb").read()
text = rsa.decrypt(cyphertext, loadkedkeys[1]).decode()
print(text)

So I seem to have figured it out, I changed so I assign the values though rsa.PublicKey(value,value), also swapped the e and n values

Related

DSA key format not supported

I am trying to do a P2MS script.
For my script, I am saving the keys into a text file with DER format instead of the usual PEM file. Both key and signatures are saved in a text file and hexlify. Below is my code for the P2MS execution.
from Crypto.PublicKey import DSA
from Crypto.Hash import SHA256
from Crypto.Signature import DSS
from binascii import hexlify, unhexlify
import binascii
message = b"helpsmepls"
# Read scriptPubKey and scriptSig from files
with open('scriptPubKey.txt', 'r') as f:
readscriptPubKey = f.read().strip()
with open('scriptSig.txt', 'r') as f:
scriptSig = f.read().strip()
print(type(readscriptPubKey))
tempholder = readscriptPubKey.split()
# Removing the first character and last character
removeend = tempholder[1:-1]
scriptPubKey = []
# Removing front extra headings
for count, x in enumerate(removeend):
w = bytes(removeend[count][1:-1], encoding = 'utf-8')
#print(w)
scriptPubKey.append(w)
# Splitting the Signatures
signatures = scriptSig.split()
hash_obj = SHA256.new(message)
# Going through the pubkeys based on the number of signatures generated
for o, sig in enumerate(signatures):
pub_key = DSA.import_key(bytes.fromhex(scriptPubKey[o].decode("utf-8")))
hash_obj = SHA256.new(message)
verifier = DSS.new(pub_key, 'fips-183-3')
# Verifying if the Public key and signatures match, loop will break if False is encountered
if verifier.verify(hash_obj, sig):
d = True
else:
d = False
break
break
if d == True:
print("The message is authentic.")
else: print("The message is not authentic.")
Unfortunately before my code can reach the verification, it encountered an error.
Full traceback
It seems my DSA key format has an error, but I am not too sure why is it giving me that error.
I have also tried unhexlifying my input from the public key text file, but it also did not work. I have tried to hex decode the input to get the DER format of the input, but my type is still just bytes. I am not so sure how to properly import the key with the appropriate DSA key format from a txt file. I am able to do that with a PEM file but would just like to find out how to execute it with a txt file.
My expected outcome is the DSA key is imported properly and i am able to verify the public key with the signatures.

cryptography.fernet.InvalidToken problem with cryptography

Getting this error when trying to run this:
File "Test Files.py", line 502, in decryptdefault
decrypted = fernet.decrypt(d)
File "/usr/lib/python3/dist-packages/cryptography/fernet.py", line 74, in decrypt
timestamp, data = Fernet._get_unverified_token_data(token)
File "/usr/lib/python3/dist-packages/cryptography/fernet.py", line 92, in _get_unverified_token_data
raise InvalidToken
cryptography.fernet.InvalidToken
FYI dk variable is defined with key (default key)
dk = 'niwaXsYbDiAxmLiqRiFbDa_8gHio15sNQ6ZO-sQ0nR4='
# Decrypts the file with default key
def decryptdefault(inclufile):
Key = dk
fernet = Fernet(Key)
readfile = open(inclufile, 'rb')
d = readfile.read()
readfile.close()
# Decrypts and puts it into the text
if readfile != "":
decrypted = fernet.decrypt(d)
decrypted = str(decrypted).replace('b\'', '', 1)
decrypted = decrypted[:-3]
return str(decrypted)
Edit: I added the key for those who asked
I have found out, through trial and error with the same project later down the line, that you need to turn your key into something like this key = b'niwaXsYbDiAxmLiqRiFbDa_8gHio15sNQ6ZO-sQ0nR4='
The main difference being the key is encoded in a utf-8 format and is now readable by Fernet and doesn't return that error. Here is a function that uses Tkinter, Fernet, and os to actually decrypt my file.
# Propriatary method of encrypting files
def decrypt(self, file):
with open(file, 'rb') as readfile:
contents = readfile.read()
self.title(os.path.basename(file) + ' - SecureNote')
# self.textbox is a variable inside of the class I am using for my window
self.textbox.delete(1.0, tk.END)
if contents != "":
# getword retur
Key = bytes(getword('Key:', 1), encoding="utf-8")
fernet = Fernet(Key)
decrypted = fernet.decrypt(contents).decode('utf-8')
self.textbox.insert(1.0, str(decrypted))
del Key
del fernet
else:
pass

Breakng the hash

I have to break 4 hash codes and find their number . but my code is not working
these are the hash codes (in a csv file) :
javad :f478525457dcd5ec6223e52bd3df32d1edb600275e18d6435cdeb3ef2294e8de
milad : 297219e7de424bb52c040e7a2cbbd9024f7af18e283894fe59ca6abc0313c3c4
tahmine : 6621ead3c9ec19dfbd65ca799cc387320c1f22ac0c6b3beaae9de7ef190668c4
niloofar : 26d72e99775e03d2501416c6f402c265e628b7d02eee17a7671563c32e0cd9a3
my code :
import hashlib
import itertools as it
import csv
from typing import Dict
number=[0,1,2,3,4,5,6,7,8,9]
code = hashlib.sha256()
passwords = list(it.permutations(number, 4))
with open('passwords.csv', newline='') as theFile:
reader = csv.reader(theFile)
passdic = dict()
# hpass is hash password
for hpass in passwords :
encoded_hpass = ''.join(map(str, hpass)).encode('ascii')
code = hashlib.sha256()
code.update(encoded_hpass)
passdic[encoded_hpass] = code.digest()
for row in theFile :
for key, value in row.items():
passdic[key].append(value)
and my result is :
'C:\Users\Parsa\AppData\Local\Programs\Python\Python38-32\python.exe' 'c:\Users\Parsa\.vscode\extensions\ms-python.python-2021.12.1559732655\pythonFiles\lib\python\debugpy\launcher' '3262' '--' 'c:\Users\Parsa\Desktop\project\hash breaker.py'
Traceback (most recent call last):
File "c:\Users\Parsa\Desktop\project\hash breaker.py", line 24, in <module>
for row in theFile :
ValueError: I/O operation on closed file.
You're trying to read from a closed file, which is impossible.
I don't know what your code is supposed to do, but here are the unlogical parts:
This opens the file to parse it as CSV
with open('passwords.csv', newline='') as theFile:
reader = csv.reader(theFile)
Then later on you run:
for row in theFile :
for key, value in row.items():
But now, you're outside of the with block and the file is closed.
I guess you should use reader in place of theFile. If you really intend to loop over the raw line of the file, you need to wrap the loop again in a with open statement.

Decrypt message with cryptography.fernet do not work

I just tried my hand at encrypting and decrypting data. I first generated a key, then encrypted data with it and saved it to an XML file. Now this data is read and should be decrypted again.
But now I get the error message "cryptography.fernet.InvalidToken".
import xml.etree.cElementTree as ET
from cryptography.fernet import Fernet
from pathlib import Path
def load_key():
"""
Load the previously generated key
"""
return open("../login/secret.key", "rb").read()
def generate_key():
"""
Generates a key and save it into a file
"""
key = Fernet.generate_key()
with open("../login/secret.key", "wb") as key_file:
key_file.write(key)
def decrypt_message(encrypted_message):
"""
Decrypts an encrypted message
"""
key = load_key()
f = Fernet(key)
message = encrypted_message.encode('utf-8')
decrypted_message = f.decrypt(message)
return(decrypted_message)
def decryptMessage(StringToDecrypt):
decryptedMessage = decrypt_message(StringToDecrypt)
return decryptedMessage
def loginToRoster(chrome):
credentials = readXML()
user = decryptMessage(credentials[0])
pw = decryptMessage(credentials[1])
userName = chrome.find_element_by_id('UserName')
userName.send_keys(user)
password = chrome.find_element_by_id('Password')
password.send_keys(pw)
In the tuple "credentials" there are 2 encrypted strings.
Please help - have already tried everything to change the formats, but no chance.
Edit:
Errormessage:
Traceback (most recent call last):
File "C:/Users/r/Documents/GitHub/ServiceEvaluationRK/source/main.py", line 27, in <module>
login.loginToRoster(chrome)
File "C:\Users\r\Documents\GitHub\ServiceEvaluationRK\source\login.py", line 106, in loginToRoster
user = decryptMessage(credentials[0])
File "C:\Users\r\Documents\GitHub\ServiceEvaluationRK\source\login.py", line 49, in decryptMessage
decryptedMessage = decrypt_message(StringToDecrypt)
File "C:\Users\r\Documents\GitHub\ServiceEvaluationRK\source\login.py", line 43, in decrypt_message
decrypted_message = f.decrypt(message)
File "C:\Users\r\Documents\GitHub\ServiceEvaluationRK\venv\lib\site-packages\cryptography\fernet.py", line 75, in decrypt
timestamp, data = Fernet._get_unverified_token_data(token)
File "C:\Users\r\Documents\GitHub\ServiceEvaluationRK\venv\lib\site-packages\cryptography\fernet.py", line 107, in _get_unverified_token_data
raise InvalidToken
cryptography.fernet.InvalidToken
I found an answer to my problem:
I took ASCII instead of utf-8. And I added a .decode('ASCII') at the function "loginToRoster" to both variables 'user' and 'pw'
Now the encryption and decryption works fine.
So, the 'loginToRoster' functions looks like:
def loginToRoster(chrome):
credentials = readXML()
user = decryptMessage(credentials[0]).decode('ASCII')
pw = decryptMessage(credentials[1]).decode('ASCII')
userName = chrome.find_element_by_id('UserName')
userName.send_keys(user)
password = chrome.find_element_by_id('Password')
password.send_keys(pw)
Where have you defined load_key() in the decrypt_message function. It's not a method it's just a undefined function. You're probably getting that error since the key is invalid because you're not getting the one you saved.

ValueError: AES key must be either 16, 24, or 32 bytes long PyCrypto 2.7a1

I'm making programm for my school project and have one problem above.
Here's my code:
def aes():
#aes
os.system('cls')
print('1. Encrypt')
print('2. Decrypt')
c = input('Your choice:')
if int(c) == 1:
#cipher
os.system('cls')
print("Let's encrypt, alright")
print('Input a text to be encrypted')
text = input()
f = open('plaintext.txt', 'w')
f.write(text)
f.close()
BLOCK_SIZE = 32
PADDING = '{'
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
secret = os.urandom(BLOCK_SIZE)
f = open('aeskey.txt', 'w')
f.write(str(secret))
f.close()
f = open('plaintext.txt', 'r')
privateInfo = f.read()
f.close()
cipher = AES.new(secret)
encoded = EncodeAES(cipher, privateInfo)
f = open('plaintext.txt', 'w')
f.write(str(encoded))
f.close()
print(str(encoded))
if int(c) == 2:
os.system('cls')
print("Let's decrypt, alright")
f = open('plaintext.txt','r')
encryptedString = f.read()
f.close()
PADDING = '{'
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
encryption = encryptedString
f = open('aeskey.txt', 'r')
key = f.read()
f.close()
cipher = AES.new(key)
decoded = DecodeAES(cipher, encryption)
f = open('plaintext.txt', 'w')
f.write(decoded)
f.close()
print(decoded)
Full error text:
Traceback (most recent call last): File "C:/Users/vital/Desktop/Prog/Python/Enc_dec/Enc_dec.py", line 341, in aes()
File "C:/Users/vital/Desktop/Prog/Python/Enc_dec/Enc_dec.py", line 180, in aes cipher = AES.new(key)
File "C:\Users\vital\AppData\Local\Programs\Python\Python35-32\lib\site-packages\Crypto\Cipher\AES.py", line 179, in new return AESCipher(key, *args, **kwargs)
File "C:\Users\vital\AppData\Local\Programs\Python\Python35-32\lib\site-packages\Crypto\Cipher\AES.py", line 114, in init blockalgo.BlockAlgo.init(self, _AES, key, *args, **kwargs)
File "C:\Users\vital\AppData\Local\Programs\Python\Python35-32\lib\site-packages\Crypto\Cipher\blockalgo.py", line 401, in init self._cipher = factory.new(key, *args, **kwargs)
ValueError: AES key must be either 16, 24, or 32 bytes long
Process finished with exit code 1
What am I doing wrong?
The error is very clear. The key must be exactly of that size. os.urandom will return you the correct key. However this key is a bytes (binary string value). Furthermore, by using str(secret), the value of repr(secret) is written into the file instead of secret.
What is more confusing is that AES.new allows you to pass the key as Unicode! However, suppose the key was the ASCII bytes 1234123412341234. Now,
f.write(str(secret))
will write b'1234123412341234' to the text file! Instead of 16 bytes, it now contains those 16 bytes + the b, and two ' quote characters; 19 bytes in total.
Or if you take a random binary string from os.urandom,
>>> os.urandom(16)
b'\xd7\x82K^\x7fe[\x9e\x96\xcb9\xbf\xa0\xd9s\xcb'
now, instead of writing 16 bytes D7, 82,.. and so forth, it now writes that string into the file. And the error occurs because the decryption tries to use
"b'\\xd7\\x82K^\\x7fe[\\x9e\\x96\\xcb9\\xbf\\xa0\\xd9s\\xcb'"
as the decryption key, which, when encoded as UTF-8 results in
b"b'\\xd7\\x82K^\\x7fe[\\x9e\\x96\\xcb9\\xbf\\xa0\\xd9s\\xcb'"
which is a 49-bytes long bytes value.
You have 2 good choices. Either you continue to write your key to a text file, but convert it to hex, or write the key into a binary file; then the file should be exactly the key length in bytes. I am going for the latter here:
Thus for storing the key, use
with open('aeskey.bin', 'wb') as keyfile:
keyfile.write(secret)
and
with open('aeskey.bin', 'rb') as keyfile:
key = keyfile.read()
Same naturally applies to the cipher text (that is the encrypted binary), you must write and read it to and from a binary file:
with open('ciphertext.bin', 'wb') as f:
f.write(encoded)
and
with open('ciphertext.bin', 'rb') as f:
encryptedString = f.read()
If you want to base64-encode it, do note that base64.b64encode/decode are bytes-in/bytes-out.
By the way, plaintext is the original, unencrypted text; the encrypted text is called ciphertext. AES is a cipher that can encrypt plaintext to ciphertext and decrypt ciphertext to plaintext using a key.
Despite these being called "-text" neither of them is textual data per se, as understood by Python, but they're binary data, and should be represented as bytes.

Categories