3
votes

I am trying to encrypt and decrypt the file by using android open ssl. Below sharing the JNI wrapper for the same.

JNIEXPORT jbyteArray JNICALL
Java_com_example_MainActivity_AESencrypt( JNIEnv* env, jobject thiz, jint 
length, jbyteArray jarrByte)
{
unsigned char plaintext[AES_BLOCK_SIZE * 4];
unsigned char ciphertext[AES_BLOCK_SIZE * 4];
unsigned char checktext[AES_BLOCK_SIZE * 4];
const unsigned char userKey[AES_BLOCK_SIZE * 4] = "123456";
const int bits = 128;
AES_KEY keyin = { { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
                    0,
                    0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, }, 12 };
AES_KEY *key = &keyin;
jbyte* pJbyte = env->GetByteArrayElements(jarrByte, NULL);
if(pJbyte!=NULL){
   memcpy(plaintext, pJbyte, length);
   env->ReleaseByteArrayElements(jarrByte, pJbyte, JNI_ABORT);
}
unsigned char* beforeEncrypt = &plaintext[0];
unsigned char* afterEncrypt = &ciphertext[0];
AES_set_encrypt_key(userKey, bits, key);
AES_encrypt(beforeEncrypt, afterEncrypt, key);
jbyteArray jarrRet = env->NewByteArray(strlen((char*) ciphertext));
env->SetByteArrayRegion(jarrRet, 0, strlen((char*) ciphertext), (jbyte *) ciphertext);
return jarrRet;
}

JNIEXPORT jbyteArray JNICALL
Java_com_example_MainActivity_AESdecrypt( JNIEnv* env, jobject thiz, jint 
length, jbyteArray jarrByte)
{
 unsigned char encryptText[AES_BLOCK_SIZE * 4];
 unsigned char ciphertext[AES_BLOCK_SIZE * 4];
 unsigned char checktext[AES_BLOCK_SIZE * 4];
 const unsigned char userKey[AES_BLOCK_SIZE * 4] = "123456";
 const int bits = 128;
AES_KEY keyin = { { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
                    0,
                    0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
                    0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, }, 12 };
AES_KEY *key = &keyin;
jbyte* pJbyte = env->GetByteArrayElements(jarrByte, NULL);
if(pJbyte!=NULL){
    memcpy(encryptText, pJbyte, length);
    env->ReleaseByteArrayElements(jarrByte, pJbyte, JNI_ABORT);
}

unsigned char* beforeDecrypt = &encryptText[0];
unsigned char* afterDecrypt = &ciphertext[0];
AES_set_decrypt_key(userKey, bits, key);
AES_decrypt(beforeDecrypt, afterDecrypt, key);

jbyteArray jarrRet = env->NewByteArray(strlen((char*) ciphertext));
env->SetByteArrayRegion(jarrRet, 0, strlen((char*) ciphertext), (jbyte *) ciphertext);
return jarrRet;
}

I am calling JNI methods as below.

Mainactivity.java :
   public void jni_encryption_and_decryption {

                    // reads the file and converts into bytes 
                    plainTextBytes = getBytesFromInputFile(); 
                    len = plainTextBytes.length;

                    // encrypts the plain text and returns the encrypted bytes
                    byte[] encryptedByte = AESencrypt(len, plainTextBytes);
                    String encryptString = new String(encryptedByte);
                    encrypt.setText(encryptString);

                    len = encryptedByte.length;
                    // decrypts encrypted bytes and returns the decrypted bytes
                    decryptedByte = AESdecrypt(len, encryptedByte);
                    String decryptString = new String(decryptedByte);
                    decrypt.setText(decryptString);
      }

Encryption is working fine but while decryption, junk is coming and also If the file contains more plain text, it is not decryting complete plain text.

Input from File: This is an android openssl encryption and decryption demo

Encryption Text: �UZ�L\n�c�������a��[���ܰ�h�ܰ�ܰ0_��

Decryption Text: This is an andro�ܰ���0_�!

I also shared bytes before and after encryption. Till 15th index bytes are same. after that bytes are found not same.

What is wrong in Jni Wrapper? Am I missing anything? Please help.

enter image description here enter image description here

JNIEXPORT jbyteArray JNICALL 
Java_com_example_MainActivity_doEncryption(jbyteArray data_plaintext, int 
plaintext_len, jbyteArray data_key,
        jbyteArray data_iv, jbyteArray data_ciphertext)
{
unsigned char* key = (unsigned char*) data_key;
unsigned char* iv = (unsigned char*) data_iv;
unsigned char* plaintext =  (unsigned char*) data_plaintext;
unsigned char* ciphertext =  (unsigned char*) data_ciphertext;
EVP_CIPHER_CTX *ctx;

int len;

int ciphertext_len;

/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())){
    ERR_print_errors_fp(stderr);
    abort();
}


