Python – Encryption.

Today, I will be showing 4 different methods to encrypt your data, in Python.
October 4, 2020

Are you in need of an easy way to encrypt passwords, sensitive corporate emails, private diary, bank account info, or other stuff? Today, I will be showing 4 different methods to encrypt your data, in Python.

Python – Encryption.

Today, I will be showing 4 different methods to encrypt your data, in Python.
October 4, 2020

Are you in need of an easy way to encrypt passwords, sensitive corporate emails, private diary, bank account info, or other stuff? Today, I will be showing 4 different methods to encrypt your data, in Python.


Python – Encryption.

Today, I will be showing 4 different methods to encrypt your data, in Python.
October 4, 2020

Are you in need of an easy way to encrypt passwords, sensitive corporate emails, private diary, bank account info, or other stuff? Today, I will be showing 4 different methods to encrypt your data, in Python.


Are you in need of an easy way to encrypt passwords, sensitive corporate emails, private diary, bank account info, or other stuff? Today, I will be showing 4 different methods to encrypt your data, in Python.


Getting Started.

The way that I’m using the word, encrypt means taking a string of text ( password, bank info, private diary, other ) and change it in such a way that it’s no longer understandable by humans. The purpose is to keep the information confidential: safe from interception and/or being read by people who should not.

The word decrypt means to take an encrypted text, and change it back into human readable form.

Encrypted text could be saved to a SQLite database or json file, attached to an email, sent to another computer over a socket or by telnet connection, or simply saved to a text file.

Please feel free to copy the examples I am showing in this article, and use them in your own projects. All the information I’m showing here is public domain and FREE.

Personally, I think the hardiest part of this topic is learning how to spell the words correctly.
The correct spellings are: Encryption and Decryption.


Cryptography

There is a type of encryption based on prime numbers, that uses two keys (a public key available to anyone, and a private key that available only to the receiver), that is used to send messages between users.

This is commonly called cryptography.

In Cryptography, anyone can send a message using the public key. But ONLY the user who is holding the private key can decrypte the message. Thus insuring that the message is seen ONLY by the person to whom it was sent. It’s a “many to one” kind of encryption system.

This is NOT the kind of encryption that this article is covering. Please don’t misunderstand me, cryptography is VERY useful and well worth the time to learn.

But the kind of encryption that I’m covering in this article is focused more on saving encrypted data to a file, rather than transmitting of data from one user to another.

The encryption methods covered in today’s article typically uses only one key. Any users who is holding this one key, can encrypt and decrypte the data.


Bytes to hexadecimal and back again.

Several of the encryption methods that I’m about to show, will return an encrypted a string that appears to be random bytes. These bytes can often include the ascii control codes for carrage-return, tabs, quotation marks, backspace, and others.

These ascii control codes can become a problem if you are saving something like an encrypted password, to a SQLite database, or json file, or even writing it to a simple text file. Consider what would happen if the 5th encrypted password you save to your database has a line-feed character right in the middle of it.

So to get around this problem, here are two helper functions:

The function bytes2hex() will convert a string or bytearray, into a string of hexadecimal values. The string of hexadecimal values is made up of characters in the range of ‘0’ to ‘F’, and has no ascii control codes. Therefore, it can be safely saved to your SQLite database, or json file, or whatever.

The function hex2bytes() reverses the processes. It will convert a string of hexadecimal values, back into a string.

Why not just uses the str.encode() and str.decode() methods?
Will, str.encode() method returns Bytes, not a String. This can cause many problems when trying to format it into something like an SQL command.
I find that converting encrypted text into a hexadecimal string is simply easier to implement, and to troubleshoot.


def bytes2hex(text):
    """Convert a bytearray or string, into a hex string."""
    reply = ""
    for x in range(0,len(text)):
      if isinstance(text, str): c = ord(text[x])
      if isinstance(text, (bytes, bytearray)): c = text[x]
      r = hex(c).split("x")[1].upper()
      if len(r) < 2: r = "0" + r
      reply = reply + r
    return reply

def hex2bytes(text):
    """Convert a hex string, into a bytearray."""
    reply = ""
    for x in range(0,len(text),2):  
      reply = reply + chr(int( text[x:x+2], 16) )
    return reply  


# Example of how to uses the above funcitons.

original = "This is the text."
encrypted = bytes2hex( original )
decrypted = hex2bytes( encrypted )

print("original: ", original )
print("encrypted: ", encrypted )
print("decrypted: ", decrypted )


original: This is the text.
encrypted: 546869732069732074686520746578742E
decrypted: This is the text.


Method 1: Cryptography module

Perhaps the best known method of encryption in Python is the cryptography module.

