how to convert NSData to char array containing hexa values - iphone

i am receiving NSData by following method
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
server send data in follwing format
04 01 00
as hexa values. so now need to convert this data into char array so that i can access every pair separately
please help

You can go like this if you'd like to compare byte by byte:
//NSData *test; // assume this is your NSData containing 0x04 0x01 0x00
char *ptr = (void *)[test bytes]; // set a pointer to the beginning of your data bytes
if(*ptr == 0x04) {
NSLog(#"okay,.. got a 0x04");
}
ptr++; // go to the next byte
if(*ptr == 0x01) {
NSLog(#"okay,.. got a 0x01");
}
hope that does work for you.

Related

parsing NSData object for information

I have a NSData object coming back from my server, it varies in its content but sticks to a particular structure.
I would like to know (hopfully with some example code) how to work though this object to get the data I need out of it.
the structure of the data objects inside the objects are like this
leading value (UInt16) - (tells me what section of the response it is)
Size of string (UInt32) or number - (UInt32)
String (not null terminated) i.e. followed by the next leading value.
I have been reading through the Binary Data Programming Guide however that's only really showing me how to put my data into new NSData objects and accessing and compairing the bytes.
The thing I am stuck on is how do I say grab the info dynamically. Check the NSdata objects first leading value figure out if its string or int then get the string or int and move onto the next leading value..
any suggestions or example code would be really helpfull.. just stuck in abit of a mind block as I have never attempted anything like this in objective C.
Some of this depends on how your server is written to encode the data into what it is sending you. Assuming it is encoding the numeric values using standard network byte ordering (big-endian) you will want it converted to the correct byte-ordering for iOS (I believe that is always little-endian).
I would approach it something like this:
uint16_t typeWithNetworkOrdering, typeWithLocalOrdering;
uint32_t sizeWithNetworkOrdering, sizeWithLocalOrdering;
char *cstring = NULL;
uint32_t numberWithNetworkOrdering, numberWithLocalOrdering;
const void *bytes = [myData bytes];
NSUInteger length = [myData length];
while (length > 0) {
memcpy(&typeWithNetworkOrdering, bytes, sizeof(uint16_t));
bytes += sizeof(uint16_t);
length -= sizeof(uint16_t);
memcpy(&sizeWithNetworkOrdering, bytes, sizeof(uint32_t));
bytes += sizeof(uint32_t);
length -= sizeof(uint32_t);
typeWithLocalOrdering = CFSwapInt16BigToHost(typeWithNetworkOrdering);
sizeWithLocalOrdering = CFSwapInt32BigToHost(sizeWithNetworkOrdering);
if (typeWithLocalOrdering == STRING_TYPE) { // STRING_TYPE is whatever type value corresponds to a string
cstring = (char *) malloc(sizeWithLocalOrdering + 1);
strncpy(cstring, bytes, sizeWithLocalOrdering);
cstring[sizeWithLocalOrdering] = '\0';
NSString *resultString = [NSString stringWithCString:cstring encoding:NSUTF8StringEncoding];
NSLog(#"String = %#", resultString);
free(cstring);
bytes += sizeWithLocalOrdering;
length -= sizeWithLocalOrdering;
// Do whatever you need to with the string
}
else if (typeWithLocalOrdering == NUMBER_TYPE) { // NUMBER_TYPE is whatever type value corresponds to a number
memcpy(&numberWithNetworkOrdering, bytes, sizeof(uint32_t));
numberWithLocalOrdering = CFSwapInt32BigToHost(numberWithNetworkOrdering);
NSLog(#"Number = %u", numberWithLocalOrdering);
bytes += sizeof(uint32_t);
length -= sizeof(uint32_t);
// Do whatever you need to with the number
}
}
Define your own internal structs and cast the pointer to it:
NSData* data;
struct headerType
{
uint16_t type;
uint32_t length;
};
const struct headerType* header=(const struct headerType*)[data bytes]; // get the header of the response
if (header->type==1)
{
const char* text=((const char*)header)+6; // skip the header (16bits+32bits=6 bytes offset)
}
EDIT:
If you need to read them in a loop:
NSData* data;
const uint8_t* cursor=(const uint8_t*)[data bytes];
while (true)
{
uint16_t type=*((uint16_t*)cursor);
cursor+=2;
if (cursor==1)
{
// string
uint32_t length=*((uint32_t*)cursor);
cursor+=4;
const char* str=(const char*)cursor;
cursor+=length;
}
else if (cursor==2)
{
// another type
}
else
break;
}

How To Generate SHA256 and CRC32 in ios

I am doing a file uploading job. I want to generate SHA256 and CRC32 hashes. Can anyone help me how shall I generate those hash? I want to get it working for iOS.
SHA256 is available in CommonCrypto. CRC32 is not a hash, it a Cyclic Redundancy Check.
Example code:
#import <CommonCrypto/CommonDigest.h>
NSData *dataIn = [#"Now is the time for all good computers to come to the aid of their masters." dataUsingEncoding:NSASCIIStringEncoding];
NSMutableData *macOut = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
CC_SHA256(dataIn.bytes, dataIn.length, macOut.mutableBytes);
NSLog(#"dataIn: %#", dataIn);
NSLog(#"macOut: %#", macOut);
NSLog output:
dataIn: <4e6f7720 69732074 68652074 696d6520 666f7220 616c6c20 676f6f64 20636f6d 70757465 72732074 6f20636f 6d652074 6f207468 65206169 64206f66 20746865 6972206d 61737465 72732e>
macOut: <53f89cf6 7ebfbe56 89f1f76a 3843dfd1 09d68c5b a938dcd2 9a12004e 108260cb>
For both of these, you can use this gist:
https://gist.github.com/paul-delange/6808278
And an example
NSString* crc32 = (__bridge NSString*)TGDFileHashCreateWithPath((__bridge CFStringRef)filepath, TGDFileHashDefaultChunkSizeForReadingData, TGDChecksumAlgorithmCRC32);
This method will generate crc32c as used by gcloud on iOS from a filepath. If you want the standard crc32 just uncomment the other value for CRC32_POLYNOMIAL.
It reads the file given in 512KB chunks so can be used on large files.
- (NSString*) crc32c:(NSString*)filepath{
/// using crc code from
// http://classroomm.com/objective-c/index.php?action=printpage;topic=2891.0
// by rgronlie
//this is the standard crc32 polynomial
//uint32_t CRC32_POLYNOMIAL = 0xEDB88320;
//this is the crc32c one
uint32_t CRC32_POLYNOMIAL = 0x82F63B78L;
uint32_t CRC32C_SEED = 0xFFFFFFFFL;
// create and populate a lookup table
uint32_t* pCRCTable = malloc(sizeof(uint32_t) * 256);
for (uint32_t i = 0; i <= 255; i++)
{
uint32_t crc32 = i;
for (uint32_t j = 8; j > 0; j--)
{
if ((crc32 & 1) == 1)
crc32 = (crc32 >> 1) ^ CRC32_POLYNOMIAL;
else
crc32 >>= 1;
}
pCRCTable[i] = crc32;
}
// get a handle to the file
NSFileHandle *filehandle = [NSFileHandle fileHandleForReadingAtPath:filepath];
if(filehandle == NULL){
NSLog(#"failed to create file handle");
return nil;
}
// a buffer to read into
NSData* databuffer;
uint32_t crc = CRC32C_SEED;
// read the file in chunks of 512KB
while(true){
databuffer = [filehandle readDataOfLength: 512 * 1024];
// if there is nothing left finish
if([databuffer length] == 0){
break;
}
// otherwise run each chunk through the lookup table
uint8_t *pBytes = (uint8_t *)[databuffer bytes];
uint32_t length = [databuffer length];
while (length--)
{
crc = (crc>>8) ^ pCRCTable[(crc & 0xFF) ^ *pBytes++];
}
}
// clean up
[filehandle closeFile];
free(pCRCTable);
// this is the result
uint32_t hash = crc ^ 0xFFFFFFFFL;
// reverse it for endianness
uint32_t hash_reversed = CFSwapInt32HostToBig(hash);
// as raw bytes
NSData* hash_data = [NSData dataWithBytes: &hash_reversed length: sizeof(hash_reversed)];
// return base64 encoded
return [hash_data base64EncodedStringWithOptions:0];
}
there are no apps which can generate Hash for ios
This should work....its for Mac
http://itunes.apple.com/us/app/digiprint/id473233587?mt=12

How to resolve File not availabe

This is the code I am using for the encryption but it generate an error
"CCKeyDerivationPBKDF is unavailable" in AESKeyForPassword method though it is declare before implementation. How to Resolve it.
#ifndef _CC_PBKDF_H_
#define _CC_PBKDF_H_
#include <sys/types.h>
#include <sys/param.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <Availability.h>
#include <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonHMAC.h>
#ifdef __cplusplus
extern "C" {
#endif
enum {
kCCPBKDF2 = 2,
};
typedef uint32_t CCPBKDFAlgorithm;
enum {
kCCPRFHmacAlgSHA1 = 1,
kCCPRFHmacAlgSHA224 = 2,
kCCPRFHmacAlgSHA256 = 3,
kCCPRFHmacAlgSHA384 = 4,
kCCPRFHmacAlgSHA512 = 5,
};
typedef uint32_t CCPseudoRandomAlgorithm;
/*
#function CCKeyDerivationPBKDF
#abstract Derive a key from a text password/passphrase
#param algorithm Currently only PBKDF2 is available via kCCPBKDF2
#param password The text password used as input to the derivation
function. The actual octets present in this string
will be used with no additional processing. It's
extremely important that the same encoding and
normalization be used each time this routine is
called if the same key is expected to be derived.
#param passwordLen The length of the text password in bytes.
#param salt The salt byte values used as input to the derivation
function.
#param saltLen The length of the salt in bytes.
#param prf The Pseudo Random Algorithm to use for the derivation
iterations.
#param rounds The number of rounds of the Pseudo Random Algorithm
to use.
#param derivedKey The resulting derived key produced by the function.
The space for this must be provided by the caller.
#param derivedKeyLen The expected length of the derived key in bytes.
#discussion The following values are used to designate the PRF:
* kCCPRFHmacAlgSHA1
* kCCPRFHmacAlgSHA224
* kCCPRFHmacAlgSHA256
* kCCPRFHmacAlgSHA384
* kCCPRFHmacAlgSHA512
#result kCCParamError can result from bad values for the password, salt,
and unwrapped key pointers as well as a bad value for the prf function.
*/
int CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
const uint8_t *salt, size_t saltLen,
CCPseudoRandomAlgorithm prf, uint rounds,
uint8_t *derivedKey, size_t derivedKeyLen)
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
/*
* All lengths are in bytes - not bits.
*/
/*
#function CCCalibratePBKDF
#abstract Determine the number of PRF rounds to use for a specific delay on
the current platform.
#param algorithm Currently only PBKDF2 is available via kCCPBKDF2
#param passwordLen The length of the text password in bytes.
#param saltLen The length of the salt in bytes.
#param prf The Pseudo Random Algorithm to use for the derivation
iterations.
#param derivedKeyLen The expected length of the derived key in bytes.
#param msec The targetted duration we want to achieve for a key
derivation with these parameters.
#result the number of iterations to use for the desired processing time.
*/
uint CCCalibratePBKDF(CCPBKDFAlgorithm algorithm, size_t passwordLen, size_t saltLen,
CCPseudoRandomAlgorithm prf, size_t derivedKeyLen, uint32_t msec)
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
#ifdef __cplusplus
}
#endif
#endif /* _CC_PBKDF_H_ */
#import "AESEncryption.h"
#import <CommonCrypto/CommonCryptor.h>
//#import <CommonCrypto/CommonKeyDerivation.h>
//#import <CommonKeyDerivation.h>
#implementation AESEncryption
NSString * const
kRNCryptManagerErrorDomain = #"net.robnapier.RNCryptManager";
const CCAlgorithm kAlgorithm = kCCAlgorithmAES128;
const NSUInteger kAlgorithmKeySize = kCCKeySizeAES128;
const NSUInteger kAlgorithmBlockSize = kCCBlockSizeAES128;
const NSUInteger kAlgorithmIVSize = kCCBlockSizeAES128;
const NSUInteger kPBKDFSaltSize = 8;
const NSUInteger kPBKDFRounds = 1000;//0; // ~80ms on an iPhone 4
// ===================
+ (NSData *)encryptedDataForData:(NSData *)data
password:(NSString *)password
iv:(NSData **)iv
salt:(NSData **)salt
error:(NSError **)error {
NSAssert(iv, #"IV must not be NULL");
NSAssert(salt, #"salt must not be NULL");
*iv = [self randomDataOfLength:kAlgorithmIVSize];
*salt = [self randomDataOfLength:kPBKDFSaltSize];
NSData *key = [self AESKeyForPassword:password salt:*salt];
size_t outLength;
NSMutableData *
cipherData = [NSMutableData dataWithLength:data.length +
kAlgorithmBlockSize];
CCCryptorStatus
result = CCCrypt(kCCEncrypt, // operation
kAlgorithm, // Algorithm
kCCOptionPKCS7Padding, // options
key.bytes, // key
key.length, // keylength
(*iv).bytes,// iv
data.bytes, // dataIn
data.length, // dataInLength,
cipherData.mutableBytes, // dataOut
cipherData.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result == kCCSuccess) {
cipherData.length = outLength;
}
else {
if (error) {
*error = [NSError errorWithDomain:kRNCryptManagerErrorDomain
code:result
userInfo:nil];
}
return nil;
}
return cipherData;
}
// ===================
+ (NSData *)randomDataOfLength:(size_t)length {
NSMutableData *data = [NSMutableData dataWithLength:length];
int result = SecRandomCopyBytes(kSecRandomDefault, length,data.mutableBytes);
NSLog(#"%d",result);
NSAssert1(result == 0, #"Unable to generate random bytes: %d", errno);
//NSAssert( #"Unable to generate random bytes: %d", errno);
return data;
}
// ===================
// Replace this with a 10,000 hash calls if you don't have CCKeyDerivationPBKDF
+ (NSData *)AESKeyForPassword:(NSString *)password
salt:(NSData *)salt {
NSMutableData *
derivedKey = [NSMutableData dataWithLength:kAlgorithmKeySize];
int result = CCKeyDerivationPBKDF(kCCPBKDF2, // algorithm
password.UTF8String, // password
password.length, // passwordLength
salt.bytes, // salt
salt.length, // saltLen
kCCPRFHmacAlgSHA1, // PRF
kPBKDFRounds, // rounds
derivedKey.mutableBytes, // derivedKey
derivedKey.length); // derivedKeyLen
NSLog(#"%d",result);
// Do not log password here
NSAssert1(result == kCCSuccess,#"Unable to create AES key for password: %d", result);
//NSAssert(#"Unable to create AES key for password: %d", result);
return derivedKey;
}
#end
The code placed above implementation is of CommonCrypto/CommonKeyDerivation.h which was not found be me xcode and hence I put code directly at the top.
Try to comment out this lines:
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
I think they limit the method to a particular Operating System and this is exactly what you don't need.
But I cannot guarantee if further issues may appear. I'm trying to achieve the same.
You have merely declared 2 prototypes for CCKeyDerivationPBKDF and CCCalibratePBKDF. Either put the full code for the functions at this place or declare them as extern and have them in a seperate module or library.

iOS/Objective C: SHA-1 and Base64

I have to convert the phrase '1234' into the Base64-encoding of its SHA-1 hash.
I want to have: '1234' = cRDtpNCeBiql5KOQsKVyrA0sAiA=
(This example work in connection with the server communication)...
But when I checked it manualley on these sites or use my Methods in my XCode Project the result is always different:
1234
After SHA-1 (http://www.sha1.cz/)
7110eda4d09e062aa5e4a390b0a572ac0d2c0220
After Base64 (http://base64-encoder-online.waraxe.us/)
NzExMGVkYTRkMDllMDYyYWE1ZTRhMzkwYjBhNTcyYWMwZDJjMDIyMA==
This is my SHA-1 function:
- (NSString *)sha1:(NSString *)str {
const char *cStr = [str UTF8String];
unsigned char result[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(cStr, strlen(cStr), result);
NSString *s = [NSString stringWithFormat:
#"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3], result[4],
result[5], result[6], result[7],
result[8], result[9], result[10], result[11], result[12],
result[13], result[14], result[15],
result[16], result[17], result[18], result[19]
];
return [s lowercaseString];
}
For Base64 I use a this class: http://cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html
This is the call of SHA-1 and Base64:
NSString *pwHash =[self sha1:self._txtFieldPW.text]; //In my case '1234'
NSLog(#"Hash: %#",pwHash); //7110eda4d09e062aa5e4a390b0a572ac0d2c0220
//7110eda4d09e062aa5e4a390b0a572ac0d2c0220
NSData *pwHashData = [[NSData alloc]initWithData:[pwHash dataUsingEncoding:1]];
NSString *base64 = [pwHashData base64Encoding];
NSLog(#"Base64: %#",base64);
//NzExMGVkYTRkMDllMDYyYWE1ZTRhMzkwYjBhNTcyYWMwZDJjMDIyMA==
What is going wrong?
Hash is a binary value. The "cRDtpNCeBiql5KOQsKVyrA0sAiA=" string is a result of the binary value of the hash, encoded. Meanwhile, the "NzExMGVkYTRkMDllMDYyYWE1ZTRhMzkwYjBhNTcyYWMwZDJjMDIyMA==" string is the result of the Base64 transform on the hexadecimal presentation of the hash.
Did that make sense? So you have a SHA1 hash, an array of 20 bytes: {0x71, 0x10, ...}. You can Base64-encode that chunk of memory as it is. Or you can convert each byte into two lowercase hex digits, then you'll get the ASCII string "7110eda4d09e062aa5e4a390b0a572ac0d2c0220". If you apply Base64 encoding to that string, as opposed to the original hash bytes, you'll get the Base64 value "NzExMGV...".
EDIT, with extra binary goodness: reformulate the second snippet thus:
unsigned char result[CC_SHA1_DIGEST_LENGTH];
const char *cStr = [self._txtFieldPW.text UTF8String];
CC_SHA1(cStr, strlen(cStr), result); //Now result contains the hash
//Wrap the result in a NSData object
NSData *pwHashData = [[NSData alloc] initWithBytes:result length: sizeof result];
//And take Base64 of that
NSString *base64 = [pwHashData base64Encoding];
NSLog(#"Base64: %#",base64);
And get rid of the sha1 method. Once you remove the monstrous stringWithFormat call, it's a two-liner. If you really want the hex hash in the log, be my guest; but don't treat the hex string as the true value of the hash, 'cause it's not.
Unless you're using ARC, don't forget to free the NSData object afterwards.

iOS Development: How can I encapsulate a string in an NSData object?

I'm building a multiplayer game on the iPhone and I need to send string data to the other players in the game. To do that, I need to encapsulate my NSString* string data in an NSData object somehow. Here's an example of how my code is structured...
typedef struct
{
PACKETTYPE packetType;
??? stringToSend; //<---not sure how to store this
} StringPacket;
StringPacket msg;
msg.packetType = STRING_PACKET;
msg.stringToSend = ... // <---not sure what to do here
NSData *packet = [NSData dataWithBytes:&msg length:sizeof(StringPacket)];
So my question is, if StringPacket is a struct defined in my header, what type should the stringToSend property be so that I can easily call the dataWithBytes method of NSData to encapsulate the packet data in an NSData object?
Thanks for your wisdom!
At first, you should convert your NSString to UTF8 representation via [NSString UTF8String].
After that, i'd recommend to store in packet string length, and after that - the string characters themself. All that can be done via appending NSData, created from char* via [NSData dataWithBytes:]
NSMutableData packet = [[NSMutableData alloc] init];
[packet appendBytes:&msg.packetType, sizeof(msg.packetType)];
char *str = [yourString UTF8String];
int len = strlen(str);
[packet appendBytes:(void*)&len, sizeof(len)];
[packet appendBytes:(void*)str, len];
To parse packet back, you should do:
NSData packet; // your packet
[packet getBytes:(void*)&packet.msg range:NSMakeRange(0, sizeof(packet.msg))];
int len;
[packet getBytes:(void*)&len range:NSMakeRange(sizeof(packet.msg), sizeof(len)];
NSData *strData = [packet subdataWithRange:NSMakeRange(sizeof(packet.msg) + sizeof(len)), packet.length];
NSString *str = [[NSString alloc] initWithData:strData encoding:UTF8Encoding];
There can be some mistakes since i'm writing from memory, but I think you'll get the idea.
If your strings have a maximum length, it's rather easy and can be done efficiently. So, assuming your strings max length for these packets is 255 and you've decided to use UTF-8 to encode your strings (both sides need to agree which encoding they're using), you could do it like this:
typedef struct
{
PACKETTYPE packetType;
uint8_t stringToSend[256]; // UTF8 string with max encoded length of 255 bytes
} StringPacket;
StringPacket msg;
msg.packetType = STRING_PACKET;
[theString getCString:msg.stringToSend maxLength:256 encoding:NSUTF8StringEncoding];
NSData *packet = [NSData dataWithBytes:&msg length:sizeof(StringPacket)];
Now you will have a proper C string in your packet that is at most 255 bytes of string data and the null terminator. Note, if your string can't be encoded to UTF8 in the size you gave it, the method will return NO, so your real code should actually check for that and handle it.
If you can't have a size limit, you can basically do the same thing, but you have to deal with dynamically allocating the memory, copying the bytes, creating the data and properly freeing the memory at the right time, so it becomes much more involved but it's the same basic idea. See also the method -getBytes:maxLength:usedLength:encoding:options:range:remainingRange: on NSString, it can be very useful in generating these messages where the string size is dynamic and totally unknown.
For the most simple case, however, the code above should get the job done.