I've been trying to generate a temporary url in python, the url will some data that i need to make sure isn't changed so i'll add a hash in the end but i keep ending with a bString no matter what i try, can anyone point out what i'm doing wrong?
Here's a sample of my code
oh and i know that maybe changing the algorithms/encoding might solve the problem but i can't find a suitable one, can any downvoter explain why he downvoted
import hashlib
import datetime
from Crypto.Cipher import AES
def checkTemp(tempLink):
encrypter = AES.new('1234567890123456', AES.MODE_CBC, 'this is an iv456')
decryption = encrypter.decrypt(tempLink)
length = len(decryption)
hash_code = decryption[length-32:length]
data= decryption[:length-32].strip()
hasher = hashlib.sha256()
hasher.update(data)
hashCode = hasher.digest()
if(hash_code==hashCode):
array = data.decode().split(",",5)
print("expiry date is :"+ str(array[5]))
return array[0],array[1],array[2],array[3],array[4]
else:
return "","","","",""
def createTemp(inviter,email,role,pj_name,cmp_name):
delim = ','
data = inviter+delim+email+delim+role+delim+pj_name+delim+cmp_name+delim+str(datetime.datetime.now().time())
data = data.encode(encoding='utf_8', errors='strict')
hasher = hashlib.sha256()
hasher.update(data)
hashCode = hasher.digest()
encrypter = AES.new('1234567890123456', AES.MODE_CBC, 'this is an iv456')
# to make the link a multiple of 16 by adding for AES with the addition of spaces
newData = data+b' '*(len(data)%16)
result = encrypter.encrypt(newData+hashCode)
return result
#print(str(link).split(",",5))
link = createTemp("name","email#homail.com","Designer","Project Name","My Company")
print(link)
inviter,email,role,project,company = checkTemp(link)
The problem was not being able to putout a normal string because the encryption will result in characters that are almost impossible to encode, so the solution is to use binascii to encode the bStrings for us and decode them
import binascii
then we encode the resulting usable string for the link
hexedLink = binascii.hexlify(link).decode()
and we unhexify it before using it in the method
inviter,email,role,project,company = checkTemp(binascii.unhexlify(hexedLink))
Related
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.
import unittest
import base64
from py3rijndael import Rijndael
def test_rijndael():
key = 'qBS8uRhEIBsr8jr8vuY9uUpGFefYRL2HSTtrKhaI1tk='
print(len(key))
a=input("Please Enter Plain text: ")
plain_text=a.encode('utf-8')
rijndael = Rijndael(base64.b64decode(key), block_size=32)
padded_text = plain_text.ljust(32, b'\x1b')
cipher = rijndael.encrypt(padded_text)
cipher_text = base64.b64encode(cipher)
pl_txt=rijndael.decrypt(cipher)
pl_txt[:len(plain_text)]
return cipher_text
In the above code, I want to generate a random key for the secure private key
changing any character in the key for ex: making
key = 'qBS8uRhEIBsr8jr8vuY9uUpGFefYRL2HSTtrKhaI1tk+' or some thing else, making test to fail with invalid key size. could someone please help with this.
I am implementing SHA1-HMAC generation for python (v 3.7) to be able to create HMAC code.
I have used an online generator to create SHA1-HMAC with the following data:
string: '123'
Secret Key: 'secret'
Digest algorithm: SHA1
I am getting this result:
b14e92eb17f6b78ec5a205ee0e1ab220fb7f86d7
However when I try to do this same with Python I am getting different results which are wrong.
import hashlib
import hmac
import base64
def make_digest(message, key):
key = bytes(key, 'UTF-8')
message = bytes(message, 'UTF-8')
digester = hmac.new(key, message, hashlib.sha1)
signature1 = digester.digest()
signature2 = base64.urlsafe_b64encode(signature1)
return str(signature2, 'UTF-8')
result = make_digest('123', 'secret')
print(result)
This code gives result:
sU6S6xf2t47FogXuDhqyIPt_htc=
What could be wrong with this code?
You should not use Base64 here. The site you link to gives you the hex values of the digest bytes. Use the HMAC.hexdigest() method to get the same value in hex in Python:
>>> key = b'secret'
>>> message = b'123'
>>> digester = hmac.new(key, message, hashlib.sha1)
>>> digester.hexdigest()
'b14e92eb17f6b78ec5a205ee0e1ab220fb7f86d7'
put differently, your code outputs the correct value, but as Base64-encoded data:
>>> digester.digest()
b'\xb1N\x92\xeb\x17\xf6\xb7\x8e\xc5\xa2\x05\xee\x0e\x1a\xb2 \xfb\x7f\x86\xd7'
>>> base64.urlsafe_b64encode(digester.digest())
b'sU6S6xf2t47FogXuDhqyIPt_htc='
and the value you generated online contains the exact same bytes as the hex digest, so we can generate the same base64 output for that:
>>> bytes.fromhex('b14e92eb17f6b78ec5a205ee0e1ab220fb7f86d7')
b'\xb1N\x92\xeb\x17\xf6\xb7\x8e\xc5\xa2\x05\xee\x0e\x1a\xb2 \xfb\x7f\x86\xd7'
>>> base64.urlsafe_b64encode(bytes.fromhex('b14e92eb17f6b78ec5a205ee0e1ab220fb7f86d7'))
b'sU6S6xf2t47FogXuDhqyIPt_htc='
I have data in my database that I need to encrypt. I will then download the database to csv files. I have a python program that can decrypt the specific columns in a csv file. The problem is that I don't get my data out from the python program.
sql function:
CREATE OR REPLACE FUNCTION AESEncrypt (data TEXT,pass TEXT)
RETURNS TEXT AS $crypted$
declare
crypted TEXT;
key BYTEA;
iv BYTEA;
BEGIN
key := digest(convert_to(pass, 'utf-8'), 'sha256');
iv := digest(convert_to(CONCAT(data , 'salt'), 'utf-8'), 'md5');
crypted := encode(encrypt_iv(convert_to(data, 'utf-8'), key, iv, 'aes'), 'base64');
RETURN crypted;
END;
$crypted$ LANGUAGE plpgsql;
python program:
import csv
import time
import base64
from hashlib import sha256, md5
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
password = 'Password'
inputFile = 'test.txt'
outputFile = 'out.txt'
delimiter = ';'
columns = [0]
backend = default_backend()
key = sha256(password.encode('utf-8')).digest()
iv = md5((password + 'salt').encode('utf-8')).digest()
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
def encrypt(input):
input = bytes(input, 'utf-8')
#Padding
length = 16 - (len(input) % 16)
input += bytes([length])*length
#Encrypt
encryptor = cipher.encryptor()
return base64.b64encode(encryptor.update(input) + encryptor.finalize()).decode("utf-8")
def decrypt(input):
input = base64.b64decode(input)
decryptor = cipher.decryptor()
data = decryptor.update(input) + decryptor.finalize()
data = data[:-data[-1]] #Remove padding
print(data)
return data.decode('utf-8')
def main():
start_time = time.time()
with open(inputFile, 'r') as csvfileIn:
with open(outputFile, 'w', newline='') as csvfileOut:
spamreader = csv.reader(csvfileIn, delimiter=delimiter)
spamwriter = csv.writer(csvfileOut, delimiter=delimiter)
firstRow = True
for row in spamreader:
if not firstRow:
for pos in columns:
row[pos] = decrypt(row[pos])
firstRow = False
spamwriter.writerow(row)
print("--- %s seconds ---" % (time.time() - start_time))
main()
If I encrypt the file with the encrypt function written in the python program then I get the correct result if i would decrypt it.
If I would call the sql funcion as AESEncrypt('data', 'Password') then it returns the base64 string Ojq6RKg7NgDx8YFdLzfVhQ==
But after decryption I get the empty string as result and not the string data. If I look at the print statment before the utf-8 decode step in the decryption function it prints out the following on the console b'', so it looks like it could be something wrong with the padding. If I would print before I remove the padding I get b'\x85\x90sz\x0cQS\x9bs\xeefvA\xc63-'. If I will encrypt a long sentence then I will actually see parts of the text in the byte outputs above.
Do anyone know what I have done wrong?
There is one same question in StackOverflow with this link:
How to generate temporary URLs in Django
But the accepted answer code is for Python 2 and I converted it to Python 3:
import hashlib, zlib
import pickle as pickle
import urllib.request, urllib.parse, urllib.error
my_secret = "michnorts"
def encode_data(data):
"""Turn `data` into a hash and an encoded string, suitable for use with `decode_data`."""
text = zlib.compress(pickle.dumps(data, 0)).encode('base64').replace('\n', '')
m = hashlib.md5(my_secret + text).hexdigest()[:12]
return m, text
def decode_data(hash, enc):
"""The inverse of `encode_data`."""
text = urllib.parse.unquote(enc)
m = hashlib.md5(my_secret + text).hexdigest()[:12]
if m != hash:
raise Exception("Bad hash!")
data = pickle.loads(zlib.decompress(text.decode('base64')))
return data
hash, enc = encode_data(['Hello', 'Goodbye'])
print(hash, enc)
print(decode_data(hash, enc))
But it have error :
text = zlib.compress(pickle.dumps(data, 0)).encode('base64').replace('\n', '')
AttributeError: 'bytes' object has no attribute 'encode'
How should I fix this?
Trying to adapt your code to Python 3, I came up with this:
import hashlib, zlib
import pickle as pickle
import urllib.request, urllib.parse, urllib.error
import base64
my_secret = "michnorts"
def encode_data(data):
"""Turn `data` into a hash and an encoded string, suitable for use with `decode_data`."""
compressed_text = zlib.compress(pickle.dumps(data, 0))
text = base64.b64encode(compressed_text).decode().replace('\n', '')
m = hashlib.md5(str.encode('{}{}'.format(my_secret, text))).hexdigest()[:12]
return m, text
def decode_data(hash, enc):
"""The inverse of `encode_data`."""
text = urllib.parse.unquote(enc)
m = hashlib.md5(str.encode('{}{}'.format(my_secret, text))).hexdigest()[:12]
if m != hash:
raise Exception("Bad hash!")
data = pickle.loads(zlib.decompress(base64.b64decode(text)))
return data
hash, enc = encode_data(['Hello', 'Goodbye'])
print(hash, enc)
print(decode_data(hash, enc))
There are some things that I needed to take into account:
in Python 3, the way to encode/decode into base64 is by using the base64 module
to cast a bytes object into a string, I used the bytes.decode method
to cast a string object into a bytes object, I used the str.encode function
the hashlib.md5 function accepts a bytesobject (strings need to be previously encoded)
I changed the way you concatenate strings (i.e. str1 + str2) with a more pythonic construction: '{}{}'.format(str1, str2)
I hope this will be helpful ;)
I recommend to use the built-in secrets modules, especially secrets.token_urlsafe.