如何在python中加密和解密字符串?

Posted

技术标签:

【中文标题】如何在python中加密和解密字符串?【英文标题】:How do I encrypt and decrypt a string in python? 【发布时间】:2015-02-04 19:03:30 【问题描述】:

我一直在寻找有关如何加密和解密字符串的时间。但大部分都在 2.7 中,任何使用 3.2 的东西都不允许我打印它或将它添加到字符串中。

所以我想做的是以下几点:

mystring = "Hello ***!"
encoded = encode(mystring,"password")
print(encoded)

jgAKLJK34t3g(一堆随机字母)

decoded = decode(encoded,"password")
print(decoded)

你好堆栈溢出!

有没有这样做,使用 python 3.X 并且当字符串被编码时它仍然是一个字符串,而不是任何其他变量类型。

【问题讨论】:

这取决于您是在寻找极高的安全性,还是只是希望字符串乍一看不可读。 我真的不需要它来保证安全,但越安全越好!我也想保持编码字符串简短。 如果您正在寻找一些可靠的库,您可以使用 pycrypto 为例 请注意,您所做的是编码,与实际加密几乎没有关系。密码采用密钥并产生字节。这些是不可打印的,但您可以将它们编码为 Hex、Base32、Base64 等。 有像pypgpme这样的GNUPG接口 【参考方案1】:

在我的 Windows 7 系统和 Python 3.5 上编译所有最常提到的加密库时遇到了麻烦。

这是最终对我有用的解决方案。

from cryptography.fernet import Fernet
key = Fernet.generate_key() #this is your "password"
cipher_suite = Fernet(key)
encoded_text = cipher_suite.encrypt(b"Hello ***!")
decoded_text = cipher_suite.decrypt(encoded_text)

【讨论】:

如何在encoded_text = cipher_suite.encrypt(b(pk))中传递一个变量 @stone,您只需要将文本转换为字节流: encoding = "utf-8" #例如 pk = bytes(original_text, encoding) encoded_text = cipher_suite.encrypt(pk)跨度> 有什么方法可以制作自己的关键文本? 为什么每次运行cipher_suite.encrypt()都会产生不同的值? cipher_suite = Fernet(base64.urlsafe_b64encode(b'12345678901234567890123456789012'))【参考方案2】:

看看PyCrypto。它支持 Python 3.2,完全符合您的要求。

来自他们的 pip 网站:

>>> from Crypto.Cipher import AES
>>> obj = AES.new('This is a key123', AES.MODE_CFB, 'This is an IV456')
>>> message = "The answer is no"
>>> ciphertext = obj.encrypt(message)
>>> ciphertext
'\xd6\x83\x8dd!VT\x92\xaa`A\x05\xe0\x9b\x8b\xf1'
>>> obj2 = AES.new('This is a key123', AES.MODE_CFB, 'This is an IV456')
>>> obj2.decrypt(ciphertext)
'The answer is no'

如果您想加密任意大小的消息,请使用 AES.MODE_CFB 而不是 AES.MODE_CBC

【讨论】:

当我尝试导入它时,它给了我一个错误:>>> from Crypto.Cipher import AES Traceback(最近一次调用最后):文件“”,第 1 行,在 from Crypto.Cipher import AES File "C:\Python34\lib\Crypto\Cipher\AES.py", line 50, in from Crypto.Cipher import _AES ImportError: cannot import name '_AES' >>>我安装对了吗?我下载了 Crypto 并将 lib 文件夹中的文件夹复制到 pythons 目录中的 Lib 文件夹中。 复制有时是不够的。使用 python setup.py install 或在命令行中键入 pip install pycrypto。你可以在这里下载pip:lfd.uci.edu/~gohlke/pythonlibs/#pip 如果您需要加密除 n*16 字节以外的任意大小的消息,您可以使用 AES.MODE_CFB 而不是 MODE_CBC。 obj = AES.new('这是一个 key123', AES.MODE_CFB, '这是一个 IV456')。请参阅pythonhosted.org/pycrypto 的文档 我在编码'utf-8' codec can't decode byte 0xa6 in position 7: invalid start byte时遇到这个错误 错误:输入字符串的长度必须是 16 的倍数。【参考方案3】:

您可以使用库cryptocode 轻松完成此操作。以下是您的安装方式:

pip install cryptocode

加密消息(示例代码):

import cryptocode

encoded = cryptocode.encrypt("mystring","mypassword")
## And then to decode it:
decoded = cryptocode.decrypt(encoded, "mypassword")

文档可以在here找到

【讨论】:

当我运行你的代码时它给出了错误 -> AttributeError: module 'hashlib' has no attribute 'scrypt'【参考方案4】:

试试这个:

需要 Python 加密工具包 (pycrypto)

