Package: dcrypt
dcryptUse RSA + Fernet encryption to encrypt and decrypt text and Python objects.InstallationInstall with pip:pipinstalldcryptUsagedcryptcontains three classes that can be used for encryption and decryption:TextCrypt: Encrypts and decrypts text.ObjectCrypt: Encrypts and decrypts text and Python objects (usingpickle).JSONCrypt:ObjectCryptthat encrypts into a JSON parsable format.Let's start by encrypting some text we want to keep secret:importdcrypt# First, we create a cryptkeycryptkey=dcrypt.CryptKey()# Then, we create a TextCrypt object with the keytext_crypt=dcrypt.TextCrypt(key=cryptkey)# Now, we can encrypt some textencrypted_text=text_crypt.encrypt("This is a secret message!")print(encrypted_text)# And decrypt it againdecrypted_text=text_crypt.decrypt(encrypted_text)print(decrypted_text)How about encrypting Python objects?# We can use our existing cryptkey# Create an ObjectCrypt object with the keyobject_crypt=dcrypt.ObjectCrypt(key=cryptkey)# Encrypt a Python objectmy_secrets={"passcode":1234,"password":"password123",}encrypted_object=object_crypt.encrypt(my_secrets)print(encrypted_object)# The Output would be something like:# {#   "passcode": "gAAAAABgJ0Z...",#   "password": "gAAAAABgJ0Z...",# }You could also decide to use the object crypt to encrypt text too.Okay! Let's assume that we want to storemy_secretsin JSON format. It would be nice ifmy_secretsis encrypted in a format that is JSON serializable. We can do this by using theJSONCryptclass:# Let's add a tuple of emails to our secretsmy_secrets["emails"]=("user@host.com","abc@xyz.com")# With JSONCryptjson_crypt=dcrypt.JSONCrypt(key=cryptkey)encrypted_secrets=json_crypt.encrypt(my_secrets)# Let's decrypt it againdecrypted_secrets=json_crypt.decrypt(encrypted_secrets)# Just to be sure, let's check that the decrypted secrets are the same as the original secretsassertdecrypted_secrets==my_secrets# Oops! We get an error:# AssertionError# Why? Because the tuple was converted to a list when we encrypted it.# So take note of this when using JSONCrypt.CryptKeyA cryptkey is simply a key that is used to encrypt and decrypt data.Let's create a cryptkey:importdcryptcryptkey=dcrypt.CryptKey()Hmm... that was easy. But what actually is a cryptkey? A cryptkey is an object containing a signature used to encrypt and decrypt data. Wondering what the signature is? A cryptkey signature contains four things:A rsa public keyA rsa private keyAn encrypted master key (Fernet key)The hash method used to sign and verify the master keyThe rsa keys are used to encrypt and decrypt the master key. The master key is used to encrypt and decrypt data. The rsa keys are generated using thersalibrary. The master key is generated using thecryptographylibrary'sFernetclass.What if we want stronger encryption? We can specify the keys signature strengthcryptkey=dcrypt.CryptKey(signature_strength=2)# The default is 1. But we can specify 2 or 3 for stronger encryption.# The caveat is that the higher the signature strength, the longer it takes to generate the cryptkey.We can also specify the hash method used to sign and verify the master keycryptkey=dcrypt.CryptKey(hash_algorithm="SHA-512")# See `dcrypt.signature.SUPPORTED_HASH_ALGORITHMS` for a list of supported hash methods.Saving and Loading CryptKeysI know, I know. You want to save your cryptkey so you can use it later. You can do this by saving the cryptkey's signature to a file. Let's see how:importdcrypt# Shinny new cryptkeycryptkey=dcrypt.CryptKey()# Now, let's save itcryptkey.signature.dump("./secrets_folder/cryptkey.json")# Yes! We saved it. Now, let's load our key signature back and recreate our cryptkeysignature=dcrypt.Signature.load("./secrets_folder/cryptkey.json")cryptkey=dcrypt.CryptKey(signature=signature)# Yay! We have our cryptkey back.Another reason why you may want to save your key signature is to remove the overhead of generating a new cryptkey every time you want to encrypt or decrypt data. Especially when the signature strength is maxed out(3). You can just load the signature from a file and use it to create a new cryptkey.Let's talk about cryptkey signaturesThe cryptkey signature is a NamedTuple which contains...? Right! A public key, a private key, an encrypted master key and a hash method.The cool thing about cryptkey signatures is that once created, they cannot be modified. So we can access the public key, private key, encrypted master key and hash method without worrying about them being modified.Let's see how we can use cryptkey signatures:importdcryptsignature=dcrypt.CryptKey.make_signature()# Yes! we use the `make_signature` classmethod to create a cryptkey signature.# Now, let's access the public keypublic_key=signature.pub_key# What about the hash method?hash_method=signature.hash_method# And the encrypted master key?encrypted_master_key=signature.enc_master_keyThere are two types of cryptkey signatures:SignatureCommonSignatureWhat are the differences between them? Let's start with theCommonSignature.
ACommonSignatureis a cryptkey signature whose values are all strings. This means that it can be easily serialized and deserialized. This is the type of signature that is saved to a file when we use thedumpmethod.Unlike theCommonSignature, aSignatureis a cryptkey signature whose values are not all strings. Some are byte type. This means that it cannot be easily serialized and deserialized. This is the type of signature that is used to create a cryptkey.However, we can convert aSignatureto aCommonSignatureand vice versa:importdcrypt# Let's create a cryptkey signaturesignature=dcrypt.CryptKey.make_signature()# Now, let's convert it to a common signaturecommon_signature=signature.common()# And back to a signaturesignature=dcrypt.Signature.from_common(common_signature)Easy, right? But why do we need to convert a signature to a common signature? Well, we need to do this when we want to save a cryptkey signature to a file. We can't save aSignatureto a file. We can only save aCommonSignatureto a file.Another use case is if we need to send a cryptkey signature over a network, we need to convert it to a common signature first and then convert it back to a signature when we receive it.importdcryptimportrequests# Let's create a cryptkey signaturesignature=dcrypt.CryptKey.make_signature()# Now, let's convert it to a common signaturecommon_signature=signature.common()# Let's send it over a networkrequests.post("https://example.com",json=common_signature.json())# Now, let's receive itcommon_signature_as_json=requests.get("https://example.com").json()# Construct a common signature from the jsoncommon_signature=dcrypt.CommonSignature(**common_signature_as_json)# And convert it back to a signaturesignature=dcrypt.Signature.from_common(common_signature)# Easy peasy!If you noticed, we converted the common signature to json before sending it over the network. You do this using thejsonmethod of theCommonSignatureclass.Encrypting function outputSay you have a method in a class calledHumanwhich returns the contact information of the human which will be sent over a network. You may want to encrypt the result of the method before sending it. How do you do this?First let's define ourHumanclass:fromdataclassesimportdataclass@dataclassclassHuman:name:strgender:stremail:strphonenumber:straddress:str...defget_contact_info(self):return{"email":self.email,"phonenumber":self.phonenumber,}Now, let's create a cryptkey and anObjectCryptobject:importdcrypt# Create a cryptkeycryptkey=dcrypt.CryptKey()# Create an ObjectCrypt objectobject_crypt=dcrypt.ObjectCrypt(key=cryptkey)# Let save the cryptkey signature to a filecryptkey.signature.dump("./secrets_folder/cryptkey.json")All that's left is to decorate theget_contact_infomethod with the object crypt we just created:classHuman:...@object_cryptdefget_contact_info(self):return{"email":self.email,"phonenumber":self.phonenumber,}That's it! Now, the result of theget_contact_infomethod will be encrypted before it is returned and yes you can decrypt it with the same object crypt or create a new object crypt with the already saved cryptkey signature.tolu=Human(name="Tolu",gender="Male",email="tioluwa.dev@gmail.com",phonenumber="08012345678",address="Lagos, Nigeria.")# Let's get his contact infoencrypted_contact_info=tolu.get_contact_info()# The output would be something like:# {#   "email": "gAAAAABgJ0Z...",#   "phonenumber": "gAAAAABgJ0Z...",# }# Now, let's decrypt itsignature=dcrypt.Signature.load("./secrets_folder/cryptkey.json")new_cryptkey=dcrypt.CryptKey(signature=signature)new_object_crypt=dcrypt.ObjectCrypt(key=new_cryptkey)decrypted_contact_info=new_object_crypt.decrypt(contact_info)# The output should be:# {#   "email": "tioluwa.dev@gmail",#   "phonenumber": "08012345678",# }You are now ready to usedcryptto encrypt and decrypt your data. Goodluck!ContributingContributions are welcome! Please feel free to submit a Pull Request.TestingTo run the tests, simply run the following command in the root directory of your cloned repository:python-munittestdiscovertests"test_*.py"