Python中的密码学包
在以下教程中,我们将通过Python编程语言中的不同示例来了解 cryptography 包。
所以,让我们开始吧。
理解密码学包
密码学是在计算机之间传输数据或在计算机上存储数据期间保护有用信息的实践。密码学涉及将明文加密为密文以及将密文解密为明文。Python提供了对 cryptography 包的支持,使我们能够加密和解密数据。 cryptography 包的 fernet 模块具有生成密钥、将明文加密为密文以及通过 encrypt() 和 decrypt() 方法将密文解密为明文的核心函数。
如何安装Python的密码学包
为了安装Python包,我们需要使用“pip”来管理在可信公共存储库中安装模块所需的包。一旦我们有“pip”,我们可以使用以下命令从Windows命令提示符(CMD)或终端安装 cryptography 库:
语法:
$ pip install cryptography
验证安装
安装模块后,我们可以通过创建一个空的Python程序文件并编写一个 import 语句来进行验证,如下所示:
文件:verify.py
import cryptography
现在,保存上述文件并在终端中使用以下命令执行它:
语法:
$ python verify.py
如果上面的Python程序文件没有返回任何错误,则说明模块已经正确安装。然而,如果出现异常情况,请尝试重新安装该库,并建议参考官方文档。
了解Fernet(对称加密)
Fernet 是对称(也称为“密钥”)身份验证加密的实现。 Fernet 保证我们在没有密钥的情况下无法进一步操作或读取使用其加密的数据。 Fernet 还提供了通过 MultiFernet 实现密钥轮换的支持。
现在,让我们看一下 Fernet 类和一些方法,以便更详细地了解密码学的概念。
类 cryptography.fernet.Fernet(key)
该类提供了加密和解密的功能。该类接受 key 作为输入参数。这个 key 参数是一个URL安全的Base64编码的32字节密钥。这必须保密。拥有此密钥的任何人都能够创建和读取消息。
现在,在我们看到 Fernet 类的一些方法之前,让我们考虑一个简单的示例来演示它的使用方法。
示例1:
# importing the Fernet class from the fernet module of the cryptography package
from cryptography.fernet import Fernet
# generating the key
theKey = Fernet.generate_key()
# variable holding the value of key
first = Fernet(theKey)
# the plain text is converted into cipher text using the encrypt() method
theToken = first.encrypt(b"Hello, Students! Welcome to Python tutorial at Javatpoint.com")
# printing the encrypted message
print("Encrypted Message: ", theToken)
# the cipher text is converted back into plain text using the decrpyt() method
decryptMsg = first.decrypt(theToken)
# printing the decrypted message
print("\nDecrypted Message: ", decryptMsg)
输出:
Encrypted Message: b'gAAAAABiZAj1lcmLXPbRJng9wxgowFB731MLUFu-nstC8Sdnzn24y_lhu_h1QmR5N68d_DdpH8mIGNF6Y-7PgSmgUYkxwouw7R80lWk1k9IPp7MiKtv5O3OWmG6gk4rK4k5iNzE5sPd-L_ns0Zn8nmG2Zr--QDUi2Q=='
Decrypted Message: b'Hello, Students! Welcome to Python tutorial at Javatpoint.com'
解释:
在上面的代码片段中,我们从cryptography包的fernet模块中导入了Fernet类。然后我们使用了名为generate_key()的类方法生成了一个密钥。然后我们使用这个密钥通过encrypt()方法将明文转换为密文并打印出加密的消息。然后我们再次使用这个密钥通过decrypt()方法将密文转换为明文并为用户打印出解密的消息。
我们可以观察到解密后的输出在原始消息前面有一个“b”,这表示字节格式。然而,我们可以通过使用decode()方法在打印原始消息时去除这个表示字节格式的“b”。让我们来看一个示例,演示了decode()方法的实现。
示例2:
# importing the Fernet class from the fernet module of the cryptography package
from cryptography.fernet import Fernet
# generating the key
theKey = Fernet.generate_key()
# variable holding the value of key
first = Fernet(theKey)
# the plain text is converted into cipher text using the encrypt() method
theToken = first.encrypt(b"This example demonstrates the implementation of the decode() method.")
# printing the encrypted message
print("Encrypted Message: ", theToken)
# the cipher text is converted back into plain text using the decrpyt() method
decryptMsg = first.decrypt(theToken)
# printing the plain text using the decode() method
# this method converts the message from byte to string
print("\nDecrypted Message: ", decryptMsg.decode())
输出:
Encrypted Message: b'gAAAAABiZrxrUg61HeVbOke04ftXTKnl17z3e8LjHfLMiCPQ2ZQ4Hz43bL1twbcS4cXcsclsUZKT-q3oyWVecKH39hgEgh1GQaB4E1gkMJr1Q6LbC93N97yeFq0kME_ttc-BVrXCGZBzNPRdW1zl45v7ow-d893kkMiab-y1OSMjbVFL9nK_iZE='
Decrypted Message: This example demonstrates the implementation of the decode() method.
解释:
在以上的代码片段中,我们从cryptography包的fernet模块中导入了Fernet类。然后我们使用了类方法generate_key()生成了一个密钥。然后我们使用这个密钥通过encrypt()方法将明文转换为密文,并打印出加密后的消息。然后我们又使用同样的密钥通过decrypt()方法将密文转换为明文。最后,我们使用decode()方法将消息从byte转换为string,并打印出来给用户。
现在让我们理解一下我们之前使用的方法的工作原理。
- generate_key(): 这个方法属于Fernet类,用于生成一个全新的fernet密钥。必须保持密钥的安全,因为它是解密密文的重要组成部分。如果密钥丢失,用户将无法解密消息。此外,如果骇客或黑客获取密钥,他们可以读取数据并伪造数据。
-
encrypt(data): 这个方法允许我们加密传递给它的数据作为参数。这个加密的输出被称为”fernet令牌”,它本质上就是密文。加密的令牌还包括生成时的当前时间戳的明文。如果数据不是字节类型,encrypt方法会抛出异常。
参数:
1. **data (bytes) -** 此参数包含我们想要加密的消息。 **返回值:** 一个安全的消息或密文,没有密钥无法阅读或更改。这被认为是一个“Fernet令牌”。它经过URL安全的base64编码。 **引发异常:** 类型错误 - 如果数据不是字节时引发此异常。
- encrypt_at_time(data, current_time): 此方法用于使用显式传递的当前时间对传递给它的数据进行加密。这个方法的工作原理类似于我们之前看到的encrypt()方法。 这个方法的思想是为客户端代码能够测试令牌过期。由于我们可以以不安全的方式使用此方法,我们必须确保传递的时间是 current_time 外部测试是正确的,即: int(time.time()) 。
参数:
1. **current_time (int)-** 此参数表示当前时间。
注意: 与 encrypt() 类似,加密消息由明文时间戳组成;在此情况下,时间戳是 current_time 参数的值。
-
decrypt(token, ttl = None): 此方法用于解密传递给它的Fernet令牌。如果成功解密令牌,将获取原始明文。否则将引发异常。在返回数据之前,Fernet会验证数据是否被篡改,因此可以立即使用此数据。
参数:
- token(字节)- 这个参数是Fernet令牌。这是调用encrypt()方法的结果。
- ttl(int)- 这是一个可选参数,表示消息的有效秒数。如果消息的年龄超过ttl秒(从创建时计算),则会引发异常。如果没有提供ttl参数(或为None),则不考虑消息的年龄。
返回值: 原始明文。抛出异常: 此方法会引发以下异常:
- ttl(int)- 这是一个可选参数,表示消息的有效秒数。如果消息的年龄超过ttl秒(从创建时计算),则会引发异常。如果没有提供ttl参数(或为None),则不考虑消息的年龄。
- token(字节)- 这个参数是Fernet令牌。这是调用encrypt()方法的结果。
- cryptography.fernet.InvalidToken- 无效令牌。
如果 token 是无效的,就会引发此异常。 token 可能无效的原因有几个:它比 ttl 旧,格式不正确或不包含有效的签名。
5. TypeError- 如果 token 不是 bytes ,则会引发此异常。
- decrypt_at_time(token,ttl,current_time): 此方法用于在明确传递的当前时间的帮助下解密 token 。此方法的工作原理类似于我们之前看到的 decrypt() 方法。此方法背后的想法是让客户端代码能够测试令牌过期。由于我们可以以不安全的方式使用此方法,因此必须确保传递给它的时间为 current_time 。参数在测试之外是正确的,即 int(time.time()) 。
参数:
- current_time(int)- 此参数表示当前时间。
- extract_timestamp(token): 此方法用于给我们传递的 token 生成时间戳。调用者可以根据时间戳判断Token是否即将过期,并且例如发布新的Token。
参数:
- token(bytes)- 此参数是Fernet Token。这是调用 encrypt() 方法的结果。
返回值: Token的UNIX时间戳。
抛出异常: 该方法会抛出以下异常:
- cryptography.fernet.InvalidToken – 如果 token 的签名无效,则抛出此异常。
- TypeError – 如果 token 不是 bytes 类型,则抛出此异常。