/* Initialise the encryption operation. IMPORTANT - ensure you use a key
 * and IV size appropriate for your cipher
 * In this example we are using 256 bit AES (i.e. a 256 bit key). The
 * IV size for *most* modes is the same as the block size. For AES this
 * is 128 bits */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)){
    ERR_print_errors_fp(stderr);
    abort();
}

/* Provide the message to be encrypted, and obtain the encrypted output.
 * EVP_EncryptUpdate can be called multiple times if necessary
 */
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)){
    ERR_print_errors_fp(stderr);
    abort();
}
ciphertext_len = len;

/* Finalise the encryption. Further ciphertext bytes may be written at
 * this stage.
 */
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)){
    ERR_print_errors_fp(stderr);
    abort();
}
ciphertext_len += len;

/* Clean up */
EVP_CIPHER_CTX_free(ctx);
jbyteArray  ciphertext_copy = (jbyteArray ) ciphertext;

return ciphertext_copy;
} 

Below sharing the error details:

Error Details : * What went wrong: Execution failed for task ':app:externalNativeBuildDebug'.

Build command failed. Error while executing process C:\android\sdk\cmake\3.6.4111459\bin\cmake.exe with arguments {--build C:\Users\SampleJni\app.externalNativeBuild\cmake\debug\armeabi-v7a --target native-lib} [1/1] Linking CXX shared library ........\build\intermediates\cmake\debug\obj\armeabi-v7a\libnative-lib.so FAILED: cmd.exe /C "cd . && C:\android\sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=armv7-none-linux-androideabi --gcc-toolchain=C:/android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64 --sysroot=C:/android/sdk/ndk-bundle/sysroot -fPIC -isystem C:/android/sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=14 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fno-integrated-as -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a --sysroot C:/android/sdk/ndk-bundle/platforms/android-14/arch-arm -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libnative-lib.so -o ........\build\intermediates\cmake\debug\obj\armeabi-v7a\libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o ../../../../openssl-armeabi-v7a/lib/libcrypto.a ../../../../openssl-armeabi-v7a/lib/libssl.a -llog -lm "C:/android/sdk/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/libgnustl_static.a" && cd ." ../../../../openssl-armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function read_string_inner: error: undefined reference to 'signal' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function read_string_inner: error: undefined reference to 'tcsetattr' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function read_string_inner: error: undefined reference to 'tcsetattr' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function open_console: error: undefined reference to 'tcgetattr' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function zlib_stateful_expand_block: error: undefined reference to 'inflate' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function zlib_stateful_compress_block: error: undefined reference to 'deflate' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function bio_zlib_free: error: undefined reference to 'inflateEnd' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function bio_zlib_free: error: undefined reference to 'deflateEnd' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function zlib_stateful_finish: error: undefined reference to 'inflateEnd' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function zlib_stateful_finish: error: undefined reference to 'deflateEnd' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function zlib_stateful_init: error: undefined reference to 'inflateInit_' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function zlib_stateful_init: error: undefined reference to 'deflateInit_' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function bio_zlib_ctrl: error: undefined reference to 'deflate' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function bio_zlib_ctrl: error: undefined reference to 'zError' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function bio_zlib_write: error: undefined reference to 'deflate' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function bio_zlib_write: error: undefined reference to 'zError' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function bio_zlib_write: error: undefined reference to 'deflateInit_' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function bio_zlib_read: error: undefined reference to 'inflate' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function bio_zlib_read: error: undefined reference to 'zError' ../../../../openssl-armeabi-v7a/lib/libcrypto.a(c_zlib.o):c_zlib.c:function bio_zlib_read: error: undefined reference to 'inflateInit_' clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation) ninja: build stopped: subcommand failed.

1

1 Answers

2
votes

AES is a block cipher, the block length is 16 bytes. The issue here is that aes_encrypt() and aes_decrypt() are lowlevel-functions, which only operate on a single block (didn't you wonder, why there was no length-parameter?). So, you only encrypted and decrypted 16 bytes of your demo string, the rest of the decryption buffer remained unintialized!

So you should either iterate for operating on more blocks, or use a higher-level interface like the EVP-functionfamily. A good primer is the OpenSSL Wiki

In both cases you should furthermore implement proper padding according to PKCS#7.