【Python | JAVA】PBEWithMD5AndDES加密、解密算法—JAVA分析及Python实现

前言

各项目、平台的功能往往涉及到数据库存储、读取等操作,连接数据库时需要用户名、密码等敏感信息。出于信息保护的角度,需要对这些敏感信息进行加密。

在JAVA中,通常使用加密算法PBEWithMD5AndDES,使用方式简单:实例化对象、设置固定口令,即可生成加密密文。

目前不少功能、算法开发均基于python编程,在python、JAVA联合开发的项目中,需要保证加密解密方式一致。然而,python并未直接提供调用包,因此本文对PBEWithMD5AndDES算法原理进行分析,在python中实现同样操作,保证两种编程环境下的结果统一。


一、JAVA中使用PBEWithMD5AndDES算法

在JAVA中调用PBEWithMD5AndDES算法的方式如下:

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.EnvironmentPBEConfig;

// 加密
public void get_Encrypt() {
    // 实例化
    StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
    
    // 配置加密算法和固定口令
    EnvironmentPBEConfig config = new EnvironmentPBEConfig();
    config.setAlgorithm("PBEWithMD5AndDES"); // 设置成PBEWithMD5AndDES算法       
    config.setPassword("forTest"); // 用于加密的口令,解密时也需要
    encryptor.setConfig(config);
    String myPwd = "123456test"; // 需要加密的明文密码
    String encryptedPwd = encryptor.encrypt(myPwd); // 加密
    System.out.println("加密结果为:" + encryptedPwd);
}

// 解密
public static void testPwdDecrypt() {
    // 实例化
    StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();

    // 配置加密算法和固定口令
    EnvironmentPBEConfig config = new EnvironmentPBEConfig();
    config.setAlgorithm("PBEWithMD5AndDES"); // 设置成PBEWithMD5AndDES算法
    config.setPassword("forTest"); // 用于加密的口令,同加密
    String encryptedPwd = "EVjR4mo1JvBbhzIMVEuPMlgVJn43PB1R"; // 需要解密的加密密码
    String myPwd = encryptor.decrypt(encryptedPwd);  // 解密
    System.out.println("解密结果为:" + myPwd);
}

调用上述功能的执行结果为:

加密结果为:EVjR4mo1JvBbhzIMVEuPMlgVJn43PB1R
解密结果为:123456test

二、PBEWithMD5AndDES算法分析

1. 加密过程

数据流程

PBEWithMD5AndDES算法的加密过程整体流程如下:使用PBKDF1算法得到密钥和初始化向量、通过DES加密算法对明文密码进行加密、得到的加密信息联合盐一起进行Base64编码,最终输出密文。
在这里插入图片描述

各算法介绍

(1) PBKDF1算法
输入:口令、系统随机生成的8字节盐、迭代次数(默认为1000次)
输出:16位输出(前8位为密钥,后8位为初始化向量IV)
过程:口令与盐的组合作为输入,使用MD5(哈希)对输入进行加密,按照指定迭代次数进行多次迭代,每一次迭代的输入为上一次MD5的结果。最终输出32位字符串,取中间的第9位到第24位的部分,得到16位长度的结果。

(2) DES加密算法
输入:密钥、初始化向量IV、明文
输出:加密信息
过程:将待加密数据以64bit为单位拆分成若干数据块,然后再进行外层、内层两重迭代。外层迭代为数据块之间的迭代,使用密码分组链接模式(Cipher Block Chaining,CBC)对各数据块进行加密;内层迭代在各数据块的内部,通过Feistel网络实现。

  • CBC模式加密:初始化向量与第一个明文数据块进行异或运算,结果与第二个明文数据块再进行异或,依次往后,得到密文。
    在这里插入图片描述
  • Feistel网络加密:将输入划分为左、右两侧数据,“子密钥”指的是本轮加密所使用的密钥。在Feistel网络中,每一轮都需要使用一个不同的子密钥。轮函数(典型的包括置换、代换、置换与代换的组合)的作用是根据“右侧”和子密钥生成对“左侧”加密的比特序列。每一轮加密左、右需调换一次数据。
    在这里插入图片描述

(3) Base64编码
输入:随机生成的8字节盐+加密信息
输出:密文
过程:将原始数据按 3 字节分组(如果数据长度不是 3 的倍数,则用 0 字节填充,在最后用 = 号填补);24位的数据拆分成 4 组,每组 6 位;每 6 位的二进制值被解释为一个整数(0~63),用这个整数查找 Base64 的字符表,对应输出一个字符。Base64字符表如下:
Base64字符表

2. 解密过程

数据流程

PBEWithMD5AndDES算法的解密过程就是将加密流程倒着走一遍:对密文进行Base64解码,从解码结果得到加密信息和盐;再利用盐、口令、迭代次数根据PBKDF1算法得到密钥和初始化向量;最后使用DES解密算法得到明文。
在这里插入图片描述

各算法介绍

