Replicate Java's PBEWithMD5AndDES in Python 2.7

好久不见. 提交于 2019-12-03 09:08:45
Tebbe

Thanks to GregS's comment, I was able to sort this conversion out!

For future reference, this Python code mimics the behavior of the Java code above:

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

This Python code outputs the following in Python 2.7:

Icy6sAP7adLgRoXNYe9N8A==

Thanks again to GregS for pointing me in the right direction!

For Python 3.6, I tested with following code and it works with a little change from above:

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))

Output:

Icy6sAP7adLgRoXNYe9N8A==

MyP455w0rd

kai

I found one from 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()

If you're using the newer Cryptodome library with Python 3, you'll need to also encode your plaintext_to_encrypt to 'latin-1', as is shown below.

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))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!