使用 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

请确保您知道,这是一种非常弱的加密并且很容易被破解 -- 但这是一个安全问题,而不是编程问题,这里是题外话。