This module is NOT one of the modules that come prepackaged with python ( called the ‘Standard Modules’ or ‘Standard Libraries’ ). So to uses it, you will need to install it using the pip utility.

For more info about using the pip utility, see my previous article “What is PIP, and how to use it.”
http://gsw7.net/K700005.php

On most computers, the command to install the cryptography module is:
pip install cryptography

On some Linux computers, you might need to uses this command instead:
pip3 install cryptography

The advantages of using cryptography are:
1. The python code is very simple and clean.
2. Uses a very strong encryption method.

The disadvantages are:
1. You need to install a non-standard module, which is an extra step for setup.
2. After the “key” has been generated, it needs to be saved and sent to anyone who needs to work with the data. Which makes changing the key difficult, and open to the possibility of being intercepted by an unauthorized person.
3. This method of encryption is NOT supported in other programming languages, like Java and C+.
4. The encrypted string can be very long, several times longer than the original text.

As of the time that I am writing this article, the cryptography project is still under active development. Meaning that there are still “Maintainers” who are keeping this module up-to-date and free of bugs.

There is a list of “Maintainers” on the project web-page, who you could ask for assistance if you really get stuck. But PLEASE read the documentation BEFORE you start sending messages.

The official web-page for this module can be found at:
https://pypi.org/project/cryptography/


from cryptography.fernet import Fernet

def generateKey():
    """Generate a new key."""
    return Fernet.generate_key()

def encrypt(text, key):
    """Encrypt a string of text using key."""
    return Fernet(key).encrypt( bytes(text, 'utf-8'))

def decrypt(text, key):
    """Decrypt the string created by encrypt()."""
    return Fernet(key).decrypt( text )


# Example of how to use the above functions.

key = generateKey()

original = "This is a test."
encrypted = encrypt( original, key)
decrypted = decrypt( encrypted, key )

print("key: ", key )
print("original: ", original )
print("encrypted: ", encrypted )
print("decrypted: ", decrypted )


key: b'Lqi9suCPli1H0Zo_oj-QLQONoDV2RN943y56_H62Tzw='
original: This is a test.
encrypted: b'gAAAAABfdqZtB8ARa1v9SctPLTllRT8_eyzf_ADzsiUK4L27cXB8IiWi6Tw4dEmBlqAZHMxqcIbrKPWed5Wac-x-s3n-M1T1eg=='
decrypted: b'This is a test.'


Method 2: Pycrypto module.

Just about everything that I said about Method 1 (above) also applies to Method 2, with one big exception:

WARNING: This module is no longer under active development. Meaning that if you have questions, there are no “Maintainers”, who you could ask. The last update was made in 2013 (about 8 years ago). Some developers consider this module to be obsolete. But others feel that it’s still quite usable.

This module is NOT one of the modules that come prepackaged with python ( called the ‘Standard Modules’ or ‘Standard Libraries’ ). So to uses it, you will need to install it using the pip utility.

For more info about using the pip utility, see my previous article “What is PIP, and how to use it.”
http://gsw7.net/K700005.php

On most computers, the command to install the Pycrypto module is:
pip install pycrypto

On some Linux computers, you might need to uses this command instead:
pip3 install pycrypto

The advantage of using Pycrypto are:
1. The python code is very simple and clean.
2. Uses a very strong encryption method.

The disadvantages are:
1. You need to install a non-standard module, which is an extra step for setup.
2. This module is no longer under active development.
3. This method of encryption is NOT supported in other programming languages, like Java and C+.
4. The encrypted string can be very long, several times longer than the original text.

The project page for this module is:
https://pypi.org/project/pycrypto/


from Crypto.Cipher import AES

def encrypt(text, key):
    obj = AES.new( key, AES.MODE_CBC, 'This is an IV456')
    t = text
    # The length of t must be a multiple of 16 characters.
    while (len(t) % 16) != 0: t = t + chr(32)
    return obj.encrypt( t )

def decrypt(ciphertext, key):
    obj = AES.new( key, AES.MODE_CBC, 'This is an IV456')
    return obj.decrypt(ciphertext)

# Example of how to use the above functions.

key = 'This is a key123'

original = "This is the text."
encrypted = encrypt( original, key)
decrypted = decrypt( encrypted, key )

print("key: ", key )
print("original: ", original )
print("encrypted: ", encrypted )
print("decrypted: ", decrypted )


key: This is a key123
original: This is the text.
encrypted: b' \t\xfe\xeb5Iu.\x1d\xa4\x13Fx\xf3l\xf0o\xeck\xfd\xc8\x0f\xc0\xbb\x0f\x90\xe8\xc2\xd2#\xd8\xaa'
decrypted: b'This is the text.