(1) Base64解码
输入:密文
输出:解码结果,前8位为盐,剩余字节为加密的信息
过程:

  1. 识别出 Base64 编码的字符串中的有效字符(即大写字母 A-Z、小写字母 a-z、数字 0-9、“+”和“/”);
  2. 将每个有效字符转换为对应的6位二进制值(例如,“A”对应 000000,“B”对应 000001等);
  3. 将6位二进制值按顺序拼接起来,每8位一组,转换为对应的 ASCII 码值,从而得到原始的二进制数据;
  4. 如果编码字符串末尾有“=”填充字符,则在解码时忽略这些填充字符,并根据填充字符的数量确定需要丢弃的二进制位(如果末尾有一个“=”,则丢弃最后 4 个二进制位;如果末尾有两个“=”,则丢弃最后 8 个二进制位)

(2) PBKDF1算法
流程同加密

(3) DES解密算法
输入:密钥、初始化向量IV、密文
输出:明文
过程:将密文数据以64bit为单位拆分成若干数据块,然后再进行外层、内层两重迭代。外层迭代为数据块之间的迭代,使用密码分组链接模式(Cipher Block Chaining,CBC)对各数据块进行解密;内层迭代在各数据块的内部,通过Feistel网络实现。

  • CBC解密:初始化向量与第一个密文数据块进行异或运算,结果与第二个密文数据块再进行异或,依次往后,得到明文。
    在这里插入图片描述

  • Feistel网络加密:将输入划分为左、右两侧数据,“子密钥”指的是本轮加密所使用的密钥。在Feistel网络中,每一轮都需要使用一个不同的子密钥。轮函数(典型的包括置换、代换、置换与代换的组合)的作用是根据“右侧”和子密钥生成对“左侧”加密的比特序列。每一轮加密左、右需调换一次数据。
    在这里插入图片描述

三、Python中PBEWithMD5AndDES算法实现

1. Python加密代码

import base64
from Crypto.Cipher import DES
from Crypto.Hash import MD5
from Crypto.Protocol.KDF import PBKDF1
from Crypto.Util.Padding import pad
import os


def encrypt_pbe_with_md5_and_des(password, plaintext):
    # 生成随机的8字节盐
    salt = os.urandom(8)

    # 使用PBKDF1生成密钥和IV
    key_iv = PBKDF1(password.encode('utf-8'), salt, 16, 1000, MD5)
    key = key_iv[:8]
    iv = key_iv[8:16]

    # 使用DES加密
    cipher = DES.new(key, DES.MODE_CBC, iv=iv)
    padded_data = pad(plaintext.encode('utf-8'), 8)  # PKCS7填充
    encrypted_data = cipher.encrypt(padded_data)

    # 组合盐和加密数据,并进行Base64编码
    combined = salt + encrypted_data
    encrypted_b64 = base64.b64encode(combined).decode('utf-8')

    return encrypted_b64


if __name__ == "__main__":
    # 配置口令和明文
    setPassword = "forTest" # 口令
    myPwd = "123456test"

    # 加密
    encrypted_pwd = encrypt_pbe_with_md5_and_des(setPassword, myPwd)
    print("++++++++++++++++++++++++++++++")
    print(f"+ 原密码为:{myPwd}")
    print(f"+ 加密后的密码为:{encrypted_pwd}")
    print("++++++++++++++++++++++++++++++")

注意:由于每次执行加密时,会随机生成一个8字节盐,因此每次加密的结果都是不一样的。

2. Python解密代码

import base64
from Crypto.Cipher import DES
from Crypto.Hash import MD5
from Crypto.Protocol.KDF import PBKDF1


def dencrypt_pbe_with_md5_and_des(password, encrypted_b64):
    encrypted_data = base64.b64decode(encrypted_b64)
    salt = encrypted_data[:8]
    ciphertext = encrypted_data[8:]

    # 生成密钥和IV
    key_iv = PBKDF1(password.encode('utf-8'), salt, 16, 1000, MD5)
    key = key_iv[:8]
    iv = key_iv[8:16]

    # 解密
    cipher = DES.new(key, DES.MODE_CBC, iv=iv)
    decrypted = cipher.decrypt(ciphertext)

    # 去除PKCS7填充
    pad_length = decrypted[-1]
    decrypted = decrypted[:-pad_length]

    return decrypted.decode('utf-8')


if __name__ == "__main__":
    setPassword = "forTest"
    pending_pwd = "EVjR4mo1JvBbhzIMVEuPMlgVJn43PB1R"

    my_pwd = dencrypt_pbe_with_md5_and_des(setPassword, pending_pwd)
    print("++++++++++++++++++++++++++++++")
    print(f"+ 加密密码为:{pending_pwd}")
    print(f"+ 解密后的密码为:{my_pwd}")
    print("++++++++++++++++++++++++++++++")

使用JAVA的加密结果进行检验,得到结果为123456test,与加密前的明文一致:
在这里插入图片描述

总结

本文对JAVA中的PBEWithMD5AndDES加密、解密算法原理进行了分析,在Python中实现了同样的算法逻辑,支持JAVA、Python作为编程语言的项目开发。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值