$ pip install pycrypto

pycrypto 包已过时,自 2014 年以来一直未维护。 有一个名为 pycryptodome 的替换包。

$ pip install pycryptodome

下面的代码在 python 3.8 上完美运行

代码:

from Crypto.Cipher import AES
from base64 import b64encode, b64decode


class Crypt:

    def __init__(self, salt='SlTKeYOpHygTYkP3'):
        self.salt = salt.encode('utf8')
        self.enc_dec_method = 'utf-8'

    def encrypt(self, str_to_enc, str_key):
        try:
            aes_obj = AES.new(str_key.encode('utf-8'), AES.MODE_CFB, self.salt)
            hx_enc = aes_obj.encrypt(str_to_enc.encode('utf8'))
            mret = b64encode(hx_enc).decode(self.enc_dec_method)
            return mret
        except ValueError as value_error:
            if value_error.args[0] == 'IV must be 16 bytes long':
                raise ValueError('Encryption Error: SALT must be 16 characters long')
            elif value_error.args[0] == 'AES key must be either 16, 24, or 32 bytes long':
                raise ValueError('Encryption Error: Encryption key must be either 16, 24, or 32 characters long')
            else:
                raise ValueError(value_error)

    def decrypt(self, enc_str, str_key):
        try:
            aes_obj = AES.new(str_key.encode('utf8'), AES.MODE_CFB, self.salt)
            str_tmp = b64decode(enc_str.encode(self.enc_dec_method))
            str_dec = aes_obj.decrypt(str_tmp)
            mret = str_dec.decode(self.enc_dec_method)
            return mret
        except ValueError as value_error:
            if value_error.args[0] == 'IV must be 16 bytes long':
                raise ValueError('Decryption Error: SALT must be 16 characters long')
            elif value_error.args[0] == 'AES key must be either 16, 24, or 32 bytes long':
                raise ValueError('Decryption Error: Encryption key must be either 16, 24, or 32 characters long')
            else:
                raise ValueError(value_error)

用法:

        test_crpt = Crypt()
        test_text = """Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum."""

        test_key = 'MyKey4TestingYnP'
        test_enc_text = test_crpt.encrypt(test_text, test_key)
        test_dec_text = test_crpt.decrypt(test_enc_text, test_key)
        print(f'Encrypted:test_enc_text  Decrypted:test_dec_text')

【讨论】:

我刚刚复制粘贴了您的代码,没有做任何其他事情。我的错误是:TypeError: Object type <class 'str'> cannot be passed to C code 如果您使用的是 python 3,请在此答案中使用具有相同代码的 pycryptodome 包。它在 python 3.8 上对我有用,所以我修改了答案(包括代码中的一个小错误修复)【参考方案5】:

加密数据

首先,我们需要安装密码库:

pip3 install cryptography

cryptography 库中,我们需要导入 Fernet 并开始生成密钥 - 此密钥是对称加密/解密所必需的。

要生成密钥,我们调用generate_key() 方法。

我们只需要执行一次上述方法即可生成密钥。

您需要将此密钥保存在安全的地方。如果您丢失了密钥,您将无法解密使用此密钥加密的数据。

生成密钥后,我们需要使用load_key() 加载密钥

加密消息

这是一个三步过程:

    对消息进行编码 初始化 Fernet 类 将编码后的消息传递给encrypt()方法

以下是加密消息的完整工作示例:

from cryptography.fernet import Fernet

def generate_key():
    """
    Generates a key and save it into a file
    """
    key = Fernet.generate_key()
    with open("secret.key", "wb") as key_file:
        key_file.write(key)

def load_key():
    """
    Load the previously generated key
    """
    return open("secret.key", "rb").read()

def encrypt_message(message):
    """
    Encrypts a message
    """
    key = load_key()
    encoded_message = message.encode()
    f = Fernet(key)
    encrypted_message = f.encrypt(encoded_message)

    print(encrypted_message)

if __name__ == "__main__":
    # generate_key() # execute only once 
    encrypt_message("Hello ***!")

输出:

b'gAAAAABgLX7Zj-kn-We2BI_c9NQhEtfJEnHUVhVqtiqjkDi5dgJafj-_8QUDyeNS2zsJTdBWg6SntRJOjOM1U5mIxxsGny7IEGqpVVdHwheTnwzSBlgpb80='

解密数据

要解密消息,我们只需调用Fernet 库中的decrypt() 方法。请记住,我们还需要加载密钥,因为解密消息需要密钥。

from cryptography.fernet import Fernet

def load_key():
    """
    Load the previously generated key
    """
    return open("secret.key", "rb").read()

def decrypt_message(encrypted_message):
    """
    Decrypts an encrypted message
    """
    key = load_key()
    f = Fernet(key)
    decrypted_message = f.decrypt(encrypted_message)

    print(decrypted_message.decode())