Method 3: Flipper()

This is a supper simple way to Encrypt / Decrypt a string of text, but it is surprisingly effective. All this function does is reverse the order of the characters in the string, and flips the 6th and 8th bites of each byte.

Any serious code-breaker could work it out in a few minutes, but this isn’t meant to foil the “experts”. Rather, it’s meant to deter the average person trying to read your text. They will simply look at the string of ascii goopity goop for a few minutes trying to see some kind of a pattern, give up, and move on. It’s so simple, and yet, so strangely effective.

The one function, flipper(), does both the encrypting and decrypting.

If you intend to save the encrypted data to a file or database, you definitely want to use the bytes2hex() and hex2bytes() functions I mentioned earlier in this article. The flipper() function sees ascii control characters as just byte of data, and the encrypted string it produces may ( probably will ) be full of ascii control characters.

The advantages of using Flipper() are:
1. The python code is very simple and clean.
2. No key is needed.
3. No 3rd party module needs to be installed.
4. Easily supported in other programming languages.
5. The encrypted string is short; its the same length as the original text.

The disadvantages are:
1. Very week encryption.
2. No technical support if you should need help.



def bytes2hex(text):
    """Convert a bytearray or string, into a hex string."""
    reply = ""
    for x in range(0,len(text)):
      if isinstance(text, str): c = ord(text[x])
      if isinstance(text, (bytes, bytearray)): c = text[x]
      r = hex(c).split("x")[1].upper()
      if len(r) < 2: r = "0" + r
      reply = reply + r
    return reply

def hex2bytes(text):
    """Convert a hex string, into a bytearray."""
    reply = ""
    for x in range(0,len(text),2):  
      reply = reply + chr(int( text[x:x+2], 16) )
    return reply  

def flipper(text):
    reply = ""
    for x in range(0, len(text)):  
      reply = chr(ord(text[x]) ^ 5) + reply
    return reply


# Example of how to use the above functions.

original = "Do not go gentle into that good night."
encrypted = bytes2hex( flipper( original ) )
decrypted = flipper( hex2bytes( encrypted ) )

print("original: ", original )
print("encrypted: ", encrypted )
print("decrypted: ", decrypted )


original: Do not go gentle into that good night.
encrypted: 2B716D626C6B25616A6A622571646D71256A716B6C256069716B6062256A6225716A6B256A41
decrypted: Do not go gentle into that good night.


Method 4: The Scrambler

So now we come to the method that I developed from scratch. I call it “The Scrambler”. Originally written in VBScript around 2014, I have used it in many projects over the years.

The Scrambler preforms some very nasty math tricks, that are designed to make it very difficult for any code-breaker to figure out, just so long as you use a strong password.

The modules uses are all members of the Standard Modules, so you don’t need to install anything to make it work. But, you will need to copy the Scrambler Class (bellow) into your project.

The advantages of using The Scrambler are:
1. The python code is very simple and clean.
2. No 3rd party module needs to be installed.
3. Very strong encryption.
4. Encrypted string is in hexadecimal, so no need to convert it to something else before saving to SQLite, json, or text files.

The disadvantages are:
1. Not supported in other programming languages, but could be easily ported into Java, C+, other.
2. No technical support if you should need help.
3. Will increase the size of your python script by about 60 lines of code.
4. Tends to be slower to execute than the other methods.



