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.
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.
I have a nested python dictionary that is serialized into a json string, that I am further converting to a compressed Gzip file and base64 encoding it. However, once I convert it back to the JSON string, it adds \\ to the string, which isn't in the original JSON string before conversion. This happens at each of the nested dictionary levels. These are the functions:
import json
import io
import gzip
import base64
import zlib
class numpy_encoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
else:
return super(numpy_encoder, self).default(obj)
def dict_json_dump(dictionary):
dumped = json.dumps(dictionary, cls = numpy_encoder, separators=(",", ":"))
return dumped
def gzip_json_encoder(json_string):
stream = io.BytesIO()
with gzip.open(filename=stream, mode='wt') as zipfile:
json.dump(json_string, zipfile)
return stream
def base64_encoder(gzip_string):
return base64.b64encode(gzip_string.getvalue())
We can use the functions as follows:
json_dict = pe.dict_json_dump(test_dictionary)
gzip_json = pe.gzip_json_encoder(json_dict)
base64_gzip = pe.base64_encoder(gzip_json)
When I check the base64_gzip with the following function:
json_str = zlib.decompress(base64.b64decode(base64_gzip), 16 + zlib.MAX_WBITS)
I get the JSON string back in a format like this(truncated):
b'"{\\"trainingResults\\":{\\"confusionMatrix\\":{\\"tn\\":2,\\"fn\\":1,\\"tp\\":1,\\"fp\\":1},\\"auc\\":{\\"score\\":0.5,\\"tpr\\":[0.0,0.5,0.5,1.0],\\"fpr\\":[0.0,0.333,0.667,1.0]},\\"f1\\"
This isn't the full string, but the contents of the string itself is accurate. What I'm not sure about is why the back slashes are showing up when I convert it back. Anyone have any suggestions? I tried utf-8 encoding on my JSON as well, with no luck. Any help is appreciated!
You're doing JSON encoding twice: Once in dict_json_dump() and again in gzip_json_encoder(). Since json_string is already encoded, you don't need to call json.dump() in gzip_json_encoder().
def gzip_json_encoder(json_string):
stream = io.BytesIO()
with gzip.open(filename=stream, mode='wt') as zipfile:
zipfile.write(json_string)
return stream
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'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))
Here is an answer which gives some information on how to base64 encode a file. However, I also want to pass in the filetype and mimetype. for the information in the base64 encoded string.
So far I have for my base64 string:
x=base64.b64encode(open('/Users/user/Desktop/img.PNG').read())
What is the correct information to prepend, and how would I do this?
It seems like the following is how I would get the base64 file information to pass to the server:
file = '/Users/user/Desktop/img.PNG'
prepend_info = 'data:%s;base64' % mimetypes.guess_type(file)[0]
base_64_data = open(file).read().encode('base64')
image_data_base64 = '%s,%s' % (prepend_info, base_64_data)
This then gives me:
data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wB...
Perhaps something along these lines:
from __future__ import print_function
import base64
import binascii
import os
def base64_encode_file(filename):
filetype = os.path.splitext(filename)[1][1:] # remove leading '.' from ext
with open(filename) as file:
data = file.read()
return base64.b64encode(','.join((filename, filetype, data))), data
filename = 'C:/Users/martin/Desktop/img.PNG'
#filename = '/Users/user/Desktop/img.PNG'
encoded, data = base64_encode_file(filename)
print('encoded: {} (hex file data: {})'.format(encoded, binascii.hexlify(data)))
decoded = base64.b64decode(encoded).split(',', 2)
print('decoded:', decoded[0], decoded[1], binascii.hexlify(decoded[2]))
Output:
encoded: QzovVXNlcnMvbWFydGluL0Rlc2t0b3AvaW1nLlBORyxQTkcsiVBORwo=
(hex file data: 89504e470a)
decoded: C:/Users/martin/Desktop/img.PNG PNG 89504e470a