Re: Returning unsinged char* from JNI/C++ to Java

5,955 views
Skip to first unread message

Carlos Silva

unread,
May 13, 2011, 9:42:06 AM5/13/11
to andro...@googlegroups.com
OK, a couple of things I think you got wrong on your C code... And can probably crash like you said.

On Fri, May 13, 2011 at 09:38, Vinay Julme <vinay...@gmail.com> wrote:
My Function is as follows:

typedef unsigned char BYTE ;
unsigned char *test = (unsigned char *)"Hi There" ;

change it to:
unsigned char *test = (unsigned char *)"Hi There\0" ; 
 
BYTE Key[20] ;
BYTE digest[20] ;
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
{
   memset(Key, 0x0b, 20) ;

        ////////Next 2 lines are for Hashing the given text
   CHMAC_SHA1 HMAC_SHA1 ;
   HMAC_SHA1.HMAC_SHA1(test, strlen((const char *)test), Key, sizeof(Key), digest) ;

HMAC_SHA1.HMAC_SHA1(test, strlen(test), Key, sizeof(Key) * 20, digest) ;
 
        ////////
   __android_log_write(ANDROID_LOG_ERROR,"Hello-Sample",(const char *)digest);
   jstring temp = env->NewStringUTF((const char*)digest);
    return temp;
}

Test it like that.