class Strambler():
  """
  Strambler() class.
  Written by Joe Roten.
  This class is used for encrypting and decrypting data.
  """

  import random

  def _int2hex(self, i):
    r = hex(i).split("x")[1].upper()
    if len(r)<2: r = "0" + r
    return r

  def _h2i(self, text, index):
     return int(text[index:index+2], 16)

  def _ra(self):
    return self.random.randint(0,255)

  def _genTL(self, pa, pn):
    TL = []
    c = 0
    for x in range(0,pn): TL.append( x % 255 )
    for x in range(0,len(pa)):
      for y in range(0,len(TL)-1):
        ( TL[y], TL[c] ) = ( TL[c], TL[y] )
        c = (c + ord(pa[x])) % len(TL)
    return (TL,c)

  def encrypt(self, text, password,pn=2683):
    """Encrypt text into a hex string."""
    # Note: pn must be a prime number grater than 2000.
    (d, k, r1, r2) = ( 0, "", self._ra(), self._ra() ) 
    pa = password + chr(r1) + chr(r2)
    (TL,c) = self._genTL(pa,pn)
    (r3, r4) = ( TL[TL[7]]^TL[TL[67]], TL[TL[72]]^TL[TL[143]] )
    p2 = ( TL[TL[TL[448]]] ^ len(pa) ^ c ) % 255
    for x in range(0, len(text)):
      b = ord(text[x])  
      k = k + self._int2hex( b ^ TL[x % len(TL)] ^ TL[TL[c]] )
      c = (c + p2) % len(TL)
      p2 = p2 ^ TL[b]
    return self._int2hex(r1) + self._int2hex(r2) + self._int2hex(r3) + self._int2hex(r4) + k

  def decrypt(self, text, password, pn=2683):
    """Decrypt a hex string back into text."""
    # The value of pn, must be the same as used to encrypt.
    (r1,r2,r3,r4) = ( self._h2i(text,0), self._h2i(text,2), self._h2i(text,4), self._h2i(text,6) )
    reply = ""
    pa = password + chr(r1) + chr(r2)
    (TL,c) = self._genTL(pa,pn)
    p2 = ( TL[TL[TL[448]]] ^ len(pa) ^ c ) % 255
    if r3 != TL[TL[7]]^TL[TL[67]] or r4 != TL[TL[72]]^TL[TL[143]]:
      reply = "**Invalid password"
    else:
      for x in range(8, len(text), 2):
        g = int(x/2) - 4
        j = self._h2i(text,x)
        b = j ^ TL[g % len(TL)] ^ TL[TL[c]] 
        reply = reply + chr( b )
        c = (c + p2) % len(TL)
        p2 = p2 ^ TL[b]
    return reply

  # End of class Strambler()


  

# Example of using the above class.

ec = Strambler()

original = "Hello world, This is a test."
password = "Rincewind the WIZZARD."

encrypted = ec.encrypt( original, password )
decrypted = ec.decrypt( encrypted, password )

print("original: ", original )
print("encrypted: ", encrypted )
print("decrypted: ", decrypted )


original: Hello world, This is a test.
encrypted: DCA72134E90C7665FB54BB0DB180EC4D1FC3D4E49332995AC70ACEE5D9867B25
decrypted: Hello world, This is a test.

Using a USB memory stick as a physical key.

Most of the above methods use an encryption key or password. But instead of saving the key on the hard drive, consider saving the key on a usb memory stick, and keeping it in your pocket or on your key-ring.

You would then have a physical key, which needs to be plugged into the usb port to encrypt or decrypt any data. Take the USB stick with you when you walk away, and the encryption application on your computer is basically locked.

I recommend that you give the key file a name like GraphicDriver.dll, so as to hide what it’s really used for. This would be just one more level of security.


import os

keyfile = "/media/MyAccount/USB163/GraphicDriver.dll"
#keyfile = "E:\GraphicDriver.dll" # On Windows

key = None
if os.path.exists(keyfile):
   with open(keyfile,"r") as t:
      key = t.read().strip()
else:
   print("Key USB is not in the port.") 
     


Complex password does not mean hard to remember.

If you intend to commit your key (or a password) to memory, having to type it in when every you start the application, you might want to consider something like this:

What if your key was the first 15 words of the novel “Tarzan of the Apps”?
I had this story from one who had no business to tell it to me
No one every said that your key should not include spaces. It’s easy to remember, or look-up if you forget it. Yet no one would every guess it.

Or perhaps the first spoken sentence from “The Life of King Henry the Eighth” by William Shakespeare, Scene 1, including the punctuation:
Good morrow, and well met.
Again, easy to remember, or look-up if you forget it.

Basically, what I’m saying here is that you don’t need to limit yourself to passwords like MonkeyF1Sh, or G32K$8888. Be creative. Keep the code-breakers out by using something long and out of the ordinary. Complex does not mean hard to remember.


Encrypting large amounts of data.

The examples that I have been showing in this article have all used very short fragments of text. But there is no reason why the text to be encrypted, using any of these 4 methods, can’t be 100,000 characters long, or more.

The entire contents of a large text file can be read in as one large string of text, encrypted with a password, and saved again.

Or, you could create a simple text editor using the python tkinter package, and have the text encrypted / decrypted as it is saved or loaded.


In concussion.

And that concludes what I have to say about Encryption in python. I hope that someone out there find’s this useful.

Everyone have a good day, and be kind to each other.

Joe Roten. www.gsw7.net/joe

Last updated: 2020-10-04



Written by Joe Roten

Computer tech, Graphic Artist, Photographer, Writer, Educator, Programmer, Jack of many trades, Social gadfly, and Scholar without portfolio. http://www.gsw7.net/joe/

Written by Joe Roten

http://www.gsw7.net/joe/

As always

The information on my website is FREE.
But donations to help pay for Coffee and Beer are always welcomed.
Thanks.



tkinter