在Python 2.7中复制Java的PBEWithMD5AndDES

问题描述 投票:4回答:4

如果它不是立即显而易见的,那么首先我要说的是我不是一个加密人。

我的任务是在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();
      }
    }
}

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

encrypted = Icy6sAP7adLgRoXNYe9N8A==

这是我的火腿尝试将上面的内容移植到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')

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

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

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

谢谢你的帮助。

java python-2.7 encryption md5 des
4个回答
1
投票

感谢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')

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

Icy6sAP7adLgRoXNYe9N8A==

再次感谢GregS指出我正确的方向!


1
投票

对于Python 3.6,我使用以下代码进行了测试,它可以从上面稍作改动:

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

_password = b'q1w2e3r4t5y6'
_salt = b'\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 (str(base64.b64encode(encrypted),'utf-8'))

    decoder = DES.new(result[:8], DES.MODE_CBC, result[8:])
    d = str(decoder.decrypt(encrypted),'utf-8')
    print (re.sub(r'[\x01-\x08]','',d))

输出:

Icy6sAP7adLgRoXNYe9N8A ==

MyP455w0rd


0
投票

我从here找到了一个

import base64
import hashlib
import re
import os
from Crypto.Cipher import DES
def get_derived_key(password, salt, count):
    key = password + salt
    for i in range(count):
        m = hashlib.md5(key)
        key = m.digest()
    return (key[:8], key[8:])
def decrypt(msg, password):
    msg_bytes = base64.b64decode(msg)
    salt = '\xA9\x9B\xC8\x32\x56\x35\xE3\x03'
    enc_text = msg_bytes
    (dk, iv) = get_derived_key(password, salt, 2)
    crypter = DES.new(dk, DES.MODE_CBC, iv)
    text = crypter.decrypt(enc_text)
    return re.sub(r'[\x01-\x08]','',text)
def encrypt(msg, password):
    salt = '\xA9\x9B\xC8\x32\x56\x35\xE3\x03'
    pad_num = 8 - (len(msg) % 8)
    for i in range(pad_num):
        msg += chr(pad_num)
    (dk, iv) = get_derived_key(password, salt, 2)
    crypter = DES.new(dk, DES.MODE_CBC, iv)
    enc_text = crypter.encrypt(msg)
    return base64.b64encode(enc_text)
def main():
    msg = "hello"
    passwd = "xxxxxxxxxxxxxx"
    encrypted_msg = encrypt(msg, passwd)
    print encrypted_msg
    plain_msg = decrypt(encrypted_msg, passwd)
    print plain_msg
if __name__ == "__main__":
    main()

0
投票

如果您在Python 3中使用较新的Cryptodome库,则还需要将plaintext_to_encrypt编码为'latin-1',如下所示。

from Cryptodome.Hash import MD5
from Cryptodome.Cipher import DES
import base64
import re

_password = b'q1w2e3r4t5y6'
_salt = b'\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.encode('latin-1'))  #encoded plaintext

    print (str(base64.b64encode(encrypted),'utf-8'))

    decoder = DES.new(result[:8], DES.MODE_CBC, result[8:])
    d = str(decoder.decrypt(encrypted),'utf-8')
    print (re.sub(r'[\x01-\x08]','',d))
© www.soinside.com 2019 - 2024. All rights reserved.