python PBEWithMD5AndDES 实现

python PBEWithMD5AndDES 实现 , 在网上不好找,使用大模型生成的代码基本上都是错的, 浪费时间验证, 如下是实测有效的, 跟java程序的PBEWithMD5AndDES 实现进行比较, 输出的值是一样的, 设置了VIP可见, 如果你不是VIP, 可以参考源代码自行修改 pbe-with-md5-and-triple-des-python

因为源码有些陈旧会有些问题会报错, 下面我发布的是验证可用的, 使用中遇到啥问题, 欢迎留言.

安装依赖, 实测于版本 python 3.11

pip install pycryptodome

使用方法, 这里面,我将原函数做了修改, 输出是16进制数值, 方便存储

from pbe_with_md5_and_triple_des import PBEWithMD5AndDES, PBEWithMD5AndTripleDES


if __name__ == '__main__':
    password = '123456'
    plain_text = 'admin'
    salt = 'RCGTeGiH'.encode("utf-8")
    cipher = PBEWithMD5AndDES()
    encrypted_text = cipher.encrypt(plain_text, password, salt)
    print(encrypted_text)

    print(cipher.decrypt(encrypted_text, password, salt))

代码如下

    """

    pbe_with_md5_and_triple_des
    ~~~~~~~~~~~~
    This module provides ciphers that implement 'PBE With MD5 And Triple DES' and 'PBE With MD5 And DES' algorithms

    :copyright: (c) 2017 by Anton Koba (anton.koba@gmail.com)
    :license: MIT

"""

from abc import ABC, abstractmethod
import base64
import hashlib
import array
from Crypto.Cipher import DES, DES3


BLOCK_LENGTH_BYTES = 8  # pad incoming message to whole length of block

DERIVED_KEY_ITERATIONS = 1000  # cycles to hash over to produce dk and iv


class AbstractPBEWithMD5AndDES(ABC):
    """ Defines basic algorithm for PBE With MD5 And DES / Triple DES (DESede)
    DES and Triple DES versions differ in the way how the derived key (dk) and
    initialization vector (iv) are generated
    """

    # use DES3 (triple DES a.k.a. DESede) or plain DES
    triple_des = True

    def __init__(self, iterations=1000):
        super().__init__()
        self.iterations = iterations

    def encrypt(self, plain_text, password, salt):
        """
        Encrypts plain text with given password

        :param plain_text: plain text to decrypt
        :param password: password to decrypt with
        :return: base64-encoded encrypted text
        """

        # pad message up to a whole block size
        padded_text = self._pad_plain_text(plain_text)

        # get dk and iv using proper algorithm (either for DES ot DES3), password as bytes
        (dk, iv) = self._get_derived_key_and_iv(password.encode('utf-8'), salt)

        # get proper class (DES/DES3) to instantiate and use for encoding
        des_class = self._get_des_encoder_class()
        des = des_class.new(dk, DES.MODE_CBC, iv)

        # do the encryption
        encrypted_text = des.encrypt(padded_text.encode('utf-8'))

        print(padded_text)
        print(encrypted_text.hex())

        # return encrypted text prepended with salt, all base64-encoded
        return base64.b64encode(salt + encrypted_text)

    def decrypt(self, encoded_text, password):
        """
        Decrypts encoded_text with given password

        :param encoded_text: encoded string
        :param password: password to decrypt with
        :return: decrypted plain text as string (bytes)
        """

        decoded_encrypted_text = base64.b64decode(encoded_text)

        # get first 8 bytes as salt
        salt = decoded_encrypted_text[:8]

        # get rest of data (starting from 8th byte as message
        encrypted_text_message = decoded_encrypted_text[8:]

        # get dk and iv using proper algorithm (either for DES ot DES3)
        (dk, iv) = self._get_derived_key_and_iv(password.encode('utf-8'), salt)

        # get proper class (DES/DES3) to instantiate and use for decoding
        des_class = self._get_des_encoder_class()
        des = des_class.new(dk, DES.MODE_CBC, iv)

        # do the decryption
        decrypted_text = des.decrypt(encrypted_text_message)

        # return decrypted text with possible padding removed, converted from bytes string to string
        return str(self._unpad_decrypted_message(decrypted_text), 'utf-8')

    def _pad_plain_text(self, plain_text):
        """
        Pads plain text up to the whole length of block (8 bytes).
        We are adding chars which are equal to the number of padded bytes.
        i.e. 'hello' -> 'hello/x03/x03/x03'
        :param plain_text: plain text to be padded (bytes)
        :return: padded bytes
        """
        pad_number = BLOCK_LENGTH_BYTES - (len(plain_text) % BLOCK_LENGTH_BYTES)
        result = plain_text
        for i in range(pad_number):
            result += chr(pad_number)
        return result

    def _unpad_decrypted_message(self, decrypted_message):
        """ Decrypted message could be padded on the end, last character means number of
        :param decrypted_message: with PKCS7 padding
        :return: unpadded text
        """

        message_length = len(decrypted_message)
        pad_value = decrypted_message[-1]

        if pad_value > 8:
            # no padding used
            return decrypted_message

        else:
            # where real data ends
            position = message_length - pad_value

            # padding element, repeated `pad_value` number of times, as byte string
            padding_elements = array.array('B', [pad_value] * pad_value).tostring()

            # check if correctly padded
            if pad_value == 0 or decrypted_message[-pad_value:] != padding_elements:
                raise ValueError('Incorrect padding')

            return decrypted_message[:position]

    def _get_des_encoder_class(self):
        return DES3 if self.triple_des else DES

    @abstractmethod
    def _get_derived_key_and_iv(self, password, salt, cycles=DERIVED_KEY_ITERATIONS):
        return None


