base64.b64encode error

后端 未结 1 1598
無奈伤痛
無奈伤痛 2021-01-02 08:41

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

相关标签:
1条回答
  • 2021-01-02 08:59

    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.

    0 讨论(0)
提交回复
热议问题