When I updated a test system to Fedora 39 Beta, all of my encryption stuff started failing with:
Expected instance of hashes.HashAlgorithm
deep in rust code.
This worked with Fedora 38 and cryptography 37.0.2 but fails with Fedora 39 and Cryptography 41.0.3 (and 41.o.4).
#! /usr/bin/env python
import os
import sys
import uuid
import base64
import traceback
from base64 import b64encode
import cryptography
from cryptography.fernet import InvalidToken, Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
class FCrypt:
def __init__(self,
pswd = "123456789012345678890"):
self.charset = 'ASCII'
slt = os.urandom(16)
kdf = PBKDF2HMAC(algorithm=hashes.SHA256, length=32,
salt=slt, iterations=480000)
pwd = b64encode(bytes(pswd, self.charset))
pwd = base64.urlsafe_b64encode(kdf.derive(pwd))
self.cryptObj = Fernet(pwd)
pass
def encrypt(self, value):
try:
t1 = bytes(value,self.charset)
t2 = self.cryptObj.encrypt(t1)
rtn = str(t2, self.charset)
return rtn
except TypeError:
print("TypeError: bytes expected not str", file=sys.stderr)
raise TypeError()
except Exception as error:
print(f"Encode Exception: {error}", file=sys.stderr)
traceback.print_stack()
raise Exception(error)
def decrypt(self, value):
try:
t1 = bytes(value, self.charset)
t2 = self.cryptObj.decrypt(t1, ttl=None)
rtn = str(t2, self.charset)
return rtn
except InvalidToken:
print(f"Invalid cryptography token: {value}", file=sys.stderr)
raise(InvalidToken(value))
pass
except TypeError:
print("TypeError: bytes expected not str", file=sys.stderr)
raise TypeError()
except Exception as err:
print(f"Decode Exception: {err}", file=sys.stderr)
traceback.print_stack()
raise Exception(err)
pass
pass
if __name__ == "__main__":
print("Test FCrypt")
print(f"Using cryptography version: {cryptography.__about__.__version__}")
fname = f"{os.environ['HOME']}/testfoo.key"
mypwd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
test_text = "Test String"
test_crpt = FCrypt(pswd=mypwd)
test_enc = test_crpt.encrypt(test_text)
f = open(fname, "w")
print(f'PASSWD = "{test_enc}"', file=f)
f.close()
f = open(fname, "r")
read_enc = f.read().split(' = ')
read_enc = read_enc[1].strip()
f.close()
test_dec = test_crpt.decrypt(read_enc)
print(f'Original:{test_text}\nEncrypted:{test_enc}\nDecrypted:{test_dec}')
os.remove(fname)
pass
This produces:
Test FCrypt
Using cryptography version: 41.0.4
Traceback (most recent call last):
File "/home/norm/bin/TestFCrypt.py", line 79, in <module>
test_crpt = FCrypt(pswd=mypwd)
^^^^^^^^^^^^^^^^^^
File "/home/norm/bin/TestFCrypt.py", line 31, in __init__
pwd = base64.urlsafe_b64encode(kdf.derive(pwd))
^^^^^^^^^^^^^^^
File "/home/norm/.local/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py", line 53, in derive
return rust_openssl.kdf.derive_pbkdf2_hmac(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Expected instance of hashes.HashAlgorithm.
When I expect:
Test FCrypt
Using cryptography version: 37.0.2
Original:Test String
Encrypted:gAAAAABlHrkL0GRgu3hupgrRvrlIBxXTztTAU_rdeauRN9-l4E6nvbA0k-oUM74MCodR4kcc2-sumZG0rzNoECfSt2Y2toMJ_w==
Decrypted:Test String
Am I doing something wrong that is finally being caught with the newer software?
>Solution :
You need to provide an object of type hashes.HashAlgorithm
, which you can do by constructing it. So do
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=slt, iterations=480000)
instead of
kdf = PBKDF2HMAC(algorithm=hashes.SHA256, length=32, salt=slt, iterations=480000)