class PBEWithMD5AndDES(AbstractPBEWithMD5AndDES):

    triple_des = False

    def _get_derived_key_and_iv(self, password, salt, cycles=DERIVED_KEY_ITERATIONS):
        """
        Returns tuple of dk(8 bytes) and iv(8 bytes) for DES

        Logic: concatenate password + salt and hash them given number of iterations
        (result of hash function is given to it an an input on following iteration)

        :param password: password used for encryption/decryption
        :param salt: salt
        :param cycles: number of hashing iterations
        :return: (8 bytes dk, 8 bytes iv)
        """
        key = password + salt
        for i in range(cycles):
            m = hashlib.md5(key)
            key = m.digest()
        return key[:8], key[8:]


class PBEWithMD5AndTripleDES(AbstractPBEWithMD5AndDES):

    def _get_derived_key_and_iv(self, password, salt, cycles=DERIVED_KEY_ITERATIONS):
        """
        Returns tuple of dk(24 bytes) and iv(8 bytes) for DES3 (Triple DES, DESede)

        Logic:
        Salt will be split in two halves and processed separately.
        1. If 2 halves of salt are same, reverse first part
        2. For each half of salt:
            - Start hashing loop with half of salt + password (not password + salt as in DES keys)
            concatenate output of hash with password on each iteration
            - iterate for each half of salt given number of times
        3. Join two parts of hashes (16 + 16 bytes)
        4. First 24 bytes will be used as key for DES3, latest 8 bytes - iv for DES3

        :param password: password used for encryption/decryption
        :param salt: salt
        :param cycles: number of hashing iterations (see description)
        :return: (24 bytes dk, 8 bytes iv)
        """

        # reverse first half of salt if two halves are the same
        if salt[:4] == salt[4:]:
            salt = salt[-5::-1] + salt[4:]

        # do part 1
        part1_to_hash = salt[:4]
        for i in range(cycles):
            m = hashlib.md5(part1_to_hash + password)
            part1_to_hash = m.digest()

        # do part 2
        part2_to_hash = salt[4:]
        for i in range(cycles):
            m = hashlib.md5(part2_to_hash + password)
            part2_to_hash = m.digest()

        result = part1_to_hash + part2_to_hash

        # key, iv
        return result[:24], result[24:]

if __name__ == '__main__':
    password = '123456'
    plain_text = 'admin'
    salt = 'RCGTeGiH'.encode("utf-8")
    cipher = PBEWithMD5AndDES()
    encrypted_text = cipher.encrypt(plain_text, password, salt)
    print(encrypted_text)

    dd = cipher.decrypt(encrypted_text,password)