if __name__ == "__main__":
    decrypt_message(b'gAAAAABgLX7Zj-kn-We2BI_c9NQhEtfJEnHUVhVqtiqjkDi5dgJafj-_8QUDyeNS2zsJTdBWg6SntRJOjOM1U5mIxxsGny7IEGqpVVdHwheTnwzSBlgpb80=')

输出:

Hello ***!


您的密码在secret.key 中,格式类似于以下密码:

B8wtXqwBA_zb2Iaz5pW8CIQIwGSYSFoBiLsVz-vTqzw=

【讨论】:

你能告诉我如何在 Django 中使用它吗? 我的尝试: 我将加密的消息存储在数据库中。之后,我试图解密该消息并收到token must be bytes 错误! 我认为在第一步你应该有:cript_body_message = decipher.decrypt(form.message.data).decode('utf-8') 这将加密消息并准备存储。之后,您可能会使用message = Message(header=form.header.data, body=cript_body_message) 创建一个对象。最后将db.session.add(message)db.session.commit() 添加到数据库中。他应该做一些私人的事情。需要注意的是,在阅读时,需要对消息进行破译。我希望我至少能帮上一点忙。 您还应该查看:django-crypto-fields、django-cryptographic-fields、django-cryptography ... 文档和示例一样出色。快乐编码(:【参考方案6】:

虽然它很老了,但我想分享另一个想法来做到这一点:

from Crypto.Cipher import AES    
from Crypto.Hash import SHA256

password = ("anything")    
hash_obj = SHA256.new(password.encode('utf-8'))    
hkey = hash_obj.digest()

def encrypt(info):
    msg = info
    BLOCK_SIZE = 16
    PAD = ""
    padding = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PAD
    cipher = AES.new(hkey, AES.MODE_ECB)
    result = cipher.encrypt(padding(msg).encode('utf-8'))
    return result  

msg = "Hello ***!"
cipher_text = encrypt(msg)
print(cipher_text)

def decrypt(info):
    msg = info
    PAD = ""
    decipher = AES.new(hkey, AES.MODE_ECB)
    pt = decipher.decrypt(msg).decode('utf-8')
    pad_index = pt.find(PAD)
    result = pt[: pad_index]
    return result

plaintext = decrypt(cipher_text)
print(plaintext)

输出:

> b'\xcb\x0b\x8c\xdc#\n\xdd\x80\xa6|\xacu\x1dEg;\x8e\xa2\xaf\x80\xea\x95\x80\x02\x13\x1aem\xcb\xf40\xdb'

> Hello ***!

【讨论】:

【参考方案7】:

您可以按如下方式使用 Fernet:

from cryptography.fernet import Fernet
key = Fernet.generate_key()
f = Fernet(key)
encrypt_value = f.encrypt(b"YourString")
f.decrypt(encrypt_value)

【讨论】:

【参考方案8】:

用于加密

  def encrypt(my_key=KEY, my_iv=IV, my_plain_text=PLAIN_TEXT): 

       key = binascii.unhexlify('ce975de9294067470d1684442555767fcb007c5a3b89927714e449c3f66cb2a4')
       iv = binascii.unhexlify('9aaecfcf7e82abb8118d8e567d42ee86')

       padder = PKCS7Padder()
       padded_text = padder.encode(my_plain_text)

      encryptor = AES.new(key, AES.MODE_CBC, iv, segment_size=128)  # Initialize encryptor
      result = encryptor.encrypt(padded_text)  

     return 
         "plain": my_plain_text,
         "key": binascii.hexlify(key),
         "iv": binascii.hexlify(iv),
         "ciphertext": result

用于解密:

     def decrypt(my_key=KEY, my_iv=IV, encryptText=encrypttext):

        key = binascii.unhexlify(my_key)
        iv = binascii.unhexlify(my_iv)
        encryptor = AES.new(key, AES.MODE_CBC, iv, segment_size=128)  # Initialize encryptor
        result = encryptor.decrypt(binascii.a2b_hex(encryptText))
        padder = PKCS7Padder()
        decryptText=padder.decode(result)  

           return 
          "plain": encryptText,
          "key": binascii.hexlify(key),
          "iv": binascii.hexlify(iv),
          "decryptedTest": decryptText

【讨论】:

以上是关于如何在python中加密和解密字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何在.net核心中加密和解密字符串

12:字符串加密、解密

如何在 Python 中使用 scrypt 生成密码和盐的哈希值

请教 php如何对字符串加密和解密,求一个相关的实例!

解密在 PHP 中使用 MCRYPT_RIJNDAEL_256 加密的 Python 字符串

使用Python pyDes和base64模块对字符串进行加密和解密