1

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);
Vaibhav Dhoke
  • 459
  • 6
  • 14
  • 2
    Your terminal is set up incorrectly. This is one of the reasons it's common to use Base64 for encrypted text. – chrylis -cautiouslyoptimistic- Mar 27 '18 at 16:53
  • So you told that i must use base64, but in java or C++ ? Characters in C++ print correctly but in java some characters didn't trasnfered from C++. – Mehrdad HosseinNejad Yami Mar 27 '18 at 16:59
  • 1
    What guarantees do you have that an arbitrary array of bytes can be represented as a `String` in Java? What encoding does `String` use? – Yakk - Adam Nevraumont Mar 27 '18 at 17:08
  • But i want to print array of bytes or show it to the client, So i need to **convert it to String** ? Do you prefer any other way ? I think String's encode is UTF-8 or UTF-16, and exactly because of this encode, this fault is happening. – Mehrdad HosseinNejad Yami Mar 27 '18 at 17:16
  • 1
    There are two common ways to represent binary bytes, Base64 (good for computers) and hexadecimal (good for developers), – zaph Mar 27 '18 at 18:45
  • 3
    If you aren't getting a warning at `buf[i] =((inputBlock[i] +10) ^ key[i] ^ key[i+15] ^ 0x11)` because inputBlock elements are 16 bits and buf elements are 8 bits, you need to amp up your warning level or get a new compiler. – Tom Blodget Mar 27 '18 at 19:11
  • 1
    @TomBlodget: you're right, this 'encryption' works only while the input string happens to be ascii. – Alex Cohn Mar 27 '18 at 19:40

1 Answers1

2

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.

zaph
  • 111,848
  • 21
  • 189
  • 228