<think>嗯,用户的问题是关于如何通过SQL查询解析加密后的密码'腱赆赆腙钹镬镱镬镫'并还原出原始密码'root.2020'。首先,我需要理解用户的具体需求。他们可能有一个加密后的字符串,想要通过SQL查询来解密,得到原始密码。但加密和解密通常不是在数据库层直接处理的,而是应用程序的责任。不过用户可能遇到了特殊情况,比如需要逆向工程已有的加密数据,或者验证加密是否正确。 接下来,我需要查看用户提供的引用内容。引用[1]提到了使用Jasypt加密配置文件中的密码,并且加密时需要配置相同的密码。引用[2]讨论了SQL注入和万能密码的原理,其中提到构造查询来绕过验证。引用[3]涉及数据库权限问题和密码错误导致的异常。这些引用可能提示用户遇到的问题可能与加密配置、SQL查询构造或权限有关。 首先,加密后的字符串'腱赆赆腙钹镬镱镬镫'看起来像是经过某种字符编码转换的结果,比如Base64或其他编码方式。不过直接查看的话,这些字符可能属于生僻的汉字,可能不是标准的编码结果。或者,可能是加密后的二进制数据被转换成了某种字符表示,比如十六进制或Base64,但被错误地解码为汉字。例如,如果加密后的字节被错误地用GBK或GB2312编码解析,可能会显示为这样的汉字。 用户提到原始密码是'root.2020',需要找到加密方式。根据引用[1],可能使用了Jasypt进行加密,而Jasypt默认使用PBEWithMD5AndDES算法。因此,用户可能在配置文件中使用了Jasypt,并且加密后的字符串是经过Base64编码的。但加密后的字符串看起来不像Base64,Base64通常包含字母、数字、+/=等符号,而这里的字符串是汉字,可能说明加密后的字节被转换为另一种编码方式,比如将字节数组转换为GBK编码的字符串。 例如,假设加密后的字节数组用GBK编码转换成字符串,导致显示为这些汉字。因此,解密步骤可能需要先将这些汉字转换回字节数组,然后用Jasypt解密。但用户想在SQL中直接处理,这可能需要数据库支持解密函数,或者用户需要编写自定义函数,但通常数据库不直接支持这种解密方式。 另一个可能性是,用户遇到的加密方式不是Jasypt,而是其他方式,比如简单的替换或编码转换。例如,每个字符被替换成另一个字符,或者进行了位移(如凯撒密码)。但考虑到原始密码是'root.2020',而加密后的字符串长度更长,可能不是简单的替换。 可能的步骤是: 1. 确定加密算法和密钥:根据引用[1],加密时使用了Jasypt,密钥是配置中的password(如123456)。因此,加密后的字符串可能是用这个密钥生成的,需要知道加密算法才能解密。 2. 将加密后的汉字字符串转换为字节数组:如果加密后的字符串是Base64或其他编码,但被错误显示为GBK汉字,那么需要先正确解码。例如,将每个汉字对应的GBK字节转换为原始字节,然后进行Base64解码,再解密。 例如,'腱赆赆腙钹镬镱镬镫'对应的GBK编码字节可能组成加密后的字节数组。假设每个汉字对应两个字节,总共有10个汉字,即20个字节。然后使用Jasypt的PBEWithMD5AndDES解密,使用密钥123456,可能会得到原始密码。 但用户想在SQL中执行此操作,这可能比较困难,因为SQL通常不具备直接处理这种加密解密的能力,除非使用数据库的扩展功能或自定义函数。例如,在MySQL中,用户可能需要编写UDF(用户定义函数)来调用Java解密代码,但这是复杂的。 另外,引用[2]提到SQL注入中的万能密码,可能用户的问题与解密无关,而是想通过注入绕过密码验证。例如,构造一个密码字段使得加密后的值匹配某个条件,但这种情况可能需要了解加密算法才能构造有效载荷。 综合来看,用户可能的情况是:应用程序使用Jasypt加密了密码,存储到数据库中的是加密后的字符串,现在需要从数据库中查询并解密得到原始密码。但用户希望直接通过SQL查询实现解密,这通常不可行,因为解密需要密钥和算法,而数据库不存储密钥。正确的做法是在应用程序中解密,例如使用Jasypt的解密功能。 但用户坚持要通过SQL查询实现,可能需要以下步骤: 1. 确认加密算法和密钥:根据引用[1],密钥是123456,算法是PBEWithMD5AndDES。 2. 将加密后的汉字字符串转换为Base64或原始字节:例如,将每个汉字按GBK编码转换为字节,然后组合成字节数组,这个字节数组实际上是加密后的数据。 3. 在SQL中调用解密函数:但大多数数据库不支持这种自定义解密,除非用户自定义函数。例如,在MySQL中,可以编写一个UDF调用Jasypt的解密方法,但这需要编程和数据库权限。 另一种可能是,加密后的字符串实际上是经过编码的,比如HEX编码,但显示为汉字。例如,将加密后的字节以HEX形式存储,但被错误地转换为汉字。例如,加密后的HEX字符串被当作GBK编码解析,导致显示为汉字。这时需要将汉字重新转换为HEX,然后解密。 例如,'腱'的GBK编码是0xE8 0x82,转换为HEX是E882,这可能对应于加密后的字节。需要将每个汉字转换为对应的GBK字节,组合起来,然后用Jasypt解密。 假设用户使用的加密流程是:原始密码 -> Jasypt加密(使用PBEWithMD5AndDES和密码123456) -> 字节数组 -> 转换为GBK字符串显示,导致出现'腱赆赆腙钹镬镱镬镫'。因此,解密需要逆向这个过程:将每个汉字转换为GBK字节,得到加密后的字节数组,然后用Jasypt解密,密钥是123456。 因此,具体步骤可能为: 1. 将每个汉字转换为GBK编码的字节。 例如,使用Python: s = '腱赆赆腙钹镬镱镬镫' bytes = s.encode('gbk') 此时,bytes是加密后的字节数组。 2. 使用Jasypt解密,密钥是123456,得到原始密码'root.2020'。 但用户希望在SQL中执行,这可能无法直接实现,除非数据库支持调用外部解密函数。 因此,回答需要说明加密可能使用的流程,并建议在应用层解密,同时如果必须用SQL,可能需要自定义函数,但需注意安全风险。 另外,引用[3]提到数据库权限问题,可能用户遇到的错误是由于密码错误,但这里的问题是关于解密,所以可能关联不大。 总结,用户的加密过程可能是Jasypt + 编码转换,解密需要逆向过程,但SQL本身不支持,建议在应用层处理。如果必须在SQL中处理,可能需要复杂的步骤,如将汉字转换回字节,调用解密函数,但可行性低。</think>要解析加密密码'腱赆赆腙钹镬镱镬镫'并生成还原原始密码'root.2020'的SQL语句,需分步骤处理: --- ### 步骤1:确认加密方式 根据引用[1],配置文件中使用**Jasypt加密工具**,默认采用`PBEWithMD5AndDES`算法。加密后的字符串通常为Base64格式,但此处出现汉字,表明可能经过**编码转换**。例如:加密后的字节数组被错误地用GBK编码解析为汉字[^1]。 --- ### 步骤2:验证编码转换关系 通过Python验证汉字与字节的对应关系: ```python encrypted_str = '腱赆赆腙钹镬镱镬镫' bytes_data = encrypted_str.encode('gbk') # 输出加密后的原始字节 ``` --- ### 步骤3:解密流程设计 1. **将汉字还原为加密字节** 通过GBK编码将每个汉字转换为2字节数据,例如'腱'对应`0xE882`。 2. **使用Jasypt解密** 需在应用层调用解密方法,SQL无法直接实现: ```java // Java示例代码 BasicTextEncryptor encryptor = new BasicTextEncryptor(); encryptor.setPassword("123456"); // 引用[1]中的配置密码 String plaintext = encryptor.decrypt(bytes_data.toString()); ``` --- ### 步骤4:生成SQL查询(需扩展支持) 若数据库支持**自定义解密函数**(如MySQL UDF),可尝试: ```sql -- 假设存在自定义函数jasypt_decrypt SELECT jasypt_decrypt('腱赆赆腙钹镬镱镬镫', '123456') AS password; ``` 但实际中需预先实现该函数[^1]。 --- ### 关键注意事项 1. **安全风险** 直接在SQL中处理密码违反安全规范,建议仅在应用层解密[^2]。 2. **编码一致性** 必须保证加密/解密时的字符编码(如GBK)完全一致。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值