Why do I get an ValueError: Invalid padding bytes when I decrypt a string with an incorrect key using Python cryptography library?
Why do I get an ValueError: Invalid padding bytes when I decrypt a string with an incorrect key using Python cryptography library?
当我按照图书馆网站上的 this 简单指南使用正确的密码解密我的字符串时,我得到了正确的字符串响应。当我将最后的 w 更改为 e 以获取无效密钥时,我会收到类似这样的填充字节错误,源于:
lib/python3.8/site-packages/cryptography/hazmat/primitives/padding.py",
line 101, in _byte_unpadding_check
接下来是我预料中的 cryptography.fernet.InvalidToken 错误。
ValueError: Invalid padding bytes.
During handling of the above exception, another exception occurred:
cryptography.fernet.InvalidToken
我读过 Whosebug,只能找到一个这样的例子,但它似乎并不适用,因为这只是他们网站上的实际例子。
我错过了什么?
from cryptography.fernet import Fernet
# print(Fernet.generate_key()) # used this to get the below
bytes_key = b'tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOew='
# changed just one digit of key to test incorrect key
# bytes_key = b'tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOee='
f = Fernet(bytes_key)
# encrypt a message
# token = f.encrypt(b"A really secret message. Not for prying eyes.")
# print(token)
# b'gAAAAABiIOCx9Pp8HB9Asq0HUXb-t0SwX-W5ue7O3GJfuF9Rm4ue8I0Drk36NIyuZ0Mufknad5xkoL3091ZGOOS-QTqMbM-MeNrEC9jvmYx_Y0ojoSTaZWO9AXMJFZgdnvgPTB-wQIQd'
print(f.decrypt(b'gAAAAABiIOCx9Pp8HB9Asq0HUXb-t0SwX-W5ue7O3GJfuF9Rm4ue8I0Drk36NIyuZ0Mufknad5xkoL3091ZGOOS-QTqMbM-MeNrEC9jvmYx_Y0ojoSTaZWO9AXMJFZgdnvgPTB-wQIQd'))
print(f.decrypt(b'gAAAAABiIOCx9Pp8HB9Asq0HUXb-t0SwX-W5ue7O3GJfuF9Rm4ue8I0Drk36NIyuZ0Mufknad5xkoL3091ZGOOS-QTqMbM-MeNrEC9jvmYx_Y0ojoSTaZWO9AXMJFZgdnvgPTB-wQIQd').decode('utf-8'))
关于Fernet密钥的结构、Fernet令牌和涉及的算法的详细信息可以找到here。
Fernet 密钥由 16 字节签名密钥和 16 字节加密密钥的串联组成,Base64url 编码。
对于已发布的有效 Fernet 密钥是:
Fernet key (Base64url): tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOew=
Signing key (hex): b6cb86ee8aa1c320ac7d4a1fdf96ed0c
Encryption key (hex): 903678cec07467f8b40334a35cd739ec
对于发布的无效键:
Fernet key (Base64url): tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOee=
Signing key (hex): b6cb86ee8aa1c320ac7d4a1fdf96ed0c
Encryption key (hex): 903678cec07467f8b40334a35cd739e7
请注意,两个加密密钥的最后一个字节不同(0xec
与 0xe7
),即您的更改已修改加密密钥!
错误的密钥导致解密生成错误的填充错误的明文。 错误的不是填充长度,而是填充字节本身的值。
详情:示例中使用的明文:
A really secret message. Not for prying eyes.
由45个字节组成,即填充由3个字节组成,即字节序列0x030303
,因为应用了PKCS#7填充。对于PKCS7# padding,所有的padding bytes都有相同的值,这个值对应padding bytes的个数,详见PKCS#7。如果使用错误的密钥解密密文,最后三个字节为 0x07e3f2
,这不对应于有效的 PKCS#7 填充并生成 ValueError:无效填充字节错误消息.
注意:如果padding正确,会自动去掉
同样,无效的签名密钥会生成相应的错误消息InvalidSignature: Signature did not match digest.
填充0x07e3f2
可以确定如下:
令牌的结构是:version (1 byte) || timestamp (8 bytes) || IV (16 bytes) || ciphertext || HMAC (32 bytes
)。因此,从token可以推导出下面的IV和密文:
IV: f4fa7c1c1f40b2ad075176feb744b05f
ciphertext: e5b9b9eecedc625fb85f519b8b9ef08d03ae4dfa348cae67432e7e49da779c64a0bdf4f7564638e4be413a8c6ccf8c78
这允许使用适当的工具(例如 here)使用 AES/CBC 不使用 填充进行解密,并生成以下字节序列以使用 错误键:
6afb18a9791e407ce0eafd1d2c2ae1cef403e94903cf80e90193fafd0681e58f0e8fff0d3f3542901bced6fc8e07e3f2
0x07e3f2
作为无效填充字节。
相反,如果提供正确的密钥进行解密,结果是:
41207265616c6c7920736563726574206d6573736167652e204e6f7420666f7220707279696e6720657965732e030303
使用正确的填充 0x030303
。
当我按照图书馆网站上的 this 简单指南使用正确的密码解密我的字符串时,我得到了正确的字符串响应。当我将最后的 w 更改为 e 以获取无效密钥时,我会收到类似这样的填充字节错误,源于:
lib/python3.8/site-packages/cryptography/hazmat/primitives/padding.py", line 101, in _byte_unpadding_check
接下来是我预料中的 cryptography.fernet.InvalidToken 错误。
ValueError: Invalid padding bytes.
During handling of the above exception, another exception occurred:
cryptography.fernet.InvalidToken
我读过 Whosebug,只能找到一个这样的例子,但它似乎并不适用,因为这只是他们网站上的实际例子。
我错过了什么?
from cryptography.fernet import Fernet
# print(Fernet.generate_key()) # used this to get the below
bytes_key = b'tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOew='
# changed just one digit of key to test incorrect key
# bytes_key = b'tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOee='
f = Fernet(bytes_key)
# encrypt a message
# token = f.encrypt(b"A really secret message. Not for prying eyes.")
# print(token)
# b'gAAAAABiIOCx9Pp8HB9Asq0HUXb-t0SwX-W5ue7O3GJfuF9Rm4ue8I0Drk36NIyuZ0Mufknad5xkoL3091ZGOOS-QTqMbM-MeNrEC9jvmYx_Y0ojoSTaZWO9AXMJFZgdnvgPTB-wQIQd'
print(f.decrypt(b'gAAAAABiIOCx9Pp8HB9Asq0HUXb-t0SwX-W5ue7O3GJfuF9Rm4ue8I0Drk36NIyuZ0Mufknad5xkoL3091ZGOOS-QTqMbM-MeNrEC9jvmYx_Y0ojoSTaZWO9AXMJFZgdnvgPTB-wQIQd'))
print(f.decrypt(b'gAAAAABiIOCx9Pp8HB9Asq0HUXb-t0SwX-W5ue7O3GJfuF9Rm4ue8I0Drk36NIyuZ0Mufknad5xkoL3091ZGOOS-QTqMbM-MeNrEC9jvmYx_Y0ojoSTaZWO9AXMJFZgdnvgPTB-wQIQd').decode('utf-8'))
关于Fernet密钥的结构、Fernet令牌和涉及的算法的详细信息可以找到here。
Fernet 密钥由 16 字节签名密钥和 16 字节加密密钥的串联组成,Base64url 编码。
对于已发布的有效 Fernet 密钥是:
Fernet key (Base64url): tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOew=
Signing key (hex): b6cb86ee8aa1c320ac7d4a1fdf96ed0c
Encryption key (hex): 903678cec07467f8b40334a35cd739ec
对于发布的无效键:
Fernet key (Base64url): tsuG7oqhwyCsfUof35btDJA2eM7AdGf4tAM0o1zXOee=
Signing key (hex): b6cb86ee8aa1c320ac7d4a1fdf96ed0c
Encryption key (hex): 903678cec07467f8b40334a35cd739e7
请注意,两个加密密钥的最后一个字节不同(0xec
与 0xe7
),即您的更改已修改加密密钥!
错误的密钥导致解密生成错误的填充错误的明文。 错误的不是填充长度,而是填充字节本身的值。
详情:示例中使用的明文:
A really secret message. Not for prying eyes.
由45个字节组成,即填充由3个字节组成,即字节序列0x030303
,因为应用了PKCS#7填充。对于PKCS7# padding,所有的padding bytes都有相同的值,这个值对应padding bytes的个数,详见PKCS#7。如果使用错误的密钥解密密文,最后三个字节为 0x07e3f2
,这不对应于有效的 PKCS#7 填充并生成 ValueError:无效填充字节错误消息.
注意:如果padding正确,会自动去掉
同样,无效的签名密钥会生成相应的错误消息InvalidSignature: Signature did not match digest.
填充0x07e3f2
可以确定如下:
令牌的结构是:version (1 byte) || timestamp (8 bytes) || IV (16 bytes) || ciphertext || HMAC (32 bytes
)。因此,从token可以推导出下面的IV和密文:
IV: f4fa7c1c1f40b2ad075176feb744b05f
ciphertext: e5b9b9eecedc625fb85f519b8b9ef08d03ae4dfa348cae67432e7e49da779c64a0bdf4f7564638e4be413a8c6ccf8c78
这允许使用适当的工具(例如 here)使用 AES/CBC 不使用 填充进行解密,并生成以下字节序列以使用 错误键:
6afb18a9791e407ce0eafd1d2c2ae1cef403e94903cf80e90193fafd0681e58f0e8fff0d3f3542901bced6fc8e07e3f2
0x07e3f2
作为无效填充字节。
相反,如果提供正确的密钥进行解密,结果是:
41207265616c6c7920736563726574206d6573736167652e204e6f7420666f7220707279696e6720657965732e030303
使用正确的填充 0x030303
。