使用 Python3 从 Java jasypt 库解密文本
Decryption of text from Java jasypt library with Python3
在数据库中,我有使用默认配置的 Java Jasypt 库在后端加密的用户电子邮件。据我了解,它使用 PBEWITHMD5andDES 和 1000 次迭代来生成密钥。
@Bean
StringEncryptor encryptor() {
StandardPBEStringEncryptor spbe = new StandardPBEStringEncryptor();
spbe.setPassword(symmetricKey);
return spbe;
}
然后加密器使用如下:
@Before("insertAccount(account)")
public void beforeInsertAccount(Account account) {
account.setFirstName(encryptor.encrypt(StringUtils.defaultString(account.getFirstName())));
account.setPhone(encryptor.encrypt(StringUtils.defaultString(account.getPhone())));
account.setEmail(encryptor.encrypt(StringUtils.defaultString(account.getEmail())));
}
在 AWS Glue(ETL 工具)中,我需要解密用户的电子邮件,或者至少匹配来自两个不同表的加密电子邮件。我可以通过创建 Python3 脚本来定义自定义转换。
我基于此写了一个脚本:https://gist.github.com/jpralves/505e653fd1c7358ad2c540e25e1ee80a
它正在使用 pycryptodome 库。
data_to_decrypt 变量使用密码 'test'.
使用 jasypt 加密 'foo@bar.com' 初始化
def MyTransform (glueContext, dfc) -> DynamicFrameCollection:
from Crypto.Hash import MD5
from Crypto.Cipher import DES
import base64
import sys
from pyspark.sql.functions import lit
newdf = dfc.select(list(dfc.keys())[0]).toDF()
data_to_decrypt = base64.b64decode("epncHsHYRZd8uIWncULit//8f0mhk8pn")
password = "test"
bs = 8
_iterations = 1000
salt = data_to_decrypt[:bs]
data = data_to_decrypt[bs:]
hasher = MD5.new()
result = hasher.digest()
hasher.update(bytearray(password.encode()))
hasher.update(bytearray(salt))
for i in range(1, _iterations):
hasher = MD5.new()
hasher.update(result)
result = hasher.digest()
encoder = DES.new(result[:bs], DES.MODE_CBC, result[bs:bs*2])
decrypted = encoder.decrypt(bytes(data))
length = len(decrypted)
unpadding = int(decrypted[length-1])
decryptedEmail = ''
if length - unpadding > 0:
decryptedEmail = decrypted[:(length - unpadding)].decode("latin")
else:
decryptedEmail = decrypted.decode("latin")
newdf = newdf.withColumn('decryptedEmail', lit(decryptedEmail))
dyf_filtered = DynamicFrame.fromDF(newdf, glueContext, "aaa")
return(DynamicFrameCollection({"CustomTransform0": dyf_filtered}, glueContext))
脚本正在输出一些废话,例如“’€ ‡>— ¦õ8Þûð›7e”。当我尝试以任何其他编码解码来自编码器的输出字符串时,它失败了。
你的实际问题是你的第一个哈希是错误的;你需要 .digest
在 完成两个 .update
之后。 (您的迭代哈希是正确的。)此外,您的去填充很差:PKCS5 填充不应超过一个块,对于 DES 来说是 8 个字节。更好的方法是检查 所有 填充字节是否超过 1,但我没有打扰。
$ cat 71576901.py3
from Crypto.Hash import MD5
from Crypto.Cipher import DES
import base64
data_to_decrypt = base64.b64decode("epncHsHYRZd8uIWncULit//8f0mhk8pn")
password = "test"
bs = 8
_iterations = 1000
salt = data_to_decrypt[:bs]
data = data_to_decrypt[bs:]
hasher = MD5.new()
hasher.update(bytearray(password.encode()))
hasher.update(bytearray(salt))
result = hasher.digest() # moved down
for i in range(1, _iterations):
hasher = MD5.new()
hasher.update(result)
result = hasher.digest()
encoder = DES.new(result[:bs], DES.MODE_CBC, result[bs:bs*2])
decrypted = encoder.decrypt(bytes(data))
length = len(decrypted)
unpadding = int(decrypted[length-1])
if unpadding > 0 and unpadding <= bs: # better check
print (decrypted[:-unpadding].decode('latin1')) # or other decoding depending on what you encrypted
else:
print ('bad') # might better raise, but TBD
$ python3 71576901.py3
foo@bar.com
请确保您知道,这是一种非常弱的加密并且很容易被破解 -- 但这是一个安全问题,而不是编程问题,这里是题外话。
在数据库中,我有使用默认配置的 Java Jasypt 库在后端加密的用户电子邮件。据我了解,它使用 PBEWITHMD5andDES 和 1000 次迭代来生成密钥。
@Bean
StringEncryptor encryptor() {
StandardPBEStringEncryptor spbe = new StandardPBEStringEncryptor();
spbe.setPassword(symmetricKey);
return spbe;
}
然后加密器使用如下:
@Before("insertAccount(account)")
public void beforeInsertAccount(Account account) {
account.setFirstName(encryptor.encrypt(StringUtils.defaultString(account.getFirstName())));
account.setPhone(encryptor.encrypt(StringUtils.defaultString(account.getPhone())));
account.setEmail(encryptor.encrypt(StringUtils.defaultString(account.getEmail())));
}
在 AWS Glue(ETL 工具)中,我需要解密用户的电子邮件,或者至少匹配来自两个不同表的加密电子邮件。我可以通过创建 Python3 脚本来定义自定义转换。
我基于此写了一个脚本:https://gist.github.com/jpralves/505e653fd1c7358ad2c540e25e1ee80a 它正在使用 pycryptodome 库。 data_to_decrypt 变量使用密码 'test'.
使用 jasypt 加密 'foo@bar.com' 初始化def MyTransform (glueContext, dfc) -> DynamicFrameCollection:
from Crypto.Hash import MD5
from Crypto.Cipher import DES
import base64
import sys
from pyspark.sql.functions import lit
newdf = dfc.select(list(dfc.keys())[0]).toDF()
data_to_decrypt = base64.b64decode("epncHsHYRZd8uIWncULit//8f0mhk8pn")
password = "test"
bs = 8
_iterations = 1000
salt = data_to_decrypt[:bs]
data = data_to_decrypt[bs:]
hasher = MD5.new()
result = hasher.digest()
hasher.update(bytearray(password.encode()))
hasher.update(bytearray(salt))
for i in range(1, _iterations):
hasher = MD5.new()
hasher.update(result)
result = hasher.digest()
encoder = DES.new(result[:bs], DES.MODE_CBC, result[bs:bs*2])
decrypted = encoder.decrypt(bytes(data))
length = len(decrypted)
unpadding = int(decrypted[length-1])
decryptedEmail = ''
if length - unpadding > 0:
decryptedEmail = decrypted[:(length - unpadding)].decode("latin")
else:
decryptedEmail = decrypted.decode("latin")
newdf = newdf.withColumn('decryptedEmail', lit(decryptedEmail))
dyf_filtered = DynamicFrame.fromDF(newdf, glueContext, "aaa")
return(DynamicFrameCollection({"CustomTransform0": dyf_filtered}, glueContext))
脚本正在输出一些废话,例如“’€ ‡>— ¦õ8Þûð›7e”。当我尝试以任何其他编码解码来自编码器的输出字符串时,它失败了。
你的实际问题是你的第一个哈希是错误的;你需要 .digest
在 完成两个 .update
之后。 (您的迭代哈希是正确的。)此外,您的去填充很差:PKCS5 填充不应超过一个块,对于 DES 来说是 8 个字节。更好的方法是检查 所有 填充字节是否超过 1,但我没有打扰。
$ cat 71576901.py3
from Crypto.Hash import MD5
from Crypto.Cipher import DES
import base64
data_to_decrypt = base64.b64decode("epncHsHYRZd8uIWncULit//8f0mhk8pn")
password = "test"
bs = 8
_iterations = 1000
salt = data_to_decrypt[:bs]
data = data_to_decrypt[bs:]
hasher = MD5.new()
hasher.update(bytearray(password.encode()))
hasher.update(bytearray(salt))
result = hasher.digest() # moved down
for i in range(1, _iterations):
hasher = MD5.new()
hasher.update(result)
result = hasher.digest()
encoder = DES.new(result[:bs], DES.MODE_CBC, result[bs:bs*2])
decrypted = encoder.decrypt(bytes(data))
length = len(decrypted)
unpadding = int(decrypted[length-1])
if unpadding > 0 and unpadding <= bs: # better check
print (decrypted[:-unpadding].decode('latin1')) # or other decoding depending on what you encrypted
else:
print ('bad') # might better raise, but TBD
$ python3 71576901.py3
foo@bar.com
请确保您知道,这是一种非常弱的加密并且很容易被破解 -- 但这是一个安全问题,而不是编程问题,这里是题外话。