How to read binary data stored in NSData - ios

I am getting data from a web call. Here is data.
00000001 00045043 4c4e0000 00023744 92f4cd44 92f4cd44 92f4cd44 92f4cd3c a3d70a00 00014de2 b767a044 93800044 93800044 93800044 93800040 a0000000 00014de2 bdd04044 94400044 94400044 93db3344 94170a3f a6666600 00014de2 c8ccc044 93ddc344 93ddc344 93ddc344 93ddc33e 99999a00 00014de2 ce4b0044 93bd1f44 943d7144 9394cd44 93eccd41 e8e14800 00014de2 d01fc044 93eb3344 93eb3344 93b00044 93b00040 c0000000
The data format is fixed (We know where it stores int / float etc.
Question is how do I read and store it in individual variables
For example the first 4 bytes here are specifying the number of symbols returned (1)

NSMutableString *stringHexForm = [NSMutableString string];
for(int i = startLocation ; i < (startLocation + nCharsToReadIn) ; i++)
{
unsigned char byte;
[dataIn getBytes : &byte range : NSMakeRange(i, 1)];
NSString *tempStr=[NSString stringWithFormat:#"%02x",byte];
[stringHexForm appendString:[NSString stringWithFormat:#"%#",tempStr]];
}
unsigned result = 0;
NSScanner *scanner = [NSScanner stringHexForm];
[scanner scanHexInt:&result];
return result;

NSData has the method func getBytes(buffer: UnsafeMutablePointer<Void>, range: NSRange) that should help you. You can grab each thing in your struct by specifying the range.
So you can do:
var length: Int = 0
myData.getBytes(&length, range: NSMakeRange(0, 4))
and so on for each type, range that you need

Related

Generating SHA256 in iOS

I tried to generate SHA256 in iOS using Arcane library with following data:
String: Amount=50&BillerID=59&ChannelID=2&Context=34|check|test&ReturnURL=https://uat.myfatoora.com/ReceiptPOC.aspx&TxnRefNum=000000000020003&UserName=DCS
Key: 71DD0F73AFFBB47825FF9864DDE95F3B
Result was 409dc622b3bef5c9fc46e45c3210111fcb4536d3a55833316fe0dc8154b3ea34
which I thought to be correct. However, the Windows counterpart is generating SHA256 using following code:
Windows Phone Source Code:
public static string HmacSha256(string secretKey, string value)
{
var msg = CryptographicBuffer.ConvertStringToBinary(value, BinaryStringEncoding.Utf8);
byte[] convertedHash = new byte[secretKey.Length / 2];
for (int i = 0; i < secretKey.Length / 2; i++)
{
convertedHash[i] = (byte)Int32.Parse(secretKey.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
}
// Create HMAC.
var objMacProv = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256);
CryptographicHash hash = objMacProv.CreateHash(convertedHash.AsBuffer());
hash.Append(msg);
return CryptographicBuffer.EncodeToHexString(hash.GetValueAndReset());
}
and the result is: 94a20ca39c8487c7763823ec9c918d9e38ae83cb741439f6d129bcdef9edba73 which is different from what I got. Can somebody help me with this and let me know what the above code is doing and how can I replicate it in iOS.
Edit:
iOS Source code
let key = self.md5(string: "71DD0F73AFFBB47825FF9864DDE95F3B")
let hash = HMAC.SHA256(str, key: key)
The key here is you need to convert your secret, which is a hex string, into NSData. In other words, NSData byte stream would "look" like the secret.
This should do what you want:
// Hex string to NSData conversion from here http://stackoverflow.com/questions/7317860/converting-hex-nsstring-to-nsdata
NSString *secret = #"71DD0F73AFFBB47825FF9864DDE95F3B";
NSData *dataIn = [#"Amount=50&BillerID=59&ChannelID=2&Context=34|check|test&ReturnURL=https://uat.myfatoora.com/ReceiptPOC.aspx&TxnRefNum=000000000020003&UserName=DCS" dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *macOut = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
secret = [secret stringByReplacingOccurrencesOfString:#" " withString:#""];
NSMutableData *secretData = [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
int i;
for (i=0; i < [secret length]/2; i++) {
byte_chars[0] = [secret characterAtIndex:i*2];
byte_chars[1] = [secret characterAtIndex:i*2+1];
whole_byte = strtol(byte_chars, NULL, 16);
[secretData appendBytes:&whole_byte length:1];
}
CCHmac(kCCHmacAlgSHA256, secretData.bytes, secretData.length, dataIn.bytes, dataIn.length, macOut.mutableBytes);
NSMutableString *stringOut = [NSMutableString stringWithCapacity:macOut.length];
const unsigned char *macOutBytes = macOut.bytes;
for (NSInteger i=0; i<macOut.length; ++i) {
[stringOut appendFormat:#"%02x", macOutBytes[i]];
}
NSLog(#"dataIn: %#", dataIn);
NSLog(#"macOut: %#", macOut);
NSLog(#"stringOut: %#", stringOut);
Output:
2016-09-27 20:18:54.181 JKS[27562:5321334] dataIn: <416d6f75 6e743d35 30264269 6c6c6572 49443d35 39264368 616e6e65 6c49443d 3226436f 6e746578 743d3334 7c636865 636b7c74 65737426 52657475 726e5552 4c3d6874 7470733a 2f2f7561 742e6d79 6661746f 6f72612e 636f6d2f 52656365 69707450 4f432e61 73707826 54786e52 65664e75 6d3d3030 30303030 30303030 32303030 33265573 65724e61 6d653d44 4353>
2016-09-27 20:18:54.181 JKS[27562:5321334] macOut: <94a20ca3 9c8487c7 763823ec 9c918d9e 38ae83cb 741439f6 d129bcde f9edba73>
2016-09-27 20:18:54.181 JKS[27562:5321334] stringOut: 94a20ca39c8487c7763823ec9c918d9e38ae83cb741439f6d129bcdef9edba73
Updated with Swift (code should be cleaned up)
// http://stackoverflow.com/questions/29799361/generate-a-hmac-swift-sdk8-3-using-cchmac
func generateHMAC(key: String, data: String) -> String {
let keyData = key.dataFromHexadecimalString()! as NSData
let dataIn = data.data(using: .utf8)! as NSData
var result: [CUnsignedChar]
result = Array(repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), keyData.bytes, keyData.length, dataIn.bytes, dataIn.length, &result)
let hash = NSMutableString()
for val in result {
hash.appendFormat("%02hhx", val)
}
return hash as String
}
You can use this extension to convert the hex string to Data
// Modified slightly http://stackoverflow.com/questions/26501276/converting-hex-string-to-nsdata-in-swift
extension String {
func dataFromHexadecimalString() -> Data? {
var data = Data(capacity: characters.count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
regex.enumerateMatches(in: self, options: [], range: NSMakeRange(0, characters.count)) { match, flags, stop in
let byteString = (self as NSString).substring(with: match!.range)
var num = UInt8(byteString, radix: 16)
data.append(&num!, count: 1)
}
return data
}
}
And to use do something like:
let secret = "71DD0F73AFFBB47825FF9864DDE95F3B"
let value = "Amount=50&BillerID=59&ChannelID=2&Context=34|check|test&ReturnURL=https://uat.myfatoora.com/ReceiptPOC.aspx&TxnRefNum=000000000020003&UserName=DCS"
print("\(generateHMAC(key: secret, data: value))")
Your output should be 94a20ca39c8487c7763823ec9c918d9e38ae83cb741439f6d129bcdef9edba73
You will need #import <CommonCrypto/CommonCrypto.h> in your bridging header.
The Windows code takes the string, interprets it as a hexadecimal number, and converts two characters a time into one byte.
Your Mac code most like takes the string as it is. Since the key starts with "71", your windows code takes that as a single byte with value 0x71 = 129, your Mac code takes it as two bytes with values '7' = 55 and '1' = 49.
All you need to do is convert the bytes on the Mac exactly as you do it on Windows. You might have to do the unthinkable and look at the source code of the Mac library to see how it does the actual hash calculation.
#import <CommonCrypto/CommonHMAC.h>
+ (NSString *)hmacSHA256EncryptString{
NSString * parameterSecret = #"input secret key";
NSString *plainString = #"input encrypt content string";
const char *secretKey = [parameterSecret cStringUsingEncoding:NSUTF8StringEncoding];
const char *plainData = [plainString cStringUsingEncoding:NSUTF8StringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, secretKey, strlen(secretKey), plainData, strlen(plainData), cHMAC);
NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
const unsigned char *bufferChar = (const unsigned char *)[HMACData bytes];
NSMutableString *hmacString = [NSMutableString stringWithCapacity:HMACData.length * 2];
for (int i = 0; i < HMACData.length; ++i){
[hmacString appendFormat:#"%02x", bufferChar[i]];
}
return hmacString;
}

byteArray to Hex NSString - adds some wrong hex content

I am trying to convert the byteArray to a Hex NSString.
Here is the solution that I referred to convert it into hex NSString. But, I discovered It add's ffffffffffffff. How can I get correct hex NSString?
Best way to serialize an NSData into a hexadeximal string
const char myByteArray[] = {
0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89,
0x12,0x23,0x34,0x45,
0x56,0x67,0x78,0x89 };
NSData *myByteData=[NSData dataWithBytes:myByteArray length:sizeof(myByteArray)];
NSMutableString *myHexString= [NSMutableString stringWithCapacity:myByteData.length*2];
for(int i=0;i<myByteData.length;i++){
;
NSString *resultString =[NSString stringWithFormat:#"%02lx",(unsigned long)myByteArray[i]];
[myHexString appendString:resultString];
}
The output String
12233445566778ffffffffffffff8912233445566778ffffffffffffff89
Don't use unsigned long for each of your bytes. And what's the point of myByteData if you don't use it?
And since you are not really using char, use uint8_t.
Try this:
const uint8_t myByteArray[] = {
0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89,
0x12,0x23,0x34,0x45,
0x56,0x67,0x78,0x89 };
size_t len = sizeof(myByteArray) / sizeof(uint8_t);
NSMutableString *myHexString = [NSMutableString stringWithCapacity:len * 2];
for (size_t i = 0; i < len; i++) {
[myHexString appendFormat:#"%02x", (int)myByteArray[i]];
}
Your initial byte data is char rather than unsigned char. This means that any values >127 (0x7f) will be seen as a twos-complement negative number, giving ffffffffffffff89.
If you change your data to be unsigned char you will get the desired result.
const unsigned char myByteArray[] = {
0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89,
0x12,0x23,0x34,0x45,
0x56,0x67,0x78,0x89 };
NSData *myByteData=[NSData dataWithBytes:myByteArray length:sizeof(myByteArray)];
NSMutableString *myHexString= [NSMutableString stringWithCapacity:myByteData.length*2];
for(int i=0;i<myByteData.length;i++){
NSString *resultString =[NSString stringWithFormat:#"%02lx",(unsigned long)myByteArray[i]];
[myHexString appendString:resultString];
}

Chinese character to ASCII or Hexadecimal

Im struggling to covert chinese word/characters to ascii or hexadecimal and all the values I've got up until now is not what I was suppose to get.
Example of conversion is the word 手 to hex is 1534b.
Methods Ive followed till now are as below, and I got varieties of results but the one I was looking for,
I really appreciate if you can help me out on this issue,
Thanks,
Mike
- (NSString *) stringToHex:(NSString *)str{
NSUInteger len = [str length];
unichar *chars = malloc(len * sizeof(unichar));
[str getCharacters:chars];
NSMutableString *hexString = [[NSMutableString alloc] init];
for(NSUInteger i = 0; i < len; i++ )
{
[hexString appendFormat:#"%02x", chars[i]]; //EDITED PER COMMENT BELOW
}
free(chars);
return hexString;}
and
const char *cString = [#"手" cStringUsingEncoding:NSASCIIStringEncoding];
below is the similar code in Java for Android, Maybe it helps
public boolean sendText(INotifiableManager manager, String text) {
final int codeOffset = 0xf100;
for (char c : text.toCharArray()) {
int code = (int)c+codeOffset;
if (! mConnection.getBoolean(manager, "SendKey", Integer.toString(code))) {
}
Your Java code is just doing this:
Take each 16-bit character of the string and add 0xf100 to it.
If you do the same thing in your above Objective-C code you will get the result you want.

unichar* to NSString, get the length

I am trying to create an NSString object from a const unichar buffer where I don't know the length of the buffer.
I want to use the NSString stringWithCharacters: length: method to create the string (this seems to work), but please can you help me find out the length?
I have:
const unichar *c_emAdd = [... returns successfully from a C++ function...]
NSString *emAdd = [NSString stringWithCharacters:c_emAdd length = unicharLen];
Can anyone help me find out how to check what unicharLen is? I don't get this length passed back to me by the call to the C++ function, so I presume I'd need to iterate until I find a terminating character? Anyone have a code snippet to help? Thanks!
Is your char buffer null terminated?
Is it 16-bit unicode?
NSString *emAdd = [NSString stringWithFormat:#"%S", c_emAdd];
Your unichars should be null terminated so you when you reach two null bytes (a unichar = 0x0000) in the pointer you will know the length.
unsigned long long unistrlen(unichar *chars)
{
unsigned long long length = 0llu;
if(NULL == chars) return length;
while(NULL != chars[length])
length++;
return length;
}
//...
//Inside Some method or function
unichar chars[] = { 0x005A, 0x0065, 0x0062, 0x0072, 0x0061, 0x0000 };
NSString *string = [NSString stringWithCharacters:chars length:unistrlen(chars)];
NSLog(#"%#", string);
Or even simpler format with %S specifier

How to count words within a text string?

On iOS, how can I count words within a specific text string?
A more efficient method than splitting is to check the string character by character.
int word_count(NSString* s) {
CFCharacterSetRef alpha = CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric);
CFStringInlineBuffer buf;
CFIndex len = CFStringGetLength((CFStringRef)s);
CFStringInitInlineBuffer((CFStringRef)s, &buf, CFRangeMake(0, len));
UniChar c;
CFIndex i = 0;
int word_count = 0;
Boolean was_alpha = false, is_alpha;
while (c = CFStringGetCharacterFromInlineBuffer(&buf, i++)) {
is_alpha = CFCharacterSetIsCharacterMember(alpha, c);
if (!is_alpha && was_alpha)
++ word_count;
was_alpha = is_alpha;
}
if (is_alpha)
++ word_count;
return word_count;
}
Compared with #ennuikiller's solution, counting a 1,000,000-word string takes:
0.19 seconds to build the string
0.39 seconds to build the string + counting using my method.
1.34 seconds to build the string + counting using ennuikiller's method.
The big disadvantage of my method is that it's not a one-liner.
[[stringToCOunt componentsSeparatedByCharactersInSet: [NSCharacterSet whitespaceCharacterSet] count]
I think this method is better:
__block int wordCount = 0;
NSRange range = {0,self.text.length };
[self.text enumerateSubstringsInRange:range options:NSStringEnumerationByWords usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
wordCount++;
}];
As a reference check the video of the session 215 of the WWDC 2012: Text and Linguistic Analysis by Douglas Davidson
One liner accurate solution:
return [[self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"length > 0"]].count;
This solution handles consecutive spaces correctly.

Resources