One other thing, is that I think that you have the HMAC_SHA1 parameters mixed up (but i'm not entirely sure).
If you see here (http://goo.gl/Bv1VI), the header of the HMAC_SHA1 function is:


void hmac_sha1( unsigned char *key,
                int key_length,
                unsigned char *data,
                int data_length,
                unsigned char *digest )
which is different from what you have. So, if it keeps erroring out, just invert the arguments.

Carlos Silva

unread,
May 16, 2011, 7:56:33 AM5/16/11
to andro...@googlegroups.com
On Mon, May 16, 2011 at 10:45, alan <al...@birtles.org.uk> wrote:
unsigned char *test = (unsigned char *)"Hi There\0" ;
is not necessary, string literals are automatically null terminated

I thought so, but I wasn't sure... 

Vinay Julme

unread,
May 13, 2011, 5:38:03 AM5/13/11
to andro...@googlegroups.com
In my code i pass a string and then hash it using HMAC SHA1 algo and then try to return it to Java. But it is not returning. It crashes or stop as VM aborts.

The code that aborts is as follows:

return env->NewStringUTF((const char*)digest);
On this statement VM Aborts.

where digest is and unsigned char which has a hashed characters. I logged digest variable and it showed some ascii values. Probably after hashing it mush have got few characters like that.


My Function is as follows:

typedef unsigned char BYTE ;
unsigned char *test = (unsigned char *)"Hi There" ;
BYTE Key[20] ;
BYTE digest[20] ;
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
{
   memset(Key, 0x0b, 20) ;

        ////////Next 2 lines are for Hashing the given text
   CHMAC_SHA1 HMAC_SHA1 ;
   HMAC_SHA1.HMAC_SHA1(test, strlen((const char *)test), Key, sizeof(Key), digest) ;
        ////////
   __android_log_write(ANDROID_LOG_ERROR,"Hello-Sample",(const char *)digest);
   jstring temp = env->NewStringUTF((const char*)digest);
    return temp;
}


While executing    env->NewStringUTF((const char*)digest);  VM aborts


Can someone please tell me how can i rectify it.


Regards

Vinay Julme
**************

alan

unread,
May 13, 2011, 11:04:33 AM5/13/11
to andro...@googlegroups.com
is your string valid utf-8? as it is a hash i suspect it is not which is why the vm is crashing. you need to pass your result back as a byte array instead

Zoran Angelov

unread,
May 13, 2011, 2:44:44 PM5/13/11
to andro...@googlegroups.com
I think your digest is not null character terminated.

--
You received this message because you are subscribed to the Google Groups "android-ndk" group.
To post to this group, send email to andro...@googlegroups.com.
To unsubscribe from this group, send email to android-ndk...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/android-ndk?hl=en.

Nasif Noorudeen

unread,
May 14, 2011, 2:46:58 AM5/14/11
to andro...@googlegroups.com
use nsigned char *

--

Tim Mensch

unread,
May 16, 2011, 12:27:15 AM5/16/11
to andro...@googlegroups.com
On 5/13/2011 12:44 PM, Zoran Angelov wrote:
> I think your digest is not null character terminated.

I think it's worse. The hash is BINARY; a quick Google finds this (somewhat familiar) sample code:


BYTE Key[20] ;
BYTE digest[20] ;

unsigned char *test = "Hi There" ;
memset(Key, 0x0b, 20) ;
CHMAC_SHA1 HMAC_SHA1 ;
HMAC_SHA1.HMAC_SHA1(test, strlen(test), Key, sizeof(Key), digest) ;
 
// Check with digest equal to 0xb617318655057264e28bc0b6fb378c8ef146be00
// or not

The comment at the end is part of it. Looks similar, and the comment (20 bytes of hex) implies that digest[20] is an array of 20 bytes of data, and not a string at all. NewStringUTF() would choke on digest no matter how you slice it.

Tim

Vinay Julme

unread,
May 16, 2011, 2:38:11 AM5/16/11
to andro...@googlegroups.com
Thank you guys for your help.

I was able to send string as follows:

std::string str(reinterpret_cast<const char*>(digest),wcslen((const wchar_t*)digest));
jstring temp = env->NewString( (const jchar*) str.c_str(), strlen( (const char*) digest) );

I then though of returning the byte code. So the following code worked for me:

jsize digestLen = wcslen((const wchar_t*)digest);
jbyteArray res = env->NewByteArray(digestLen);
env->SetByteArrayRegion( res, 0 , digestLen , ( jbyte* ) digest);

Now for few more questions:

@Tim Mensch

I was able to send the byte code but i guess you showed that the return string is
0xb617318655057264e28bc0b6fb378c8ef146be00

So should I convert first from hexadecimal to byte array and then return? Cause right now i was just copying unsigned char* to bytearray

@Carlos Silva
May i know which HMAC_SHA1 you are using? As i checked in my files there i found
void CHMAC_SHA1::HMAC_SHA1 (
         BYTE *text,
         int text_len,
         BYTE *key,
         int key_len,
         BYTE *digest
);

So i guess i have something different compared to yours. Please send me the HMAC_SHA version you have.

Thanks and Regards

Vinay Julme
**************

alan

unread,
May 16, 2011, 6:45:32 AM5/16/11
to andro...@googlegroups.com
unsigned char *test = (unsigned char *)"Hi There\0" ;

Tim Mensch

unread,
May 16, 2011, 12:56:36 PM5/16/11
to andro...@googlegroups.com
On 5/16/2011 12:38 AM, Vinay Julme wrote:
@Tim Mensch

I was able to send the byte code but i guess you showed that the return string is
0xb617318655057264e28bc0b6fb378c8ef146be00

So should I convert first from hexadecimal to byte array and then return? Cause right now i was just copying unsigned char* to bytearray

There's no reason it couldn't have an embedded zero, in which case you wouldn't get the whole string. In fact, looking at this document, it's completely a coincidence that your binary "string" is null-terminated: http://tools.ietf.org/html/rfc2202 (scroll to section 3, "Test Cases for HMAC-SHA-1"). Note that only the "Hi there" string has a 00 at the end, and none of the others do.

So yes, I'd say you should return it as a byte array, not a string. It's certainly NOT valid UTF-8, no matter what, and I don't know if and when Java will choke on it as a "UTF-8 string" -- and it certainly will fail for any hash with an embedded zero.

Tim

Vinay Julme

unread,
May 18, 2011, 8:56:40 AM5/18/11
to andro...@googlegroups.com
Thank you guys for helping. I was able to solve the issues. Sorry for late reply.

I have one final problem. Can someone please give me an API for  HMAC_SHA1 algorithm written in C++.

Some how the code present in
http://www.codeproject.com/KB/recipes/HMACSHA1class.aspx

is not giving me proper hash as shown in
http://tools.ietf.org/html/rfc2202

I searched google but nothing substantial came up besides
http://www.codeproject.com/KB/recipes/csha1.aspx
and i'm not able to understand its implementation. Does some one have a simpler implementation?

Any help would be appreciated.

Regards

Vinay Julme
**************


--

Tim Mensch

unread,
May 25, 2011, 9:45:20 PM5/25/11
to andro...@googlegroups.com
I would be surprised if that class didn't work correctly; instead I'd suspect your use of the class, considering that he includes the test code on the page referenced below.

Have you tried stepping through the code and ensuring everything is doing what you expect? If you aren't hooked up to do that on Android, you could drop it into an app on your platform of choice and debug it there.

Tim

Vinay Julme

unread,
May 30, 2011, 4:13:28 AM5/30/11
to andro...@googlegroups.com
Hi Guys,

Sorry for a late reply. After getting every thing fixed i went on a five day vacation!! (Not the only reason for vacation.)

@Tim- I did step into the code and checked if it was following all HMAC and SHA1 standards. Then i found out that the culprit was how I passed the length of the key. The length of the key for an hexadecimal string would be half of the number of characters in that string. So when i convert hexadecimal to unsigned char it gave wrong conversion length with sizeof function for BYTE* . sizeof function gave correct length when i used BYTE[]. (Here BYTE is defined as unsigned char*). Not sure why this was happening.

For example
#define unsigned char BYTE;
BYTE Key[20];
memcpy(Key, 0x0b, 20);
int size = sizeof(Key);

Here size was = 20.

But
const char* dummyKey = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
BYTE Key*;
convert_string_to_byte(dummyKey, Key);
int size = sizeof(Key);

Here size was = 4; 

Now this may be trivial to some people but wasn't for me.

Anyways thanks for all your help.

Regards

Vinay Julme
**************

Tim Mensch

unread,
May 30, 2011, 4:10:03 PM5/30/11
to andro...@googlegroups.com
On 5/30/2011 2:13 AM, Vinay Julme wrote:
> But
> const char* dummyKey = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
> BYTE Key*;
> convert_string_to_byte(dummyKey, Key);
> int size = sizeof(Key);
>
> Here size was = 4;

That's because a Key* is size 4 on that architecture. You're getting the
size of the pointer. There's no way for the compiler to know the length
of a buffer at compile-time.

BUT, more importantly, what does convert_string_to_byte do? Key hasn't
been assigned anything above, and so unless I'm missing something, your
function is likely writing to a random address in RAM.

Tim

Ryan King

unread,
Feb 20, 2014, 8:10:07 AM2/20/14
to andro...@googlegroups.com
I want use aes.c in android with the help of ndk. But there came a problem, how to pass string to const unsigned char*.The I saw this ,I came with flowing code.But the result is wrong,when I encode a string and decode it ,it was different .messy code.......!!!!
c part:

extern "C" jbyteArray Java_com_ryan_aes_test_MainActivity_stringToJNIencode(
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;
}
java part
 Text = (EditText) findViewById(R.id.show);
btnEncode.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String plainText = Text.getText().toString();
byte[] plainTextBytes = null;
int len = 0;
try {
plainTextBytes = plainText.getBytes("UTF-8");
len = plainTextBytes.length;
Log.v("ds", String.valueOf(len));
byte[] bytes = stringToJNIencode(len, plainTextBytes);
String s = new String(bytes,"UTF-8");
Text.setText(s);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

});
Reply all
Reply to author
Forward
0 new messages