Search code examples
pythonjavapython-cryptographyjavax.crypto

Decrypt a Java encrypted file in Python


I use the following to encrypt a file in Java:


   public static byte[] hexStringToByteArray(String s) {

      int len = s.length();
      byte[] data = new byte[len / 2];
      for (int i = 0; i < len; i += 2)
      {   
         data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
      }
      return data;

   } 

   public static void encExtract ( String zipName, String encKey )
   {

      try{
         byte[] KeyByte = hexStringToByteArray( encKey );
         SecretKey secKey =  new SecretKeySpec(KeyByte, 0, KeyByte.length, "AES");

         Cipher desCipher;
         desCipher = Cipher.getInstance("AES");

         File zipFile = new File(zipName);
         byte[] indata = java.nio.file.Files.readAllBytes(zipFile.toPath());
         System.out.println("             Encyption size " + indata.length );

         desCipher.init(Cipher.ENCRYPT_MODE, secKey);
         byte[] textEncrypted = desCipher.doFinal(indata);

         try (FileOutputStream outputStream = new FileOutputStream(zipName+".enc")) {
               outputStream.write(textEncrypted);
               System.out.println("             Encypted size " + textEncrypted.length );
         }

      }catch(Exception e)
      {
         e.printStackTrace(System.out);
      }
   }

The system that the encrypted file will get sent to will use Python to decrypt it. I am trying to test this and have built the following Python script:

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


encFH = open('the_enc_file.zip.enc', 'rb')
encData = bytearray(encFH.read())

encKey = "__hello123__world123__again123__"

iv = encData[:AES.block_size]
cipher = AES.new(encKey, AES.MODE_CBC, iv)
decdata = cipher.decrypt(encData[AES.block_size:])

f = open("the_dec_file.zip", "wb")
f.write(decdata)
f.close()

When I run the above Python I get the error:

Traceback (most recent call last):
  File "thescript.py", line 13, in <module>
    cipher = AES.new(encKey, AES.MODE_CBC, iv)
  File "/home/xxx/.local/lib/python3.10/site-packages/Crypto/Cipher/AES.py", line 228, in new
    return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs)
  File "/home/xxx/.local/lib/python3.10/site-packages/Crypto/Cipher/__init__.py", line 79, in _create_cipher
    return modes[mode](factory, **kwargs)
  File "/home/xxx/.local/lib/python3.10/site-packages/Crypto/Cipher/_mode_cbc.py", line 274, in _create_cbc_cipher
    cipher_state = factory._create_base_cipher(kwargs)
  File "/home/xxx/.local/lib/python3.10/site-packages/Crypto/Cipher/AES.py", line 100, in _create_base_cipher
    result = start_operation(c_uint8_ptr(key),
  File "/home/xxx/.local/lib/python3.10/site-packages/Crypto/Util/_raw_api.py", line 248, in c_uint8_ptr
    raise TypeError("Object type %s cannot be passed to C code" % type(data))
TypeError: Object type <class 'str'> cannot be passed to C code

I think perhaps there is a mismatch with AES.MODE_CBC in Python and Cipher.ENCRYPT_MODE in Java, but I'm not sure.


Solution

  • The AES encryption algorithm expects the key to be in bytes, but you're passing a string as the key. Try this:

    encKey = "hello123__world123__again123".encode('utf-8')

    with open('the_enc_file.zip.enc', 'rb') as encFH:
        encData = encFH.read()
    
    iv = encData[:AES.block_size]
    
    cipher = AES.new(encKey, AES.MODE_CBC, iv)
    
    decdata = cipher.decrypt(encData[AES.block_size:])
    
    with open("the_dec_file.zip", "wb") as f:
        f.write(decdata)