This example works fine example:
import hashlib
m = hashlib.md5()
m.update(b"Nobody inspects")
r= m.digest()
print(r)
Now, I want to do the same thing but with a variable: var= "hash me this text, please". How could I do it following the same logic of the example ?
The hash.update() method requires bytes, always.
Encode unicode text to bytes first; what you encode to is a application decision, but if all you want to do is fingerprint text for then UTF-8 is a great choice:
m.update(var.encode('utf8'))
The exception you get when you don't is quite clear however:
>>> import hashlib
>>> hashlib.md5().update('foo')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Unicode-objects must be encoded before hashing
If you are getting the hash of a file, open the file in binary mode instead:
from functools import partial
hash = hashlib.md5()
with open(filename, 'rb') as binfile:
for chunk in iter(binfile, partial(binfile.read, 2048)):
hash.update(chunk)
print hash.hexdigest()
Try this. Hope it helps.
The variable var has to be utf-8 encoded. If you type in a string i.e. "Donald Duck", the var variable will be b'Donald Duck'. You can then hash the string with hexdigest()
#!/usr/bin/python3
import hashlib
var = input('Input string: ').encode('utf-8')
hashed_var = hashlib.md5(var).hexdigest()
print(hashed_var)
I had the same issue as the OP. I couldn't get either of the previous answers to work for me for some reason, but a combination of both helped come to this solution.
I was originally hashing a string like this;
str = hashlib.sha256(b'hash this text')
text_hashed = str.hexdigest()
print(text_hashed)
Result;d3dba6081b7f171ec5fa4687182b269c0b46e77a78611ad268182d8a8c245b40
My solution to hash a variable;
text = 'hash this text'
str = hashlib.sha256(text.encode('utf-8'))
text_hashed = str.hexdigest()
print(text_hashed)
Result; d3dba6081b7f171ec5fa4687182b269c0b46e77a78611ad268182d8a8c245b40
Related
Below is a test. When I try to decode the same string for the second time I get a error message and I really have no clue why or where to search for. Please advise.
Error:
Traceback (most recent call last):
File "test.py", line 28, in <module>
telnr_to_string = str(telnr_decrypt, 'utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x9e in position 0: invalid start byte
Code:
from Crypto.Cipher import AES
from Crypto.Util.Padding import *
from urllib.request import urlopen
import os
import urllib
import subprocess
import re
import time
import base64
import random
file_key = open("key.txt")
key = file_key.read()
key = key.encode()
file_iv = open("iv.txt")
iv = file_iv.read()
iv = iv.encode()
obj2 = AES.new(key, AES.MODE_CBC, iv)
z=1
while z < 3:
x=''
telnr_decrypt=''
telnr=''
telnr_to_string=''
telnr_cleaned=''
x=(b'\x9e\xde\x98p:\xa3\x04\x92\xb5!2K[\x8e\\\xee')
telnr_decrypt = obj2.decrypt(x)
telnr_to_string = str(telnr_decrypt, 'utf-8')
telnr_cleaned = re.sub("[^0-9]", "", telnr_to_string)
print (telnr_cleaned)
z=z+1
Just move obj2 = AES.new(key, AES.MODE_CBC, iv) into the while loop. Don't worry, cipher objects are not very stateful objects; they don't do much other than to store the key (or, for AES, probably the internal subkeys) and maintain a small buffer. Generally it is therefore a bad idea to reuse or cache them.
If you call encrypt / decrypt multiple times in succession then the methods act as if you would be encrypting one big message. In other words, they allow you to encryption / decrypt in a piecemeal fashion so that message-sized buffers can be avoided. This is not very explicitly documented, but you can see this in figure 2 in the documentation.
For CBC mode it means that the operation is identical to setting the IV to the last block of ciphertext. If the IV is wrong then the first block of plaintext will be randomized. Random bytes do generally not contain valid UTF-8 encoding, which means that decoding to string will (likely) fail.
I have been struggling with this for hours. I have the following production code (parsed out for simplicity) that runs just fine in Python 2.7:
import hashlib
import hmac
string1 = 'firststring'
string2 = 'secondstring'
digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest()
print('hmac_digest = ' + digest) # digest is a string
The output is a string like so:
hmac_digest = �!�Ni��I.u�����x�l*>a?. �
But when I run this with Python3.7, I get the following error:
Traceback (most recent call last):
File "/home/xxxx/work/py23.py", line 7, in <module>
digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest()
File "/usr/lib/python3.7/hmac.py", line 153, in new
return HMAC(key, msg, digestmod)
File "/usr/lib/python3.7/hmac.py", line 49, in __init__
raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__)
TypeError: key: expected bytes or bytearray, but got 'str'
Process finished with exit code 1
After a quite a bit of research I understood that hmac has changed in 3.4 and beyond. Therefore I redid my code to the following:
import hashlib
import hmac
import base64
string1 = 'firststring'
string2 = 'secondstring'
digest = hmac.new(key=string1.encode('utf-8'), msg=string2.encode('utf-8'), digestmod=hashlib.sha256).digest()
digest = base64.encodebytes(digest).decode('utf-8') # need to convert to string
print('hmac_digest = ' + digest)
But the output I get is completely different!
hmac_digest = 5CEZhgMDTmmFxkkudbGPxaLSytl4+gdsKj4PYT8uAJk=
How do I correctly port this code to python3.7 so I get the exact same output as 2.7?
Thanks in advance!
The issue you're hitting is that in Python 2, strings are effectively just bytes, while in Python 3 strings are unicode strings, and there is a new bytes data type for raw bytes. You can read more about the issues involved in the Python 3 porting guide (and elsewhere).
The minimal set of changes to get your code to work is probably something like this:
import hashlib
import hmac
string1 = 'firststring'.encode('utf-8')
string2 = 'secondstring'.encode('utf-8')
digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest()
print('hmac_digest = ' + repr(digest)) # digest is a string
This will output:
hmac_digest = b'\xe4!\x19\x86\x03\x03Ni\x85\xc6I.u\xb1\x8f\xc5\xa2\xd2\xca\xd9x\xfa\x07l*>\x0fa?.\x00\x99'
We're printing out the repr() of the hmac because it's just a collection of bytes. If you really wanted to print this out you would normally convert it to a hex string:
digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).hexdigest()
Which would result in:
hmac_digest = 'e421198603034e6985c6492e75b18fc5a2d2cad978fa076c2a3e0f613f2e0099'
Thanks to Josh Lee for his answer in UnicodeDecodeError, invalid continuation byte
His suggestion about using 'latin-1' to decode the digest output solved the problem for me!
Here's how my code looks in Python 3.7 now and gives me the exact same output as my code in Python 2.7:
import hashlib
import hmac
string1 = 'firststring'.encode('utf-8') # can use 'latin-1'
string2 = 'secondstring'.encode('utf-8') # can use 'latin-1'
digest = hmac.new(key=string1, msg=string2, digestmod=hashlib.sha256).digest()
print('hmac_digest = ' + digest.decode('latin-1')) # Use only 'latin-1' to decode because 'utf-8' or 'ascii' will throw a UnicodeDecodeError
Sorry to waste everybody's time because I don't know python. I use jrnla lot to write journal entries, and a while ago I encrypted a file that I know the password to, but don't know how to use this script (provided by the developer) to decrypt. I realized I had to make it executable to use it (genius right) but then got an error when I used it. Any help would be much appreciated.
Traceback (most recent call last):
File "/home/usr/src/jrnl_decrypt", line 16, in
with open(args.filepath, 'rb') as f:
AttributeError: 'Namespace' object has no attribute 'filepath'
Here's the script. I also found an alternative one in older documentation. It's below the larger script.
import argparse
from Crypto.Cipher import AES
import getpass
import hashlib
import sys
parser = argparse.ArgumentParser()
parser.add_argument("~", help="old-journal-encrypted.txt")
args = parser.parse_args()
pwd = getpass.getpass()
key = hashlib.sha256(pwd.encode('utf-8')).digest()
with open(args.filepath, 'rb') as f:
ciphertext = f.read()
crypto = AES.new(key, AES.MODE_CBC, ciphertext[:16])
plain = crypto.decrypt(ciphertext[16:])
plain = plain.strip(plain[-1:])
plain = plain.decode("utf-8")
print(plain)
# Python script to manually decrypt jrnl files
//Alt script
import hashlib, Crypto.Cipher
key = hashlib.sha256(my_password).digest()
with open("old-journal-encrypted.txt") as f:
cipher = f.read()
crypto = AES.new(key, AES.MODE_CBC, iv = cipher[:16])
plain = crypto.decrypt(cipher[16:])
plain = plain.strip(plain[-1])
plain = plain.decode("utf-8")
First of all: you're not wasting anyone's time. None of us known everything from the beginning ^^
In this line parser.add_argument("~", help="old-journal-encrypted.txt") you are adding your argument as ~, so you may use it as args.~ (if it was the case). That's not intuitive, so try changin that line to parser.add_argument("filepath", help="old-journal-encrypted.txt"). After that try to run the script again.
Edit: you're not setting the value with the 'help parameter', it's just a tooltip. You must pass the value when you call the script I.E: python my_prog.py old-journal-encrypted.txt. Make sure that the file is reacheable as well
Hope this helps you!
P.S: You have an example here in case you still have some doubts (don't hesitate to add a comment as well if that's the case ^^)
I have two keys(secret key and public key) that are generated using curve25519. I want to encode the two keys using base64.safe_b64encode but i keep getting an error. Is there any way I can encode using this?
This is my code:
import libnacl.public
import libnacl.secret
import libnacl.utils
from tinydb import TinyDB
from hashlib import sha256
import json
import base64
pikeys = libnacl.public.SecretKey()
piprivkey = pikeys.sk
pipubkey = pikeys.pk
piprivkey = base64.safe_b64encode(piprivkey)
pipubkey = base64.safe_b64encode(pipubkey)
print("encoded priv", piprivkey)
print("encoded pub", pipubkey)
This is the error I got:
Traceback (most recent call last):
File "/home/pi/Desktop/finalcode/pillar1.py", line 130, in <module>
File "/home/pi/Desktop/finalcode/pillar1.py", line 50, in generatepillar1key
piprivkey = base64.safe_b64encode(piprivkey)
AttributeError: 'module' object has no attribute 'safe_b64encode'
The reason you get this error is because the base64 library does not have a function named safe_base64encode. What do you even mean by safe_base64encode? Why do you want to encode both of your keys with base64? there is a urlsafe encoding function and there is the regular base64 encoding function.
encoded_data = base64.b64encode(data_to_encode)
or
encoded_data = base64.urlsafe_b64encode(data_to_encode)
The latter one will just have a different alphabet with - instead of + and _ instead of / so it's urlsafe. I'm not sure what you want to do but refer to the docs here
The error is telling you that the function safe_b64encode does not exist in the base64 module. Perhaps you meant to use base64.urlsafe_b64encode(s)?
I had a script in Python2 that was working great.
def _generate_signature(data):
return hmac.new('key', data, hashlib.sha256).hexdigest()
Where data was the output of json.dumps.
Now, if I try to run the same kind of code in Python 3, I get the following:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.4/hmac.py", line 144, in new
return HMAC(key, msg, digestmod)
File "/usr/lib/python3.4/hmac.py", line 42, in __init__
raise TypeError("key: expected bytes or bytearray, but got %r" %type(key).__name__)
TypeError: key: expected bytes or bytearray, but got 'str'
If I try something like transforming the key to bytes like so:
bytes('key')
I get
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: string argument without an encoding
I'm still struggling to understand the encodings in Python 3.
You can use bytes literal: b'key'
def _generate_signature(data):
return hmac.new(b'key', data, hashlib.sha256).hexdigest()
In addition to that, make sure data is also bytes. For example, if it is read from file, you need to use binary mode (rb) when opening the file.
Not to resurrect an old question but I did want to add something I feel is missing from this answer, to which I had trouble finding an appropriate explanation/example of anywhere else:
Aquiles Carattino was pretty close with his attempt at converting the string to bytes, but was missing the second argument, the encoding of the string to be converted to bytes.
If someone would like to convert a string to bytes through some other means than static assignment (such as reading from a config file or a DB), the following should work:
(Python 3+ only, not compatible with Python 2)
import hmac, hashlib
def _generate_signature(data):
key = 'key' # Defined as a simple string.
key_bytes= bytes(key , 'latin-1') # Commonly 'latin-1' or 'ascii'
data_bytes = bytes(data, 'latin-1') # Assumes `data` is also an ascii string.
return hmac.new(key_bytes, data_bytes , hashlib.sha256).hexdigest()
print(
_generate_signature('this is my string of data')
)
try
codecs.encode()
which can be used both in python2.7.12 and 3.5.2
import hashlib
import codecs
import hmac
a = "aaaaaaa"
b = "bbbbbbb"
hmac.new(codecs.encode(a), msg=codecs.encode(b), digestmod=hashlib.sha256).hexdigest()
for python3 this is how i solved it.
import codecs
import hmac
def _generate_signature(data):
return hmac.new(codecs.encode(key), codecs.encode(data), codecs.encode(hashlib.sha256)).hexdigest()