How do I convert a series of 32 bits (representing 4 bytes) stored in an NSString, into an NSData object of 4 bytes in objective-c?
For example, how can I convert the following string:
NSString *bitSeries = #"00000000000000000000000111101100";
into NSData object with length precisely 4?
You can use strtoul() with base 2 to convert the string to an unsigned integer:
NSString *bitSeries = #"00000000000000000000000111101100";
uint32_t value = strtoul([bitSeries UTF8String], NULL, 2);
and then create an NSData object:
NSData *data = [NSData dataWithBytes:&value length:sizeof(value)];
NSLog(#"%#", data);
// Output: <ec010000>
Or, if you prefer big-endian byte order:
value = OSSwapHostToBigInt32(value);
NSData *data = [NSData dataWithBytes:&value length:sizeof(value)];
NSLog(#"%#", data);
// Output: <000001ec>
Related
I have a method like this
+ (NSData *)getPublicKeyFromDecimalX:(NSData *)xInput decimalY:(NSData *)yInput { ... }
I know how to generate it when I have hexX: (NSData*) like this...
UInt8 iBytes[] = {0x04};
NSMutableData *allData = [[NSMutableData alloc] init];
[allData appendBytes:iBytes length:sizeof(iBytes)];
[allData appendData:xInput];
[allData appendData:yInput];
NSMutableDictionary *publicKeyOptions = [[NSMutableDictionary alloc]init];
[publicKeyOptions setValue:(__bridge id) kSecAttrKeyTypeECSECPrimeRandom forKey:(__bridge id)kSecAttrKeyType];
[publicKeyOptions setValue:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id)kSecAttrKeyClass];
[publicKeyOptions setValue:[NSNumber numberWithInt:256] forKey:(__bridge id)kSecAttrKeySizeInBits];
[publicKeyOptions setValue:[NSNumber numberWithBool:NO] forKey:(__bridge id)kSecAttrIsPermanent];
SecKeyRef publicKeyRef = SecKeyCreateWithData((__bridge CFDataRef)allData, (__bridge CFDictionaryRef)publicKeyOptions, nil);
BUT I'm struggling to convert decimal NSData into hexadecimal NSData.
I'm struggling to convert decimal NSData into hexadecimal NSData.
A NSData, itself, is neither decimal or hexadecimal. It is just a series of bytes of data.
Consider
UInt8 bytes[] = {0x2a, 0xff};
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
NSLog(#"%#", data); // {length = 2, bytes = 0x2aff}
That is an NSData with 0x2a followed by 0xff.
If you declare bytes in decimal, the NSData is identical:
UInt8 bytes[] = {42, 255};
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
NSLog(#"%#", data); // also {length = 2, bytes = 0x2aff}
Where it gets interesting is the number being represented in the NSData is not a series of bytes (i.e. not just a series of 8-bit integers), but a numeric value larger than one byte (e.g. 16-bits, 32-bits, etc.) In this case, we have to worry about the “endianness” as the decimal value represented in the NSData. So, when we store numeric values as a series of bytes, we like to be explicit about the order of the bytes. For example, if we want a big-endian NSData representation:
UInt16 value = 11007;
UInt16 bytes = NSSwapHostShortToBig(value);
NSData *data = [NSData dataWithBytes:&bytes length:sizeof(bytes)];
NSLog(#"%#", data); // {length = 2, bytes = 0x2aff}
I think this generates random 64 bytes NSData.
uint8_t buffer[64];
SecRandomCopyBytes(kSecRandomDefault, 64, buffer);
NSData *keyData = [[NSData alloc] initWithBytes:buffer length:sizeof(buffer)];
I want to generate 64 bytes NSData like this but not a random data.
How can I generate 64 bytes NSData with a given key like "com.this.is.akey".
Tried this one but it gave me wrong bytes size(not 64 bytes).
NSString *base64EncodedString = [[#"somekey.here" dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
NSData *encodedData = [[NSData alloc] initWithBase64EncodedString:base64EncodedString
options:0];
You can use -[NSString dataUsingEncoding:] to convert NSString to NSData.
NSString *key = #"com.this.is.akey";
NSData *keyData = [key dataUsingEncoding:NSASCIIStringEncoding];
If length of the data is less or greater than 64 bytes, you should pad or truncate data to exact 64 bytes.
if (keyData.length != 64) {
NSMutableData *mutableData = keyData.mutableCopy;
mutableData.length = 64;
keyData = mutableData.copy;
}
Then, you can pass the NSData object to RLMRealmConfiguration.encryptionKey.
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.encryptionKey = keyData;
NSError *error = nil;
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
Given a string for a key one should use a key derivation function such as PBKDF2.
Example:
#import <CommonCrypto/CommonCrypto.h>
NSString *keyString = #"com.this.is.key"; // Should use a random value
NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
NSData *salt = [#"saltstring" dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *derivedKey = [NSMutableData dataWithLength:CC_SHA512_DIGEST_LENGTH];
CCKeyDerivationPBKDF(kCCPBKDF2,
keyData.bytes, keyData.length,
salt.bytes, salt.length,
kCCPRFHmacAlgSHA512,
10000, // Choose for desired timing
derivedKey.mutableBytes, derivedKey.length);
NSLog(#"derivedKey: %#", derivedKey);
Output: derivedKey:
065d2106 1da7ebcf d155a50a b1ee5540 dee8efce f4678c47 02164488 e92e05e5 30c1f12d a3813013 652aca1b 0016b258 610d7929 f240de72 3eab85d9 7e028b35
Notes:
It is best to set the salt to a random value and provide it along with the derived key.
The iteration count should set to provide a suitable derivation tine, perhaps 100ms. There is a corresponding CCCalibratePBKDF function the help with this. The iteration count can also be provided along with the derived key.
Sorry if this seems to be more work that necessary but security is not easy to get right.
I am using the following code to write the 0xDE value for a Bluetooth Caracteristic (Reset Device) using the IOS Core Bluetooth :
...
NSData *bytes = [#"0xDE" dataUsingEncoding:NSUTF8StringEncoding];
[peripheral writeValue:bytes
forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
...
is there any mistake in my code because the value is not written properly?
Swift 3.0: In case anyone is wondering the format for Swift is slightly different as writeValue can get the count from the array.
let value: UInt8 = 0xDE
let data = Data(bytes: [value])
peripheral.writeValue(data, for: characteristic, type: .withResponse)
Try creating your data with an array of single byte values.
const uint8_t bytes[] = {0xDE};
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
This is a useful approach for creating arbitrary constant data. For more bytes,
const uint8_t bytes[] = {0x01,0x02,0x03,0x04,0x05};
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
If you want to create data to send using variables, I would recommend using NSMutableData and appending the bytes that you need. It isn't very pretty, but it is easy to read / understand, especially when you are matching a packed struct on the embedded side. Example below is from a BLE project where we were making a simple communication protocol.
NSMutableData *data = [[NSMutableData alloc] init];
//pull out each of the fields in order to correctly
//serialize into a correctly ordered byte stream
const uint8_t start = PKT_START_BYTE;
const uint8_t bitfield = (uint8_t)self.bitfield;
const uint8_t frame = (uint8_t)self.frameNumber;
const uint8_t size = (uint8_t)self.size;
//append the individual bytes to the data chunk
[data appendBytes:&start length:1];
[data appendBytes:&bitfield length:1];
[data appendBytes:&frame length:1];
[data appendBytes:&size length:1];
The answer by bensarz is almost correct. Except one thing: you shouldn't use sizeof(int) as the length for NSData. The size of int is 4 or 8 bytes (depending on the architecture). As you want to send 1 byte, use uint8_t or Byte instead:
uint8_t byteToWrite = 0xDE;
NSData *data = [[NSData alloc] initWithBytes:&byteToWrite length:sizeof(&byteToWrite)];
[peripheral writeValue:data
forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
Of courser you could also use int as the variable's type, but you have to initialize NSData with the length of 1.
This code will fix the problem :
NSData * data = [self dataWithHexString: #"DE"];
[peripheral writeValue:data forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
dataWithHexString implementation :
- (NSData *)dataWithHexString:(NSString *)hexstring
{
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= hexstring.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString* hexStr = [hexstring substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
What you are, in fact, doing here is writing the string "0xDE" to the characteristic. If you want to use binary/octal notation, you need to stay away from strings.
int integer = 0xDE;
NSData *data = [[NSData alloc] initWithBytes:&integer length:sizeof(integer)];
[peripheral writeValue:data
forCharacteristic:characteristic
type:CBCharacteristicWriteWithResponse];
I want to convert the 8 bytes I have in an NSData instance to a uint32_t array that has 2 items. I did the following, but it's not correct.
NSLog(#"Challenge data %#",dataChallenge);
uint32_t *data = (uint32_t *)dataChallenge.bytes;
NSLog(#"data0: %08x, data1: %08x", data[0], data[1]);
And this is the result:
Challenge data <3ce3e664 dafda14b>
data0: 64e6e33c, data1: 4ba1fdda
The order of data is not correct.
The values should be:
Challenge data <3ce3e664 dafda14b>
data0: 3ce3e664, data1: dafda14b
uint32_t *data = (uint32_t *)dataChallenge.bytes;
Example:
NSData *dataChallenge = [#"12345678" dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"dataChallenge: %#", dataChallenge);
uint32_t *data = (uint32_t *)dataChallenge.bytes;
NSLog(#"data0: %08x, data1: %08x", data[0], data[1]);
NSLog output:
dataChallenge: <31323334 35363738>
data0: 34333231, data1: 38373635
Note: The bytes are reversed because this is a lithe-endian machine
With memcpy:
NSData *dataChallenge = [#"12345678" dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"dataChallenge: %#", dataChallenge);
uint32_t data[2];
memcpy(data, (uint32_t *)dataChallenge.bytes, dataChallenge.length);
NSLog(#"data0: %08x, data1: %08x", data[0], data[1]);
NSLog output:
dataChallenge: <31323334 35363738>
data0: 34333231, data1: 38373635
Swapping the byte order:
NSLog(#"data0: %08x, data1: %08x", CFSwapInt32BigToHost(data[0]), CFSwapInt32BigToHost(data[1]));
NSLog output:
data0: 31323334, data1: 35363738
Note: See CFByteOrder.h for more combinations of byte swapping.
Below logic converts NSData to integer perfectly. Length of bytes does not matter. It just works.
NSData *data;
NSString *stringData = [data description];
stringData = [stringData substringWithRange:NSMakeRange(1, [stringData length]-2)];
unsigned dataAsInt = 0;
NSScanner *scanner = [NSScanner scannerWithString: stringData];
[scanner scanHexInt:& dataAsInt];
I have an NSData object that contains just <64> which is supposed to represent the int 100
How can I convert this NSData to an int?
I can convert it to it's Chr equivalent d using
NSString *string = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
but I need the Dec equivalent of 100
Thanks
<64> means that the NSData object contains a single byte with the value 0x64 = 100,
so the following should work;
const uint8_t *bytes = [data bytes]; // pointer to the bytes in data
int value = bytes[0]; // first byte
int *b = (int *)data.bytes;
printf("%d",*b); //prints 100
Below logic converts NSData to integer perefctly. Length of bytes does not matter. It just works.
NSData *data;
NSString *stringData = [data description];
stringData = [stringData substringWithRange:NSMakeRange(1, [stringData length]-2)];
unsigned dataAsInt = 0;
NSScanner *scanner = [NSScanner scannerWithString: stringData];
[scanner scanHexInt:& dataAsInt];