How do you convert an unsigned char array to an NSData in objective c?
This is what I am trying to do, but it doesn't work.
Buffer is my unsigned char array.
NSData *data = [NSData dataWithBytes:message length:length];
You can just use this NSData class method
+ (id)dataWithBytes:(const void *)bytes length:(NSUInteger)length
Something like
NSUInteger size = // some size
unsigned char array[size];
NSData* data = [NSData dataWithBytes:(const void *)array length:sizeof(unsigned char)*size];
You can then get the array back like this (if you know that it is the right data type)
NSUInteger size = [data length] / sizeof(unsigned char);
unsigned char* array = (unsigned char*) [data bytes];
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I need to generate HMAC-SHA1 in Objective C. But i didnt find anything that works. I tried with CommonCrypto, using CCHMAC, but didnt works. I need to generate a hmac and after generate HOTP number.
Somebody have any example code in Objective C or C?
Here's how you generate an HMAC using SHA-256:
NSString *key;
NSString *data;
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC
length:sizeof(cHMAC)];
NSString *hash = [HMAC base64Encoding];
I'm not aware of an HOTP library, but the algorithm was quite simple, if I recall correctly.
here is how you can generate HMAC-SHA1 base64.
You need to add Base64.h and Base64.m to your project. You can get it from here.
If you use ARC, it will show some errors in Base64.m. Find the lines who are similar like this
return [[[self alloc] initWithBase64String:base64String] autorelease];
what you need is to delete the autorelease section. The final result should look like:
return [[self alloc] initWithBase64String:base64String];
Now in your general project import "Base64.h"
and the following code
#import "Base64.h"
#include <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonHMAC.h>
- (NSString *)hmacsha1:(NSString *)data secret:(NSString *)key {
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
NSString *hash = [HMAC base64String];
return hash;
}
With
NSLog(#"Hash: %#", hash);
you will get something similar to this:
ghVEjPvxwLN1lBi0Jh46VpIchOc=
This is the complete solution which works without any extra libraries or hacks:
+(NSString *)hmac:(NSString *)plainText withKey:(NSString *)key
{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [plainText cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMACData = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
const unsigned char *buffer = (const unsigned char *)[HMACData bytes];
NSString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2];
for (int i = 0; i < HMACData.length; ++i)
HMAC = [HMAC stringByAppendingFormat:#"%02lx", (unsigned long)buffer[i]];
return HMAC;
}
You don't have to include any third-party base64 library as it is already encoded.
This works without using custom protocols, using some code from
http://cocoawithlove.com/2009/07/hashvalue-object-for-holding-md5-and.html
HashSHA256.h
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#interface HashSHA256 : NSObject {
}
- (NSString *) hashedValue :(NSString *) key andData: (NSString *) data ;
#end
HashSHA256.m
#import "HashSHA256.h"
#import <CommonCrypto/CommonHMAC.h>
#implementation HashSHA256
- (NSString *) hashedValue :(NSString *) key andData: (NSString *) data {
const char *cKey = [key cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSString *hash;
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++)
[output appendFormat:#"%02x", cHMAC[i]];
hash = output;
return hash;
}
#end
Usage:
- (NSString *) encodePassword: (NSString *) myPassword {
HashSHA256 * hashSHA256 = [[HashSHA256 alloc] init];
NSString * result = [hashSHA256 hashedValue:mySecretSalt andData:myPassword];
return result;
}
This is how yo do it without external files returning an hex string:
-(NSString *)hmac:(NSString *)plaintext withKey:(NSString *)key
{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [plaintext cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
const unsigned char *buffer = (const unsigned char *)[HMACData bytes];
NSMutableString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2];
for (int i = 0; i < HMACData.length; ++i){
[HMAC appendFormat:#"%02x", buffer[i]];
}
return HMAC;
}
It was tested in xCode 5 with iOS 7 and works fine!
I spend a whole day, trying to convert the generated hash (bytes) into readable data. I used the base64 encoded solution from the answer above and it didn´t work at all for me (b.t.w. you need and an external .h to be able to use the base64 encoding, which I had).
So what I did was this (which works perfectly without an external .h):
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
// Now convert to NSData structure to make it usable again
NSData *out = [NSData dataWithBytes:cHMAC length:CC_SHA256_DIGEST_LENGTH];
// description converts to hex but puts <> around it and spaces every 4 bytes
NSString *hash = [out description];
hash = [hash stringByReplacingOccurrencesOfString:#" " withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#"<" withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#">" withString:#""];
// hash is now a string with just the 40char hash value in it
NSLog(#"%#",hash);
Out of interest, why do you create (unsigned char cHMAC) and then convert into (NSData) and then convert it into (NSMutableString) and then convert finally into (HexString)?
You could do this in a quicker way by cutting the middleman (i.e. without NSData and NSMutableString altogether, quicker and better performance), also changing (unsigned char) into (uint8_t []), after all they are all hex-arrays anyway!, below:
-(NSString *)hmac:(NSString *)plaintext withKey:(NSString *)key
{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [plaintext cStringUsingEncoding:NSASCIIStringEncoding];
uint8_t cHMAC[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSString *Hash1 = #"";
for (int i=0; i< CC_SHA1_DIGEST_LENGTH; i++)
{
Hash1 = [Hash1 stringByAppendingString:[NSString stringWithFormat:#"%02X", cHMAC[i]]];
}
return Hash1;
}
I hope this helps,
Regards
Heider Sati
Have you seen Jens Alfke's new MyCrypto classes?
He has some sample code on his blog.
I am converting a Java code to Objective C to match signature in request with SHA256.
Here are my inputs and outputs:
#
Java:
SecretKeySpec key = new SecretKeySpec(client_secret.getBytes("UTF-8"), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(key);
byte[] bytes = mac.doFinal(baseString.getBytes("UTF-8"));
String signature = new String(Base64.encodeBase64(bytes));
log.info("signature="+signature);
Output is: signature=q4T4uuz482U+guKa8oRn8Enq9xJjSRYvQlYxF6TSAFQ=
Obj C:
-- (NSString*) HMACWithSec:(NSString*) secret data:(NSString*) data {
const char *cKey = [secret cStringUsingEncoding:NSASCIIStringEncoding];
//Making it NSUTF8StringEncoding does not help
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *hash = [[NSData alloc] initWithBytes: cHMAC length:CC_SHA256_DIGEST_LENGTH];
// I tried making a Hex string out of the bytes and then covering it back to ASCII or UTF-8, did not work.
NSString* signature = [hash base64EncodedStringWithOptions:0];
//All base 64 methods returns same. I found this as most convenient.
NSLog(#"%#", signature);
return signature;
}
Output is: HcqgsyTj0DRYlGT1QV9L48LcvX9Zc+eX8ShXjJQEDKc=
#
I tried the following too:
NSString *s8 = [NSString stringWithCharacters:(const char *)cHMAC length:sizeof(cHMAC)];
Output is arbitrary chars.
Explanation:
Both inputs are same for secret and data. I verified with cKey and cData. After I am getting the bytes in obj c into "cHMAC". Making it a NSData and then getting the base64 string is not generating the same string.
Question:
What did I miss out? Any insight helps.
I would like to sign a request with HMAC SHA512, but I seem to mess up encoding and decoding from and to NSData and NSString. I desperately tried to figure out what is wrong, but I just don't seem to get it right.
PSEUDOCODE:
function hmac_512(msg, sec) {
sec = Base64Decode(sec);
result = hmac(msg, sec, sha512);
return Base64Encode(result);
}
secret = "7pgj8Dm6";
message = "Test\0Message";
result = hmac_512(message, secret);
if (result == "69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==")
print("Success!");
else
printf("Error: %s", result);
My implementation:
+(void)doSomeMagic{
NSString *message = #"Test\0Message";
NSString *signedRequest = [self signRequestForParameterString:message];
//checking against CORRECT (from JAVA equivalent) signed request
if ([signedRequest isEqualToString:#"69H45OZkKcmR9LOszbajUUPGkGT8IqasGPAWqW/1stGC2Mex2qhIB6aDbuoy7eGfMsaZiU8Y0lO3mQxlsWNPrw==" ])
NSLog(#"Success!");
else
NSLog(#"Error!");
}
Here is the signing method:
+(NSString *)signRequestForParameterString:(NSString*)paramStr{
NSString *secret = #"7pgj8Dm6";
// secret is base64 encoded, so I decode it
NSData *decodedSecret = [secret base64DecodedData];
NSString *decodedSecretString = [NSString stringWithUTF8String:[decodedSecret bytes]];
NSData *data = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *dataString = [NSString stringWithUTF8String:[data bytes]];
return [self generateHMACSHA512Hash:decodedSecretString data:dataString];
}
Here is the hashing function:
+(NSString *)generateHMACSHA512Hash:(NSString *)key data:(NSString *)data{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC
length:sizeof(cHMAC)];
NSString *hash = [HMAC base64EncodedString];
return hash;
}
I am pretty sure it is due to the encoding of the strings (decodedSecretString and dataString). decodedSecretString (decoded base64) after decoding is encoded in ASCII. However, when I call the hashing method, I encode it in ascii again, which will result in a null error. Everything is confusing me right now.
Your secret doesn't decode to a valid UTF-8 string, and Java allows NUL bytes in strings, but when you're converting "Test\0Message" to a C string and using strlen, its length is 4.
Something like this should work:
+(NSString *)signRequestForParameterString:(NSString*)paramStr{
NSString *secret = #"7pgj8Dm6";
NSData *data = [paramStr dataUsingEncoding:NSUTF8StringEncoding];
return [self generateHMACSHA512Hash:[secret base64DecodedData] data:data];
}
+(NSString *)generateHMACSHA512Hash:(NSData *)key data:(NSData *)data{
unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, key.bytes, key.length, data.bytes, data.length, cHMAC);
NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
return [HMAC base64EncodedString];
}
When doing HMAC or other cryptographic functions, you should build up some fundamental methods/functions that don't deal with strings first. Then you can create wrapper methods that decode/encode string data or digests in a convenient way.
+ (NSData *)dataBySigningData:(NSData *)data withKey:(NSData *)key
{
unsigned char cHMAC[CC_SHA512_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA512, [key bytes], [key length], [data bytes], [data lenght], cHMAC);
return [[NSData alloc] initWithBytes:cHMAC length:CC_SHA512_DIGEST_LENGTH];
}
+ (NSData *)dataBySigningMessage:(NSString *)message withKey:(NSData *)key
{
return [self dataBySigningData:[message dataUsingEncoding:NSUTF8StringEncoding]
withKey:[key dataUsingEncoding:NSUTF8StringEncoding]];
}
(Note: this code is not tested, just hacked together in a text editor)
Don't worry about the string representation of your key or data. Then you can go from there, e.g. getting the base64 encoding of the digest.
Cryptographic functions DO NOT CARE about strings or text encodings. They care about bytes. Strings (in C, since they are null-terminated) are a mere subset of what can be represented in data. So it would be severely limiting to deal with strings.
I am trying to convert a string to a 32-bit unsigned, network (big-endian) byte order. I can't seem to figure out how to do this. In Ruby I accomplish this by string.unpack('N') - but can't seem how to manage this in Objective-C. Any suggestions? Thanks!
In Objective-C you would convert NSString to NSData. Then you can access the bytes from the NSData object.
NSString *str = #"😄 H€llö Wòrld";
NSData *data = [str dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSLog(#"%#", data);
// Output:
// <0001f604 00000020 00000048 000020ac 0000006c 0000006c 000000f6 00000020 00000057 000000f2 00000072 0000006c 00000064>
const uint8_t *bytes = [data bytes]; // pointer to converted bytes
NSUInteger length = [data length]; // number of converted bytes