Casting NSString to unsigned char * - objective-c

I'm trying to use a function that has the following signature to sign a HTTP request:
extern void hmac_sha1(const unsigned char *inText, int inTextLength, unsigned char* inKey, const unsigned int inKeyLength, unsigned char *outDigest);
And this is the method I wrote to use it:
- (NSString *)sign: (NSString *)stringToSign {
NSString *secretKey = #"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const unsigned char *inText = (unsigned char *)[stringToSign UTF8String];
int inTextLength = [stringToSign length];
unsigned char *inKey = (unsigned char *)[secretKey UTF8String];
const unsigned int inKeyLength = (unsigned int)[secretKey length];
unsigned char *outDigest;
hmac_sha1(inText, inTextLength, inKey, inKeyLength, outDigest);
NSString *output = [NSString stringWithUTF8String:(const char *)outDigest];
return output;
}
The problem is I'm sure this is not the way I'm supposed to do this casting, as inside this hmac_sha1 function I get a EXC_BAD_ACCESS exception.
Since I am new to Objective-C and have close to no experience in C (surprise!) I don't really know what to search for. Any tips on how I can start solving this?
Thanks in advance!
BTW, I got the reference for this function here in stackoverflow.

It looks like the problem is not with the casting, but with outDigest. The fifth argument to hmac_sha1 should point to an already allocated buffer of size 20 bytes (I think).
If you change the line that says
unsigned char *outDigest;
to say
#define HMACSHA1_DIGEST_SIZE 20
void *outDigest = malloc(HMACSHA1_DIGEST_SIZE);
That should get you past the crash inside hmac_sha1.
Then you've got the problem of converting the data at outDigest into an NSString. It looks like hmac_sha1 will put 20 bytes of random-looking data at outDigest, and not a null terminated UTF-8 string, so stringWithUTF8String: won't work. You might want to use something like this instead if you have to return an NSString:
NSString *output = [[NSString alloc] initWithBytesNoCopy:outDigest
length:HMACSHA1_DIGEST_SIZE
encoding:NSASCIIStringEncoding
freeWhenDone:YES];
I don't think NSString is really the right type for the digest, so it might be worth changing your method to return an NSData if you can.

