【问题标题】:Converting java code for 3DES Encryption with md5 message digest and DESede/CBC/PKCS5Padding to python使用 md5 消息摘要和 DESede/CBC/PKCS5Padding 将用于 3DES 加密的 java 代码转换为 python
【发布时间】:2021-01-14 17:24:18
【问题描述】:

我有这个使用 3DES 加密对密码进行加密的有效 java 代码-

import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Main{

    public static void main(String[] args) throws Exception {
        String text = "aug@2019";
        String codedtext = new Main().encrypt(text);
        System.out.println(codedtext);
    }

    public String encrypt(String message) throws Exception {
        final MessageDigest md = MessageDigest.getInstance("md5");
        final byte[] digestOfPassword = md.digest("Lgp!kdao2020"
                .getBytes("utf-8"));
        final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        for (int j = 0, k = 16; j < 8;) {
            keyBytes[k++] = keyBytes[j++];
        }

        final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
        final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
        final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);

        final byte[] plainTextBytes = message.getBytes("utf-8");
        final byte[] cipherText = cipher.doFinal(plainTextBytes);
        final String encodedCipherText = new String(java.util.Base64.getMimeEncoder().encode(cipherText),
                         "UTF-8");
        return encodedCipherText;
    }

}

我想在 Python 中进行相同的加密,所以从两个代码生成的加密是相同的,这是我的 python 代码

import base64
from Crypto.Cipher import AES
import pyDes
from Crypto import Random
import hashlib


def encrypt(message, passkey):
    hash_object = hashlib.md5(passkey.encode("utf-8"))
    digested_passkey = hash_object.digest()
    print(digested_passkey)
    key24 = digested_passkey[:24]
    des = pyDes.des(key24);
    message = message.encode('utf-8')
    message = message + (16 - len(message) % 16) * chr(16 - len(message) % 16)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(des, AES.MODE_CBC, iv)
    return base64.b64encode(iv + cipher.encrypt(message))

print(encrypt('aug@2019', 'Lgp!kdao2020'))

我收到一个错误 -> ValueError: Invalid DES key size。密钥的长度必须正好为 8 个字节。

【问题讨论】:

  • pyDes.des(..) 是单个 DES .. 3DES 被命名为 pyDes.triple_des(...)。但是你为什么要在 DES/3DES 中实现新的东西呢? AES 应该是首选..
  • @EbbeM.Pedersen 如何在 python 中使用 AES 实现相同的加密逻辑并实现匹配的加密短语(在 java 中检索)。我是加密方法的新手 :)
  • 同样在使用 pyDes.triple_des(key24) 更新我的代码后,我得到另一个 TypeError - can't concat str to bytes at message = message + (16 - len(message) % 16) * chr(16 - len(message) % 16)

标签: java python encryption


【解决方案1】:

两个代码有很多不同:

  • 在 Java 代码中,密钥是通过将 16 个字节的 MD5 哈希与相同哈希的前 8 个字节连接起来生成的。在 Python 代码中,密钥生成似乎根本不起作用(从 {: &lt;24} 更改为 [:24] 并没有真正让它变得更好)。最后的第二个更改 digested_passkey[:24]digested_passkey 相同,并且由于 PyCryptodome 根据 2-key Triple DES 自动将密钥扩展为 24 个字节,因此可以正常工作。
  • 在 Python 代码中,使用了两个库:pyDesPyCryptodome。此处只应应用一个库。关于 PyCryptodome 使用了 AES。实际上,与三重 DES 相比,AES 是更快/更现代的算法,但它与 Java 代码的不同。
  • Python 代码还实现了填充,这不是必需的,因为 PyCryptodome(与旧版 PyCrypto 相比)支持填充。除此之外,填充是错误实现的,因为它使用 16 字节的块大小,但三重 DES 的块大小为 8 字节。
  • 在 Java 代码中,IV 采用 0 向量,在 Python 代码中采用随机 IV(实际上是正确的,但与 Java 代码不同)。
  • 在 Java 代码中 IV 和密文没有被连接,在 Python 代码中它们被连接(这实际上是正确的,只是与 Java 代码不同)。

除此之外,正如评论中已经提到的,所使用的算法是不安全的 (MD5) 或过时/缓慢的 (Triple DES)。 0 向量作为 IV 也是完全不安全的。

import base64
#from Crypto.Cipher import AES
from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad
#import pyDes
#from Crypto import Random
import hashlib


def encrypt(message, passkey):
    
    #hash_object = hashlib.md5(passkey.encode("utf-8"))                       
    hash_object = hashlib.md5(passkey) 
    digested_passkey = hash_object.digest()
    print(digested_passkey)

    #key24 = "[:24]".format(digested_passkey) 
    key24 = digested_passkey + digested_passkey[0:8]        # Derive key as in Java
    
    #des = pyDes.des(key24);                                # Remove pyDes
    
    #message = message.encode('utf-8') 
    #message = message + (16 - len(message) % 16) * chr(16 - len(message) % 16) 
    message = pad(message, 8)                               # Use padding from PyCryptodome       
    
    #iv = Random.new().read(AES.block_size)                 # For Java code compliance: Use 0-IV
    iv = bytes.fromhex('0000000000000000')

    #cipher = AES.new(des, AES.MODE_CBC, iv)                # For Java code compliance: Use TripleDES
    cipher = DES3.new(key24, DES3.MODE_CBC, iv)
    
    #return base64.b64encode(iv + cipher.encrypt(message))  # For Java code compliance: Don't concatenate IV and ciphertext
    return base64.b64encode(cipher.encrypt(message)) 

#print(encrypt('aug@2019', 'Lgp!kdao2020'))                 # Better: Pass binary data
print(encrypt(b'aug@2019', b'Lgp!kdao2020'))

它以 Java 代码 (7B0aNUwOU1ECqKqnIZs6mQ==) 的形式给出结果。

【讨论】:

    猜你喜欢
    • 2020-10-03
    • 2020-04-30
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    • 1970-01-01
    • 2021-08-13
    • 2019-05-15
    • 1970-01-01
    相关资源
    最近更新 更多