Converting java code for 3DES Encryption with md5 message digest and DESede/CBC/PKCS5Padding to python

痴心易碎 提交于 2020-12-12 09:42:26

问题


I have this working java code which encrypts the passphrase with 3DES encryption-

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;
    }

}

I wanted to have the same encryption in Python, so the encryption generated from both the codes are same, this is my python code

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

I am getting an error -> ValueError: Invalid DES key size. Key must be exactly 8 bytes long.


回答1:


There are a lot of differences between both codes:

  • In the Java code the key is generated by concatenating the 16 bytes MD5 hash with the first 8 bytes of the same hash. In the Python code, key generation does not seem to work at all (changing from {: <24} to [:24] does not really make it better). The 2nd change finally, digested_passkey[:24], is identical to digested_passkey and works because PyCryptodome automatically extends the key to 24 bytes according to 2-key Triple DES.
  • In the Python code, two libraries are used: pyDes and PyCryptodome. Only one library should be applied here. Regarding PyCryptodome AES is used. Actually AES is the faster/modern algorithm compared to Triple DES, but it just differs from that of the Java code.
  • The Python code also implements padding, which is not necessary, because PyCryptodome (in contrast to the legacy PyCrypto) supports padding. Apart from that the padding is wrongly implemented because it uses a block size of 16 bytes, but Triple DES has a block size of 8 bytes.
  • In the Java code a 0 vector is taken for the IV, in the Python code a random IV (which is actually correct, but just differs from the Java code).
  • In the Java code IV and ciphertext are not concatenated, in the Python code they are concatenated (which is actually correct, but just differs from the Java code).

Apart from that, the algorithms used are insecure (MD5) or outdated/slow (Triple DES), as already mentioned in the comment. Also a 0-vector as IV is completely insecure.

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

which gives the result form the Java code (7B0aNUwOU1ECqKqnIZs6mQ==).



来源:https://stackoverflow.com/questions/64113853/converting-java-code-for-3des-encryption-with-md5-message-digest-and-desede-cbc

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