user2387537
user2387537

Reputation: 399

base64.b64encode error

I'm trying to encrypt and decrypt text in python, and I know how to do that - the problem is that I don't want to have to use a set amount of letters like 16 or 32. I want to be able to use as many letters/numbers as I want, and then encrypt the text without any errors.

base64 in python would be perfect, because I can do just that, but when I want to do:

password = "password"
encode = base64.b64encode(password)

... it returns an error because it's not in bytes; it has to be like:

encode = base64.b64encode(b'password')

That works completely fine, but I don't want to do that.

import base64

password = "hello world"  
encoded = base64.b64encode(password.encode("utf-8"))
print(encoded)
decoded = base64.b64decode(encoded)
print(decoded)

that is now my code and it works fine but i now know i was using the wrong type of thing i need to know on how to use AES.

Upvotes: 16

Views: 57245

Answers (1)

Brendan Long
Brendan Long

Reputation: 54242

In Python 3, you need to convert your string to bytes, since base64 encoding depends on the encoding of the string, and Python 3 doesn't make assumptions about string encoding. See this question.

import base64

# Assuming UTF-8 encoding, change to something else if you need to
base64.b64encode("password".encode("utf-8"))

This page explains why strings act differently in Python 3:

The biggest difference with the 2.x situation is that any attempt to mix text and data in Python 3.0 raises TypeError, whereas if you were to mix Unicode and 8-bit strings in Python 2.x, it would work if the 8-bit string happened to contain only 7-bit (ASCII) bytes, but you would get UnicodeDecodeError if it contained non-ASCII values. This value-specific behavior has caused numerous sad faces over the years.

And, like sberry said, base64 encoding is not encryption. If you actually want this to be secure, you'll need to use something like AES, or if you just want to safely store the password, use bcrypt or PBKDF2.


Here's an example of using PyCrypto to encrypt something with AES, using a key derived from a password using PBKDF2.

#!/usr/bin/env python3

from Crypto.Cipher import AES
from Crypto import Random
from Crypto.Protocol.KDF import PBKDF2

def make_key(password, salt = None):
    if salt is None:
        # Generate a key from the password
        salt = Random.new().read(8)

    # You probably want to adjust the number of iterations
    # based on your target platform and willingness to wait.
    # Somewhere around 10,000 will give you reasonable security.
    # If you don't mind the wait, 100,000 is better.
    # If you have a really fast computer, or are willing to wait a long
    # time, feel free to set it even higher.
    key = PBKDF2(password, salt, AES.block_size, 100000)
    return (key, salt)

def encrypt(message, key):
    # The IV should always be random
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CFB, iv)
    ciphertext = cipher.encrypt(message.encode("utf-8"))
    return (ciphertext, iv)

def decrypt(ciphertext, key, iv):
    cipher = AES.new(key, AES.MODE_CFB, iv)
    msg = cipher.decrypt(ciphertext).decode("utf-8")
    return msg

def main():
    # Encryption
    password = "correct horse battery staple"
    message = "Super secret information that shouldn't be seen by attackers"
    key, salt = make_key(password)
    ciphertext, iv = encrypt(message, key)
    print(b"The ciphertext is: " + ciphertext)

    # Decryption

    # In normal cases, you now need to store the salt and iv somewhere
    # Usually you prepend them to the ciphertext
    # I don't feel like doing that, so we'll just assume that I got the salt
    # and IV somehow.
    key, _ = make_key(password, salt)
    cleartext = decrypt(ciphertext, key, iv)
    print("The cleartext is: " + cleartext)

if __name__ == "__main__":
    main()

Just using AES like this provides confidentiality (an attacker can't read the message without the password), but not integrity (an attacker could insert data into the ciphertext, and the only way you could notice is that it would probably decrypt as garbage). To prevent that, you can also use a message authentication code to ensure that the ciphertext hasn't been changed by someone who doesn't have the password.


I thought this was an interesting exercise, so I put a more complete example in a BitBucket repo. It adds an HMAC, and reads and writes from a JSON file.

Upvotes: 35

Related Questions