Convert Hex NSData to int in Objective C - ios

Our custom Smart Router is giving me NSData response
<800c01ff 0001ffff ffff29ff>
Here, 800c is my deviceId. How to convert it to int ?
deviceId =32780;
When I send command to router I constructed it like,
Byte mqttData[12];
mqttData[0] =[[NSNumber numberWithUnsignedChar:(deviceID >> 8) & 0xFF] intValue];
//mqttData[0]=128 or 80 in Hex
mqttData[1] =[[NSNumber numberWithUnsignedChar:deviceID & 0xFF] intValue];
//mqttData[1]=12 or 'C' in Hex
return [NSData dataWithBytes:mqttData length:sizeof(mqttData)];

int deviceId = CFSwapInt16BigToHost(*(int*)([deviceIDData bytes]))
Answer taken from Larme's comment.

Related

How to put unicode char into NSString

For example I could type an emoji character code such as:
NSString* str = #"😊";
NSLog(#"%#", str);
The smile emoji would be seen in the console.
Maybe the code editor and the compiler would trade the literal in UTF-8.
And now I'm working in a full unicode, I mean 32bit per char, environment and I've got the unicode of the emoji, I want to convert the 32bit unicode into a NSString for example:
int charcode = 0x0001F60A;
NSLog(#"%??", charcode);
The question is what should I put at the "??" position and then I could format the charcode into a emoji string?
BTW the charcode was a variable which can not be determine at the compile time.
I don't want to compress the 32bit int into UTF-8 bytes unless that would be the only way.
If 0x0001F60A is a dynamic value determined at runtime then
you can use the NSString method
- (instancetype)initWithBytes:(const void *)bytes length:(NSUInteger)len encoding:(NSStringEncoding)encoding;
to create a string containing a character with the given Unicode value:
int charcode = 0x0001F60A;
uint32_t data = OSSwapHostToLittleInt32(charcode); // Convert to little-endian
NSString *str = [[NSString alloc] initWithBytes:&data length:4 encoding:NSUTF32LittleEndianStringEncoding];
NSLog(#"%#", str); // 😊
Use NSString initialization method
int charcode = 0x0001F60A;
NSLog(#"%#", [[NSString alloc] initWithBytes:&charcode length:4 encoding:NSUTF32LittleEndianStringEncoding]);

Convert NSData to a NSString returns random characters

I am working on a bluetooth iOS project and have managed to get some data from the bluetooth device.
However, I am struggling to convert this data into something useful, such as an NSString. Whenever I try to NSLog the NSString that was converted from the NSData received, it is a bunch of gibberish. The output is:
ēဥ၆䄀
The bluetooth device is a heart monitor from a manufacturer in Asia and they have provided the protocol reference on how to make calls to the device. This one thing they mention in the protocol reference:
The PC send 16-byte packets to the device, then the device sent back the 16-byte packets. Except for some special commands, all others can use this communication mode.
Can anyone tell me what I am doing wrong? I have tried everything I know, including every single encoding in the apple docs as well as both initWithData and initWithBytes. Thanks!
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
error:(NSError *)error {
if (error)
{
NSLog(#"erorr in read is %#", error.description);
return;
}
NSData *data= characteristic.value;
NSString *myString = [[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF16StringEncoding];
NSLog(#"Value from device is %#", myString); //OUTPUT IS ēဥ၆䄀
}
What you have here is a string of raw data that can't be directly converted into a human readable string - unless you consider hex-representation to be human readable :)
To make sense of this data you need to either have a protocol specification at hand or prepare for hours (sometimes) days of reverse-engineering.
This byte-sequence can be composed of multiple values formatted in standard (float IEEE 754, uint8_t, uint16_t...) or even proprietary formats.
One important thing to consider when communicating with the outside world is also endianness (ie: does the 'biggest' byte in multi-byte format come first or last).
There are many ways to manipulate this data. To get the raw array of bytes you could do:
NSData *rxData = ...
uint8_t *bytes = (uint8_t *)[rxData bytes];
And then if (for example) first byte tells you what type of payload the string holds you can switch like:
switch (bytes[0])
{
case 0x00:
//first byte 0x00: do the parsing
break;
case 0x01:
//first byte 0x01: do the parsing
break;
// ...
default:
break;
}
Here would be an example of parsing data that consists of:
byte 0: byte holding some bit-coded flags
bytes 1,2,3,4: 32-bit float
bytes 5,6: uint16_t
bool bitFlag0;
bool bitFlag1;
bool bitFlag2;
bool bitFlag3;
uint8_t firstByte;
float theFloat;
uint16_t theInteger;
NSData *rxData = ...
uint8_t *bytes = (uint8_t *)[rxData bytes];
// getting the flags
firstByte = bytes[0];
bitFlag0 = firstByte & 0x01;
bitFlag1 = firstByte & 0x02;
bitFlag2 = firstByte & 0x04;
bitFlag3 = firstByte & 0x08;
//getting the float
[[rxData subdataWithRange:NSMakeRange(1, 4)] getBytes:&theFloat length:sizeof(float)];
NSLog (#"the float is &.2f",theFloat);
//getting the unsigned integer
[[data subdataWithRange:NSMakeRange(6, 2)] getBytes:&theInteger length:sizeof(uint16_t)];
NSLog (#"the integer is %u",theInteger);
One note: depending on the endianness you might need to reverse the 4-float or the 2-uint16_t bytes before converting them. Converting this byte arrays can also be done with unions.
union bytesToFloat
{
uint8_t b[4];
float f;
};
and then:
bytesToFloat conv;
//float would be written on bytes b1b2b3b4 in protocol
conv.b[0] = bytes[1]; //or bytes[4] .. endianness!
conv.b[1] = bytes[2]; //or bytes[3] .. endianness!
conv.b[2] = bytes[3]; //or bytes[2] .. endianness!
conv.b[3] = bytes[4]; //or bytes[1] .. endianness!
theFloat = conv.f,
If for example you know that byte6 and byte7 represent an uint16_t value you can calculate it from raw bytes:
value = uint16_t((bytes[6]<<8)+bytes[7]);
or (again - endianness):
value = uint16_t((bytes[7]<<8)+bytes[6]);
One more note: using simply sizeof(float) is a bit risky since float can be 32-bit on one platform and 64-bit on another.

Convert Unsigned Int to Hexadecimal value

How can I convert a integer 6 digit number such as "1234674" to a hexadecimal 4 byte NSData in Objective-C ?
This is the part of our code that sends passkey:
#define HSL_PRIVATE_SERVICE_UUID 0xFF20
#define HSL_PRIVATE_NEW_PASSKEY_UUID 0xFF35
unsigned int newPassKey = [_confirmNewPassKey.text intValue];
NSLog(#"newPasskey %d", newPassKey);
NSData *d = [NSData dataWithBytes:&newPassKey length:sizeof(unsigned int)];
[_t writeValue:HSL_PRIVATE_SERVICE_UUID characteristicUUID:HSL_PRIVATE_NEW_PASSKEY_UUID p:_peripheral data:d];
I did an air capture comparing BTOOL versus iPhone passkey writes.
BTOOL (A simulator tool) wrote (the correct result) :
0x40e201
iPhone wrote(wrong data):
0x0001e240
Not sure what is going on and how to fix it in the app so that the result matches what the Bluetooth device is expecting . I would like the result to be same as BTOOL one.
Try this:
uint32_t value = [_confirmNewPassKey.text intValue];
uint32_t swapped = CFSwapInt32HostToBig(value);
NSData *d = [NSData dataWithBytes:&swapped length:sizeof(swapped)];
This assumes you want big endian for the output.

Converting NSString to unichar in iOS

I have seen questions in stackoverflow that convert unichar to NSString but now I would like to do the reverse.
How do i do it?
Need some guidance.. Thanks
For example, I have an array of strings:[#"o",#"p",#"q"];
These are strings inside. How do i convert it back to unichar?
The following will work as long as the first character isn't actually two composed characters (in other words as long as the character doesn't have a Unicode value greater than \UFFFF):
unichar ch = [someString characterAtIndex:0];
You could convert it to a buffer in NSData:
if ([string canBeConvertedToEncoding:NSUnicodeStringEncoding]) {
NSData * data = [string dataUsingEncoding:NSUnicodeStringEncoding];
const unichar* const ptr = (const unichar*)data.bytes;
...
}

Convert XML Dsig format to DER ASN.1 public key

I am working on an iPhone app that retrieves an RSA public key from an ASP.NET web service in the form:
<RSAKeyValue>
<Modulus>qdd0paiiBJ+xYaN4TKDdbEzrJJw9xlbRAltb5OPdegjLoW60yOjL/sni52WVsGC9QxpNitZR33dnUscmI0cTJoxkXypPjbD94UpH+p4el2tuKBypHlE7bERApuUp55y8BiRkbQNFH8smZFWDwtIc/PsJryeGf8fAryel8c5V3PU=</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
I need to then convert this response into an NSData * of the appropriate format (from some intense Googling, most likely 'ASN.1 DER' binary format. I've got code in place to convert both parts from their Base64 representations to the original binary values, but I can't for the life of me figure out a reasonable way to create the one-piece binary key.
The code waiting for the key is the -addPeerPublicKey:(NSString *) keyBits:(NSData *) method of the SecKeyWrapper class from Apple's CryptoExercise example project (Code here).
I would be more than happy to implement this another way--all I need is to encrypt a single string (no decryption required). As far as I can tell, though, the built-in Security framework has what I need, if I could just close this format gap. If there is a way to convert the key and send it Base64-encoded from the webservice, that works for me as well--but I couldn't find any way to ASN.1-encode it there, either.
So, I used the SecKeyWrapper class to generate a random key, then used the -getPublicKeyBits method to get the binary representation of the public key (in whatever format is used internally). Presuming it is some form of DER ASN.1, I NSLog'd it to the console as hex and loaded it into this program. Sure enough, the internal representation is DER ASN.1, but it is a very simplified version of what I normally found for RSA key representations:
![SEQUENCE { INTEGER, INTEGER }][2]
Shouldn't be too tough to construct on the fly from a binary rep. of the modulus and exponent, since the DER encoding is just
30 (for SEQUENCE) LL (total sequence byte length)
02 (INTEGER) LL (modulus byte length) XX XX... (modulus data bytes)
02 LL XX XX XX... (exponent length and bytes)
Here's my code, for simplicity. It uses a few Google libs for XML+base64, just heads up; also Apple's demo code SecKeyWrapper. See my other question for a note on making this work. Also, note that it is not ARC-compatible; this is left as an exercise for the reader (I wrote this years ago, now).
#define kTempPublicKey #"tempPayKey"
-(NSData *)encryptedDataWithXMLPublicKey:(NSString *)base64PublicKey data:(NSData *)data {
if(![data length]){
#throw [NSException exceptionWithName:#"NSInvalidArgumentException" reason:#"Data not set." userInfo:nil];
}
GTMStringEncoding *base64 = [GTMStringEncoding rfc4648Base64StringEncoding];
NSData *keyData = [base64 decode:base64PublicKey];
NSError *err = nil;
GDataXMLDocument *keyDoc = [[GDataXMLDocument alloc] initWithData:keyData options:0 error:&err];
if(err){
NSLog(#"Public key parse error: %#",err);
[keyDoc release];
return nil;
}
NSString *mod64 = [[[[keyDoc rootElement] elementsForName:#"Modulus"] lastObject] stringValue];
NSString *exp64 = [[[[keyDoc rootElement] elementsForName:#"Exponent"] lastObject] stringValue];
[keyDoc release];
if(![mod64 length] || ![exp64 length]){
#throw [NSException exceptionWithName:#"NSInvalidArgumentException" reason:#"Malformed public key xml." userInfo:nil];
}
NSData *modBits = [base64 decode:mod64];
NSData *expBits = [base64 decode:exp64];
/* the following is my (bmosher) hack to hand-encode the mod and exp
* into full DER encoding format, using the following as a guide:
* http://luca.ntop.org/Teaching/Appunti/asn1.html
* this is due to the unfortunate fact that the underlying API will
* only accept this format (not the separate values)
*/
// 6 extra bytes for tags and lengths
NSMutableData *fullKey = [[NSMutableData alloc] initWithLength:6+[modBits length]+[expBits length]];
unsigned char *fullKeyBytes = [fullKey mutableBytes];
unsigned int bytep = 0; // current byte pointer
fullKeyBytes[bytep++] = 0x30;
if(4+[modBits length]+[expBits length] >= 128){
fullKeyBytes[bytep++] = 0x81;
[fullKey increaseLengthBy:1];
}
unsigned int seqLenLoc = bytep;
fullKeyBytes[bytep++] = 4+[modBits length]+[expBits length];
fullKeyBytes[bytep++] = 0x02;
if([modBits length] >= 128){
fullKeyBytes[bytep++] = 0x81;
[fullKey increaseLengthBy:1];
fullKeyBytes[seqLenLoc]++;
}
fullKeyBytes[bytep++] = [modBits length];
[modBits getBytes:&fullKeyBytes[bytep]];
bytep += [modBits length];
fullKeyBytes[bytep++] = 0x02;
fullKeyBytes[bytep++] = [expBits length];
[expBits getBytes:&fullKeyBytes[bytep++]];
SecKeyRef publicKey = [[SecKeyWrapper sharedWrapper] addPeerPublicKey:kTempPublicKey keyBits:fullKey];
[fullKey release];
NSData *encrypted = [[SecKeyWrapper sharedWrapper] wrapSymmetricKey:data keyRef:publicKey];
// remove temporary key from keystore
[[SecKeyWrapper sharedWrapper] removePeerPublicKey:kTempPublicKey];
return encrypted;
}

Resources