This wasn't part of your question but it's a bug nonetheless, you shouldn't use -length to get the byte count of an UTF8 string. That method returns the number of Unicode characters in the string, not the number of bytes. What you want is -lengthOfBytesUsingEncoding:.
NSUInteger byteCount = [stringToSign lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
Also be aware that the result does not account for a terminating NULL character.

Are you sure you don't need to allocate some memory for outDigest before calling hmac_sha1? Since you pass in a pointer, rather than a pointer to a pointer, there's no way that the memory can be allocated inside the routine.

Related

How to print unsigned char* in NSLog()

Title pretty much says everything.
would like to print (NOT in decimal), but in unsigned char value (HEX).
example
unsigned char data[6] = {70,AF,80,1A, 01,7E};
NSLog(#"?",data); //need this output : 70 AF 80 1A 01 7E
Any idea? Thanks in advance.
There is no format specifier for an char array. One option would be to create an NSData object from the array and then log the NSData object.
NSData *dataData = [NSData dataWithBytes:data length:sizeof(data)];
NSLog(#"data = %#", dataData);
Nothing in the standard libraries will do it, so you could write a small hex dump function, or you could use something else that prints non-ambigious full data. Something like:
char buf[1 + 3*dataLength];
strvisx(buf, data, dataLength, VIS_WHITE|VIS_HTTPSTYLE);
NSLog(#"data=%s", buf);
For smallish chunks of data you could try to make a NSData and use the debugDescription method. That is currently a hex dump, but nothing promises it will always be one.
To print char* in NSLog try the following:
char data[6] = {'H','E','L','L','0','\n'};
NSString *string = [[NSString alloc] initWithUTF8String:data];
NSLog(#"%#", string);
You will need to null terminate your string.
From Apple Documentation:
- (instancetype)initWithUTF8String:(const char *)nullTerminatedCString;
Returns an NSString object initialized by copying the characters from a given C array of UTF8-encoded bytes.

How to convert an "initWithBytes" NSString to unsigned char*

How to convert an "initWithBytes" NSString to unsigned char*?
here's how the NSString produced
NSString *byte = [[[NSString alloc] initWithBytes:inputbytes length:inputlength encoding:NSASCIIStringEncoding] autorelease];
which contains bytes data that should not be changed in bit level(will be the input of base64 conversion)
The data in the byte is 0x01 0x00 0x01, 3 bytes
and I want to convert it into an unsigned char*
How should I do it?
Thanks
Generally speaking, you should work with NSString directly rather than attempting to move in and out of Objective-C. But there are reasons to drop down to C (e.g. using a C-only API) so I'll humour you. ;)
If you just need to pass the data to another function, you can do this:
const unsigned char *cString = (const unsigned char *)[byte cStringUsingEncoding: NSASCIIStringEncoding];
If you need to modify the C string (i.e. make it non-const), you will need to make a copy:
const unsigned char *cString = (const unsigned char *)strdup([byte cStringUsingEncoding: NSASCIIStringEncoding]);
And then free() it when you're done with it:
free(cString);
Note that this will not modify the original C string or the NSString you made from it. If you need an NSString you can modify, use NSMutableString.
Try the cStringUsingEncoding: method of NSString:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/uid/20000154-BAJHJHHD

How to convert NSString to C string?

I know that this question is a possible duplicate, but even after looking at some Google tutorials and questions even on this forum none of them gives me a decent answer about this subject.
I have:
NSString *str = #"text";
And I would like to do something like:
char cstring [512] = str;
(this only shows what I want to do, after looking at Apple's NSString Class Ref I didn't even think about using it).
Up to now I have:
char command [512] = [[NSString stringWithFormat:#"text"] cStringUsingEncoding:NSUTF8StringEncoding];
Still, with that I get errors.
Any solution?
try const char *command = [str UTF8String];
A c string is returned as a pointer, not as an array of characters. To use it, you can change your variable to a pointer.
const char *command = [theString cStringUsingEncoding:NSUTF8StringEncoding];
Since you want the UTF8 encoding, you can use the UTF8String convenience method.
const char *command = [theString UTF8String];
If you need the data to be stored in a character array, you can use the getCString:maxLength:encoding: method, passing the array as the buffer. This will allow you to store the string directly to the buffer, and will tell you if the buffer is too small.
char command[512];
if(![theString getCString:command maxLength:sizeof(command)/sizeof(*command) encoding:NSUTF8StringEncoding]) {
NSLog(#"Command buffer too small");
}

Defined behavior of cast from unsigned char * to char * in Objective-C

I understand the difference between unsigned char * and char * types. I also understand how to use reinterpret_cast to cast an unsigned char * to a char * in C++.
I'm using sqlite3 in Objective-C and am trying to get an NSString from a call to
sqlite3_column_text(...);
To do this, I'm basically doing:
char *cParam = (char *)sqlite3_column_text(compiledStatementPtr, 0);
NSString *aParam = nil;
if (cParam) {
aParam = [NSString stringWithUTF8String:cParam];
}
sqlite3_column_text(), however, returns an unsigned char * and I'm worried about the behavior of the cast to char *. I've read that the cast is implemenation specific and I was wondering if this is a safe cast in Objective-C or if I'm totally barking up the wrong tree?
You don't have much to worry about due to the cast. Actually, Apple sample code uses the exact same code pattern you are using:
self.title =
[NSString stringWithUTF8String:(char *)sqlite3_column_text(init_statement, 0)];
(From SQLite Book List Book.m class).
I think you should be more concerned with the database actually having UTF-8 strings.

casting a NSString to char problem

i want to casting my NSString to a constant char
the code is shown below :
NSString *date = #"12/9/2009";
char datechar = [date UTF8String]
NSLog(#"%#",datechar);
however it return the warning
assignment makes integer from pointer without a cast
and cannot print the char properly,can somebody tell me what is the problem
Try something more like this:
NSString* date = #"12/9/2009";
char* datechar = [date UTF8String];
NSLog(#"%s", datechar);
You need to use char* instead of char, and you have to print C strings using %s not %# (%# is for objective-c id types only).
I think you want to use:
const char *datechar = [date UTF8String];
(note the * in there)
Your code has 2 problems:
1) "char datechar..." is a single-character, which would only hold one char / byte, and wouldn't hold the whole array that you are producing from your date/string object. Therefore, your line should have a (*) in-front of the variable to store multi characters rather than just the one.
2) After the above fix, you would still get a warning about (char *) vs (const char *), therefore, you would need to "cast" since they are technically the same results. Change the line of:
char datechar = [date UTF8String];
into
char *datechar = (char *)[date UTF8String];
Notice (char *) after the = sign, tells the compiler that the expression would return a (char *) as opposed to it's default (const char *).
I know you have already marked the answer earlier however, I thought I could contribute to explain the issues and how to fix in more details.
I hope this helps.
Kind Regards
Heider
I would add a * between char and datechar (and a %s instead of a %#):
NSString *date=#"12/9/2009"; char * datechar=[date UTF8String];
NSLog(#"%s",datechar);
I was suffering for a long time to convert NSString to char to use for this function
-(void)gpSendDTMF:(char) digit callID: (int)cid;
I have tried every answer of this question/many things from Google search but it did not work for me.
Finally I have got the solution.
Solution:
NSString *digit = #"5";
char dtmf;
char buf[2];
sprintf(buf, "%d", [digit integerValue]);
dtmf = buf[0];