1

I was trying to convert a java code to python. tried to use pycryptodome library for the purpose. This is java code:

try {
    String data= "shouldEncryptDATA";
    String bas64ed= "";
    int len12 = Integer.parseInt("12");
    byte[] randomparam= new byte[len12];
    new SecureRandom().nextBytes(randomparam);
    SecretKeySpec secretKeySpec= new SecretKeySpec("1f1f7892GKG38815".getBytes(), "AES");
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(1, secretKeySpec, new GCMParameterSpec(Integer.parseInt("16") * 8, randomparam)); 
    byte[] bytedata= cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
    byte[] newbytearray= new byte[bytedata.length + len12];
    System.arraycopy(randomparam, 0, newbytearray, 0, len12); 
    System.arraycopy(bytedata, 0, newbytearray, len12, bytedata.length);
    bas64ed= Base64.getEncoder().encodeToString(newbytearray);
    System.out.println("bas64ed: "+bas64ed);
            
    System.out.println(URLEncoder.encode(bas64ed, "UTF-8"));
          
} catch (Exception unused_ex) {
    System.out.println();
    System.out.println("ERROR: " + unused_ex);
}

so far I tried below python code to mimic above java code:

import base64
from Crypto.Cipher import AES
import urllib.parse
from Crypto.Random import get_random_bytes

data= "shouldEncryptDATA"

key = b '1f1f7892GKG38815' 

len12 = 12
v1 = bytearray(len12)
                                         
cipher = AES.new(key, AES.MODE_GCM, nonce=get_random_bytes(12) ) 
ciphertext, tag = cipher.encrypt_and_digest(data.encode("utf8"))
base64ed = ""
for x in cipher.nonce, ciphertext, tag:
        base64ed += base64.b64encode(x).decode('utf-8')
urlencoded = urllib.parse.quote_plus(base64ed+"\n")

print(urlencoded )

the above python code generates an output but the problem is that when I supply the output to the decryption code I got MAC check Failed. so I realized my implementation in the python code is somewhat is the problem because the output of the Java code when passed to the decryption code, it works and decrypts the data. so How can I correctly convert the Java encryption code to Python? using the Pycryptodome or any other suitable library.

Topaco
  • 40,594
  • 4
  • 35
  • 62
hanan
  • 532
  • 2
  • 7
  • 23

1 Answers1

1

The bug in the Python code is in the concatenation, it must be:

base64ed = base64.b64encode(cipher.nonce + ciphertext + tag).decode('utf-8')

After this fix, if you compare the ciphertexts of both codes with identical input data (especially with identical IV), they are the same.

Topaco
  • 40,594
  • 4
  • 35
  • 62
  • 1
    @hanan - Both codes provide different ciphertexts for each encryption. This is due to the random IV and is necessary for security reasons. So if you want to compare the ciphertexts of Java and Python code, you have to use identical IVs (for testing only, of course)! Another possibility for verification is the decryption. – Topaco Sep 06 '21 at 16:06
  • while the code you shared is correct but when I supply the output of `java` code to the `server` it worked fine but the output of the `python` code it returns `Invalid Input Data`. I mean is it the problem the `IV` ? the java side it is generated using `new GCMParameterSpec(Integer.parseInt("16") * 8, randomparam)`? right? but in python I don't know how can I do this? the `get_randombytes(12)` was just guessing and trying. – hanan Sep 06 '21 at 16:12
  • 1
    Both lines generate random (and thus of course different) 12 bytes IVs, which is quite correct! The IV is concatenated with the ciphertext so that it is available during decryption. Also, on my machine, the Java and Python code produce _identical_ ciphertexts when the same plaintext, the same key, and especially the _same IV_ are applied. If it is different for you, you should post an example: plaintext, key, IV and ciphertext of both codes. – Topaco Sep 06 '21 at 16:28