Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java and c++ encrypted results not matching

Tags:

I have a existing c++ code which will encrypt a string. Now I did the same encryption in . Some of the encrypted strings are matching . Some are mismatching in one or two characters.

I am unable to figure out why it is happening. I ran both the codes in debug mode until they call their libraries both have the same key, salt, iv string to be encrypted.

I know that even if a single byte padding change will modify encrypted string drastically. But here I am just seeing a one or two characters change. Here is a sample (Bold characters in between stars is the part mis matching)

java:

U2FsdGVkX18xMjM0NTY3OGEL9nxFlHrWvodMqar82NT53krNkqat0rrgeV5FAJFs1vBsZIJPZ08DJVrQ*Pw*yV15HEoyECBeAZ6MTeN+ZYHRitKanY5jiRU2J0KP0Fzola

C++:

U2FsdGVkX18xMjM0NTY3OGEL9nxFlHrWvodMqar82NT53krNkqat0rrgeV5FAJFs1vBsZIJPZ08DJVrQ*jQ*yV15HEoyECBeAZ6MTeN+ZYHRitKanY5jiRU2J0KP0Fzola

I am using AES encryption. provider is SunJCE version 1.6. I tried changing provider to Bouncy Castle. Even then result is same.

Added One More sample:

C++:

U2FsdGVkX18xMjM0NTY3O*I*/BMu11HkHgnkx+dLPDU1lbfRwb+aCRrwkk7e9dy++MK+/94dKLPXaZDDlWlA3gdUNyh/Fxv*oF*STgl3QgpS0XU=

java:

U2FsdGVkX18xMjM0NTY3O*D*/BMu11HkHgnkx+dLPDU1lbfRwb+aCRrwkk7e9dy++MK+/94dKLPXaZDDlWlA3gdUNyh/Fxv*j9*STgl3QgpS0XU=

UPDATE:

As per the comments I feel base 64 encryption is the culprit. I am using Latin-1 char set in both places. Anything else that I can check

like image 381
javaMan Avatar asked Jun 20 '12 14:06

javaMan


2 Answers

Sigh!!

The problem almost certainly is that after you encrypt the data and receive the encrypted data as a byte string, you are doing some sort of character conversion on the data before sending it through Base-64 conversion.

Note that if you encrypt the strings "ABC_D_EFG" and "ABC_G_EFG", the encrypted output will be completely different starting with the 4th character, and continuing to the end. In other words, the Base-64 outputs would be something like (using made-up values):

U2FsdGVkX18xMj

and

U2FsdGXt91mJpz

The fact that, in the above examples, only two isolated Base-64 characters (one byte) are messed up in each case pretty much proves that the corruption occurs AFTER encryption.

The output of an encryption process is a byte sequence, not a character sequence. The corruption observed is consistent with erroneously interpreting the bytes as characters and attempting to perform a code page conversion on them, prior to feeding them into the Base-64 converter. The output from the encryptor should be fed directly into the Base-64 converter without any conversions.

You say you are using the "Latin-1 char set in both places", a clear sign that you are doing some conversion you should not be doing -- there should be no need to muck with char sets.

like image 181
Hot Licks Avatar answered Oct 17 '22 02:10

Hot Licks


First a bit of code:

import javax.xml.bind.DatatypeConverter;

...

public static void main(String[] args) {
    String s1j = "U2FsdGVkX18xMjM0NTY3OGEL9nxFlHrWvodMqar82NT53krNkqat0rrgeV5FAJFs1vBsZIJPZ08DJVrQPwyV15HEoyECBeAZ6MTeN+ZYHRitKanY5jiRU2J0KP0Fzola";
    String s1c = "U2FsdGVkX18xMjM0NTY3OGEL9nxFlHrWvodMqar82NT53krNkqat0rrgeV5FAJFs1vBsZIJPZ08DJVrQjQyV15HEoyECBeAZ6MTeN+ZYHRitKanY5jiRU2J0KP0Fzola";
    byte[] bytesj = DatatypeConverter.parseBase64Binary(s1j);
    byte[] bytesc = DatatypeConverter.parseBase64Binary(s1c);
    int nmax = Math.max(bytesj.length, bytesc.length);
    int nmin = Math.min(bytesj.length, bytesc.length);
    for (int i = 0; i < nmax; ++i) {
        if (i >= nmin) {
            boolean isj = i < bytesj.length;
            byte b = isj? bytesj[i] : bytesc[i];
            System.out.printf("%s [%d] %x%n", (isj? "J" : "C++"), i, (int)b & 0xFF);
        } else {
            byte bj = bytesj[i];
            byte bc = bytesc[i];
            if (bj != bc) {
                System.out.printf("[%d] J %x != C++ %x%n", i, (int)bj & 0xFF, (int)bc & 0xFF);
            }
        }
    }
}

This delivers

[60] J 3f != C++ 8d

Now 0x3f is the code of the question mark.

The error is, that 0x80 - 0xBF are in Latin-1, officially ISO-8859-1, control characters. Windows Latin-1, officially Windows-1252, uses these codes for other characters.

Hence you should use "Windows-1252" or "Cp1252" (Code-Page) in Java.


Blundly

In the encryption the original bytes in the range 0x80 .. 0xBF were replaced with a question mark because of some translation to ISO-8859-1 instead of Windows-1252 to byte[].

like image 38
Joop Eggen Avatar answered Oct 17 '22 00:10

Joop Eggen