Flutter how to convert NSData* to Byte* in objc - objective-c

I am trying to use c++ api with objc native code in flutter.
https://docs.flutter.dev/development/platform-integration/platform-channels?tab=type-mappings-obj-c-tab
flutter documentation says Uint8List should be stored as FlutterStandardTypedData typedDataWithBytes: in objc do
send argument in flutter
var data = <String, Uint8List>{
"key": byte, //data type is Uint8List
"value": byteBuffer, //data type is Uint8List
};
Uint8List? byteRes;
byteRes = await platform.invokeMethod('SeedDecrypt', data);
get argument in objc (AppDelegate.m)
NSData* key = call.arguments[#"key"];
NSData* value = call.arguments[#"value"];
NSUInteger keyLength = [key length];
NSUInteger valueLength = [value length];
Byte* byteKey = (Byte*)malloc(keyLength);
Byte* byteValue = (Byte*)malloc(valueLength);
memcpy(byteKey, [key bytes], keyLength);
memcpy(byteValue, [value bytes], byteLength);
DWORD roundKey[32];
//Call C++ API
//prototype : void SeedKey(DWORD* roundKey, BYTE* byteKey);
SeedKey(roundKey, byteKey);
//protoType : void Decrypt(BYTE* byteValue, DWORD* roundKey);
Decrypt(byteValue, roundKey);
NSData* res = [NSData dataWithBytes: byteValue length: sizeof(byteValue)];
result(res);
Store the argument as NSData* and copy the memory to a Byte* variable. After executing the C API, it is converted to NSData type. The problem is that when I run it, the device shuts down. I wrote this source referring to the article below. Do you know what my mistake is?
How to convert NSData to byte array in iPhone?
thanks.

Solved
NSNumber* keyLength = call.arguments[#"keyLen"];
NSNumber* valueLength = call.arguments[#"valueLen"];
NSUInteger keyLen = [keyLength integerValue];
NSUInteger valueLen = [valueLength integerValue];
FlutterStandardTypedData* key = call.arguments[#"key"];
FlutterStandardTypedData* value = call.arguments[#"value"];
Byte* byteKey = (Byte*)malloc(keyLen);
Byte* byteValye = (Byte*)malloc(valueLen);
memcpy(byteKey, [key.data bytes], keyLen);
memcpy(byteValue, [value.data bytes], valueLen);
DWORD roundKey[32];
//Call C++ API
NSData* res = [NSData dataWithBytes:keyValue length:keyLen];
FlutterStandardTypedData* rest = [FlutterStandardTypedData typedDataWithBytes: res];
free(byteKey);
free(byteValue);
result(rest);
See https://docs.flutter.dev/development/platform-integration/platform-channels?tab=type-mappings-obj-c-tab. After matching the data type, match the OBJC data type with the C data type and return the result.

Related

How can I read the "attributedBody" column in macOS' iMessage database?

Apple changed the Messages database schema in the latest macOS Ventura update, and sent messages seem to no longer store their body/content in the text column. The attributedBody column has the content, but it's stored as an encoded blob.
Has anyone had any luck getting plaintext out of this?
The attributedBody column is a serialized NSMutableAttributedString — packed using NSArchiver. It can be unpacked and read using NSUnarchiver but must first be extracted from the Messages sqlite database without losing any of its non-printable characters.
To preserve the column's content when performing a query, you can use sqlite3's HEX() function. The resulting bytes can then be read back into their original state by iterating over them and building a new NSString.
In the example below, NSData is extended with two helper methods to handle reading a file with hex-encoded data. Using dataWithContentsOfHexEncodedFile, a message record's attributedBody can be passed to NSUnarchiver, which will handle decoding the serialized NSAttributedString. This can then be converted to a normal NSString by accessing the string property.
#import <Foundation/Foundation.h>
#implementation NSData (NSDataExtended)
+ (NSData *)dataWithContentsOfHexEncodedString:(NSString *) string {
const char * chars = [string UTF8String];
int i = 0;
NSMutableData *data = [NSMutableData dataWithCapacity: string.length / 2];
char byteChars[3] = {'\0', '\0', '\0'};
unsigned long wholeByte;
while (i < string.length) {
byteChars[0] = chars[i++];
byteChars[1] = chars[i++];
wholeByte = strtoul(byteChars, NULL, 16);
[data appendBytes:&wholeByte length:1];
}
return data;
}
+ (NSData *)dataWithContentsOfHexEncodedFile:(NSString *) filePath {
return [self dataWithContentsOfHexEncodedString:[NSString
stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:nil]];
}
#end
int main(int argc, const char * argv[]) {
system([[[NSString alloc] initWithFormat:#"%s %s > %s",
"/usr/bin/sqlite3 ~/Library/Messages/chat.db",
"'SELECT HEX(attributedBody) FROM message ORDER BY ROWID DESC LIMIT 1'",
"/private/tmp/msgbody"] UTF8String]);
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
NSMutableAttributedString *msg = [[[NSUnarchiver alloc]
initForReadingWithData:[NSData dataWithContentsOfHexEncodedFile:#"/private/tmp/msgbody"]
] decodeTopLevelObjectAndReturnError:nil];
NSLog(#"%#", [msg string]);
return 0;
}

Objective C - Parse NSData

I have the following data inside an NSData object:
<00000000 6f2d840e 31504159 2e535953 2e444446 3031a51b 8801015f 2d02656e 9f110101 bf0c0cc5 0affff3f 00000003 ffff03>
I'm having issues parsing this data. This data contains information which is marked by tags
Tag 1 is from byte value 0x84 to 0xa5
Tag 2 is from byte value 0xa5 to 0x88
Tag 3 is from byte value 0x88 to 0x5f0x2d
Tag 4 is from byte value 0x5f0x2d to 0x9f0x11
How would I go about to get those values from the NSData object?
Regards,
EZFrag
Use -[NSData bytes] to get a pointer to the contents. Then use pointer arithmetic to iterate over the bytes until you find what you are looking for. Since you want to go byte by byte, you should probably cast the pointer returned by bytes to uint8_t*. Then, pointer[0] points to the first byte, pointer[1] to the second, and so on.
I managed a nice solution, deciding to actually use the graymatter
-(int)getIndexOfSubDataInData:(NSData*)haystack forData:(NSData*)needle{
int dataCounter = 0;
NSRange dataRange = NSMakeRange(dataCounter, [needle length]);
NSData* compareData = [haystack subdataWithRange:dataRange];
while (![compareData isEqualToData:needle]) {
dataCounter++;
dataRange = NSMakeRange(dataCounter, [needle length]);
compareData = [haystack subdataWithRange:dataRange];
}
return dataCounter;
}
-(NSData*)getSubDataInData:(NSData*)targetData fromTag:(NSData*)fromTag toTag:(NSData*)toTag{
int startIndex = [self getIndexOfSubDataInData:targetData forData:fromTag] + [fromTag length];
int endIndex = [self getIndexOfSubDataInData:targetData forData:toTag];
int dataLength = endIndex - startIndex;
NSRange dataRange = NSMakeRange(startIndex, dataLength);
return [targetData subdataWithRange:dataRange];
}
//here is how I use the code
NSData* langTagStart=[[NSData alloc] initWithBytes:"\x5F\x2D" length:2];
NSData* langTagEnd=[[NSData alloc] initWithBytes:"\x9F\x11" length:2];
NSData* languageData = [self getSubDataInData:[response bytes] fromTag:langTagStart toTag:langTagEnd];
Thanks for your suggestions.
Regards,
EZFrag

Need java equivalent SHA512 for Objective-C

as I'm only a beginner in this field this question may seem to be very trivial, but I beg your pardon. I've a Java code as follows:
String passwordSalt = "somesalt";
byte[] bsalt = base64ToByte(passwordSalt);
byte[] thePasswordToDigestAsBytes = ("somepassword").getBytes("UTF-8");
System.out.println("------------------------------"+passwordSalt);
MessageDigest digest = MessageDigest.getInstance("SHA-512");
digest.reset();
digest.update(bsalt);
byte[] input = digest.digest(thePasswordToDigestAsBytes);
System.out.println("------------------------------"+byteToBase64(input));
I want to achieve the same in Objective-C and I'm using the following code :
NSData *saltdata = [Base64 decode:#"some base64 encoded salt"];
NSString *passwordDgst;
passwordDgst = #"somepassword";
NSData *input = [passwordDgst dataUsingEncoding: NSUTF8StringEncoding];
unsigned char hash[CC_SHA512_DIGEST_LENGTH];
CC_SHA512_CTX context;
CC_SHA512_Init(&context);
CC_SHA512_Update(&context, [saltdata bytes], (CC_LONG)[saltdata length]);
CC_SHA512_Update(&context, [input bytes], (CC_LONG)[input length]);
CC_SHA512_Final(hash, &context);
input = [NSMutableData dataWithBytes:(const void *)hash length:sizeof(unsigned char)*CC_SHA512_DIGEST_LENGTH];
passwordDgst = [input encodeBase64WithNewlines:NO];
But this seems to generate a different hash than the Java Code? Why is that? Can anybody clarify me that? Thanks in advance :)

Converting NSData bytes to NSString

I am trying to create a 16 byte and later 32 byte initialization vector in objective-c (Mac OS). I took some code on how to create random bytes and modified it to 16 bytes, but I have some difficulty with this. The NSData dumps the hex, but an NSString dump gives nil, and a cstring NSLog gives the wrong number of characters (not reproduced the same in the dump here).
Here is my terminal output:
2012-01-07 14:29:07.705 Test3Test[4633:80f] iv hex <48ea262d efd8f5f5 f8021126 fd74c9fd>
2012-01-07 14:29:07.710 Test3Test[4633:80f] IV string: (null)
2012-01-07 14:29:07.711 Test3Test[4633:80f] IV char string t^Q¶�^��^A
Here is the main program:
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//NSString *iv_string = [NSString stringWithCString:iv encoding:NSUTF8StringEncoding];
testclass *obj = [testclass alloc];
NSData *iv_data = [obj createRandomNSData];
//[iv_string dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"iv hex %#",iv_data);
//NSString *iv_string = [[NSString alloc] initWithBytes:[iv_data bytes] length:16 encoding:NSUTF8StringE$
NSString *iv_string = [[NSString alloc] initWithData:iv_data encoding:NSUTF8StringEncoding];
NSLog(#"IV string: %#",iv_string);
NSLog(#"IV char string %.*s",[iv_data bytes]);
return 0;
]
(I left in the above some commented code that I tried and did not work also).
Below is my random number generater, taken from a stack overflow example:
#implementation testclass
-(NSData*)createRandomNSData
{
int twentyMb = 16;
NSMutableData* theData = [NSMutableData dataWithCapacity:twentyMb];
for( unsigned int i = 0 ; i < twentyMb/4 ; ++i )
{
u_int32_t randomBits = arc4random();
[theData appendBytes:(void*)&randomBits length:4];
}
NSData *data = [NSData dataWithData:theData];
[theData dealloc];
return data;
}
#end
I am really quite clueless as to what could be the problem here. If I have data as bytes, it should convert to a string or not necessarily? I have looked over the relevant examples here on stackoverflow, but none of them have worked in this situation.
Thanks,
Elijah
An arbitrary byte sequence may not be legal UTF8 encoding. As #Joachim Isaksson notes, there is seldom reason to convert to strings this way. If you need to store random data as a string, you should use an encoding scheme like Base64, serialize the NSData to a plist, or similar approach. You cannot simply use a cstring either, since NULL is legal inside of a random byte sequence, but is not legal inside of a cstring.
You do not need to build your own random byte creator on Mac or iOS. There's one built-in called SecRandomCopyBytes(). For example (from Properly encrypting with AES with CommonCrypto):
+ (NSData *)randomDataOfLength:(size_t)length {
NSMutableData *data = [NSMutableData dataWithLength:length];
int result = SecRandomCopyBytes(kSecRandomDefault,
length,
data.mutableBytes);
NSAssert(result == 0, #"Unable to generate random bytes: %d",
errno);
return data;
}
When converting NSData to NSString using an UTF8 encoding, you won't necessarily end up with the same number of bytes since not all binary values are valid encodings of characters. I'd say using a string for binary data is a recipe for problems.
What is the use of the string? NSData is exactly the datatype you want for storing binary data to begin with.

Objective-C: Decode Signed Request

How do I decode a signed request in Objective-C?
Basically, how do I translate this Ruby code to Objective-C or C?
# Facebook sends a signed_requests to authenticate certain requests.
# http://developers.facebook.com/docs/authentication/signed_request/
def decode_signed_request(signed_request)
encoded_signature, encoded_data = signed_request.split('.')
signature = base64_url_decode(encoded_signature)
expected_signature = OpenSSL::HMAC.digest('sha256', #secret, encoded_data)
if signature == expected_signature
JSON.parse base64_url_decode(encoded_data)
end
rescue Exception => e
puts $!, $#
end
def base64_url_decode(string)
"#{string}==".tr("-_", "+/").unpack("m")[0]
end
SSToolKit Base64 decode NSString looks helpful.
Do you want to verify the signature on the data or just "decode" it? If it's the latter, you can just ignore the signature:
NSString *signedData = ...;
NSString *base64EncodedData = [[signedData componentsSeparatedByString:#"."] objectAtIndex:1];
NSString *jsonString = [NSString stringWithBase64String:base64EncodedData];
id jsonObject = ...;
I leave using the Facebook SDK and choosing a suitable JSON framework (I recommend JSONKit) up to you.
Your comment indicates that you want to verify the HMAC included with the message. In that case:
unsigned int length = 0;
unsigned char *expectedHmac = HMAC(EVP_sha256(), [key bytes], [key length], [base64EncodedData UTF8String], [base64EncodedData length], NULL, &length);
NSData *expectedHmacData = [NSData dataWithBytes:expectedHmac length:length];
// compare expected hmac