在 Python 2.7 中复制 Java 的 PBEWithMD5AndDES

Teb*_*bbe 5 java encryption md5 des python-2.7

如果这不是很明显,我首先要说的是我不是加密货币人士。

我的任务是在 Python 2.7 中复制 Java 的 PBEWithMD5AndDES(具有 DES 加密的 MD5 摘要)的行为。

我确实可以访问 Python 的加密工具包 PyCrypto。

下面是我试图复制其行为的 Java 代码:

import java.security.spec.KeySpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.Cipher;
import javax.xml.bind.DatatypeConverter;

public class EncryptInJava
{
    public static void main(String[] args)
    {
      String encryptionPassword = "q1w2e3r4t5y6";
      byte[] salt = { -128, 64, -32, 16, -8, 4, -2, 1 };
      int iterations = 50;

      try
      {
        KeySpec keySpec = new PBEKeySpec(encryptionPassword.toCharArray(), salt, iterations);
        SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
        AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterations);

        Cipher encoder = Cipher.getInstance(key.getAlgorithm());
        encoder.init(Cipher.ENCRYPT_MODE, key, paramSpec);

        String str_to_encrypt = "MyP455w0rd";
        byte[] enc = encoder.doFinal(str_to_encrypt.getBytes("UTF8"));

        System.out.println("encrypted = " + DatatypeConverter.printBase64Binary(enc));
      }
      catch (Exception e)
      {
        e.printStackTrace();
      }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于给定值,它输出以下内容:

encrypted = Icy6sAP7adLgRoXNYe9N8A==
Run Code Online (Sandbox Code Playgroud)

这是我将上面的内容移植到 Python 的笨手笨脚的尝试encrypt_in_python.py

from Crypto.Hash import MD5
from Crypto.Cipher import DES

_password = 'q1w2e3r4t5y6'
_salt = '\x80\x40\xe0\x10\xf8\x04\xfe\x01'
_iterations = 50
plaintext_to_encrypt = 'MyP455w0rd'

if "__main__" == __name__:

    """Mimic Java's PBEWithMD5AndDES algorithm to produce a DES key"""
    hasher = MD5.new()
    hasher.update(_password)
    hasher.update(_salt)
    result = hasher.digest()

    for i in range(1, _iterations):
        hasher = MD5.new()
        hasher.update(result)
        result = hasher.digest()

    key = result[:8]

    encoder = DES.new(key)
    encrypted = encoder.encrypt(plaintext_to_encrypt + ' ' * (8 - (len(plaintext_to_encrypt) % 8)))
    print encrypted.encode('base64')
Run Code Online (Sandbox Code Playgroud)

它输出一个完全不同的字符串。

是否可以使用标准 Python 库将 Java 实现移植到 Python 实现?

显然,Python 实现要求我加密的明文是八个字符的倍数,而且我什至不确定如何填充我的明文输入以满足该条件。

感谢您的帮助。

Teb*_*bbe 2

感谢 GregS 的评论,我能够解决这个转换问题!

为了便于将来参考,此 Python 代码模仿了上面 Java 代码的行为:

from Crypto.Hash import MD5
from Crypto.Cipher import DES

_password = 'q1w2e3r4t5y6'
_salt = '\x80\x40\xe0\x10\xf8\x04\xfe\x01'
_iterations = 50
plaintext_to_encrypt = 'MyP455w0rd'

# Pad plaintext per RFC 2898 Section 6.1
padding = 8 - len(plaintext_to_encrypt) % 8
plaintext_to_encrypt += chr(padding) * padding

if "__main__" == __name__:

    """Mimic Java's PBEWithMD5AndDES algorithm to produce a DES key"""
    hasher = MD5.new()
    hasher.update(_password)
    hasher.update(_salt)
    result = hasher.digest()

    for i in range(1, _iterations):
        hasher = MD5.new()
        hasher.update(result)
        result = hasher.digest()

    encoder = DES.new(result[:8], DES.MODE_CBC, result[8:16])
    encrypted = encoder.encrypt(plaintext_to_encrypt)

    print encrypted.encode('base64')
Run Code Online (Sandbox Code Playgroud)

此 Python 代码在 Python 2.7 中输出以下内容:

Icy6sAP7adLgRoXNYe9N8A==
Run Code Online (Sandbox Code Playgroud)

再次感谢 GregS 为我指明了正确的方向!