Search code examples
javac++java-native-interfacejbytearray

How to transfer encrypt data from c++ to java


I've a simple encryption program using JNI(JAVA , C++ . Briefly : I pass a simple string into c++ program. C++ program encrypts that string for me and return cipher string. I'll print ciphertext for a client.

Problem : When I encrypt in c++ and pass it to java some characters cannot be transfered. but when I print it using c++ console it's right. one of that character is :

â , ü

cipher text in c++ console :

ozmzâx~w|(~i}|64ío(üuvt*po~,s|*nY|(yy~(ktztskk|sgX

cipher text that transfered in java:

ozmz?x~w|(~i}|64ío(?uvt*po~,s|*nY|(yy~(ktztskk|sgX

(â , ü is lost)

So because of this fault when I want to decrypt the text, those characters don't decrypt correctly (but in c++ decrypt correctly!)

plain text :

Hello, This is a test message for encryptor test, we will test it for our application

cipher text java :

Rmvpy4*Prq},su~m}xuos}iqirybozmz?x~w|(~i}|64ᄀo(?uvtpo~,s|*nY|(yy| (ktztskk|sgX

decrypt text :

Hello, This is a test message for encrケptor test, キe キill test it for our application

(fail in "encryptor" and "we" and "will") what can I do?

I transfer chars from c++ to java in jbyteArray format.

C++ CODE :

JNIEXPORT jbyteArray JNICALL Java_com_mf_dems_HelloJNI_encryptTest
(JNIEnv *env, jobject thisObject, jobject encryptorContext, jstring 
jInputBlock)
{

//get class
jclass encryptorContextClass = env->GetObjectClass(encryptorContext);

//get keyLength
jfieldID keyLengthFieldId = env->GetFieldID(encryptorContextClass, 
"keyLength", "I");
jint keyLength = env->GetIntField(encryptorContext, keyLengthFieldId);

//get blockLength
jfieldID blockLengthFieldId = env->GetFieldID(encryptorContextClass, 
"blockLength", "I");
jint blockLength = env->GetIntField(encryptorContext, blockLengthFieldId);

//get key
jfieldID keyFieldId = env->GetFieldID(encryptorContextClass, "key", "[C");
jobject jKeyArray =env->GetObjectField(encryptorContext, keyFieldId);
jchar *key =env->GetCharArrayElements((jcharArray)(jKeyArray), NULL);

//get inputBlock
const jchar *inputBlock = env->GetStringChars(jInputBlock, NULL);

jbyte *buf = new jbyte[blockLength];

unsigned int i=0;
for(i ; i< blockLength ; i++)
{
    buf[i] =((inputBlock[i] +10) ^ key[i] ^ key[i+15] ^ 0x11);
}

env->ReleaseStringChars(jInputBlock, inputBlock);
env->ReleaseCharArrayElements((jcharArray)(jKeyArray), key, 0);

jbyteArray jOut = env->NewByteArray(blockLength);
env->SetByteArrayRegion(jOut, 0, blockLength, buf);
delete [] buf;
return jOut;

}

JAVA CODE :

 EncryptorContext encryptorContext = new EncryptorContext();
    encryptorContext.setBlockLength(17);
    encryptorContext.setKeyLength(32);
    encryptorContext.setKey(new char[encryptorContext.getKeyLength()]);
    String plainText = "Hello, This is a test message for encryptor test, we will test it for our application.";
    String cipherText = "";
    //set key
    for (int i = 0; i < encryptorContext.getKeyLength(); i++) {
        encryptorContext.getKey()[i] = (char) (i + 1);
    }
    //ENCRYPT
    for (int i = 0; i < (plainText.length() -encryptorContext.getBlockLength()); i +encryptorContext.getBlockLength()) 
    {
       byte [] out = helloJNI.encryptTest(encryptorContext, 
       plainText.substring(i, i + encryptorContext.getBlockLength()));
       byte[] latin1 = new String(out, "ISO-8859-1").getBytes("UTF-8");
        for (byte b : out) {
            cipherText+=(char)b;
        }
    }
     System.out.println(cipherText);

Solution

  • The solution is to encode the encrypted output into a character based encoding. On decryption first decode back to binary. Some encryption implementations handle Base64 with an option, orbiter by default and others you will require you to do the encoding/decoding yourself.

    Encryption is byte based, not character, not all byte values can be displayed/are characters. The solution is to encode the encrypted binary data in a character encoding such as ASCII, two main methods are two common ways to represent binary bytes so they are displayable: Base64 (good for computers) and Hexadecimal (good for developers)..

    -more-
    The two character displays:
    ozmzâx~w|(~i}|64ío(üuvt*po~,s|*nY|(yy~(ktztskk|sgX
    ozmz?x~w|(~i}|64ío(?uvt*po~,s|*nY|(yy~(ktztskk|sgX
    are different because the two systems are using slightly different characters for some byte values, the lower one is using a ? for values it does not have a glyph for.

    The plain text is 86 characters and with padding is 96 characters. This will encrypt tp 96 characters. The encrypted text is displaying 50 characters so 46 bytes are missing, these are byte values with no displayable value and/or the display terminated early.