iOS BLE Characteristic Control Point Write - ATT Error - ios

I'm having trouble performing a write on a control point characteristic.
Perhaps I'm providing an erroneous value, as I don't fully understand the nature of a control point. I've noted some of the specs about the control point value next to implementation.
Even so, wouldn't I receive a more detailed error description than ATT Unknown, so Im having trouble figuring out the root cause.
char buffer[1];
buffer[0] = 0x01; // opCode - 1 byte
// buffer[1] = 0x00; // Operand - variable length, N/A in this case
// buffer[2] = 0x00; // Crypto Data, 3 bytes, (handled by encryption manager? investigating)
NSData *data = [NSData dataWithBytes:buffer length:1];
NSData *data2 = [self.encryptionManager encrypt:data];
[_peripheral writeValue:data2 forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
By the way, all other profiles/control points can be successfully read and written to. And this has been successfully tested on Android - not by me.

It is your remote device that returns that error code. The specification mentions when the device should send this code as following:
2.3 CLIENT CHARACTERISTIC CONFIGURATION DESCRIPTOR IMPROPERLY CONFIGURED (0xFD)
The Client Characteristic Configuration Descriptor Improperly Configured error code is used when a Client Characteristic Configuration descriptor is not configured according to the requirements of the profile or service.
If the error code is being used correctly - I can't tell. Please read the documentation for your remote device how it should be used. Because now it's a bit like you're asking why a random http server responds with error 500.
"Control point" more or less just means a characteristic you write to.

Related

GetDescriptor() null value / 128-bit UUID descriptor?

I'm writing my code using Xamarin. I'm developing my IOS app which allows me to read the BLE devices, Services, characteristic value and activation of the notification.
My BLE beacon have one custom Services that contain two custom characteristics and both have the notification implemented using CCCD.
My ble devices work correctly I test it with BLE scanner app and it working well without any problem.
I can read value and I can active the notification for both characteristic. See picture here.
The app that I wrote using xamarin work correctly (reading services, characteristic value....) the only problem that didn't work is the activation of the notification. Here's a portion of the code :
public UUID Charac_UUID0 = UUID.FromString("0000beef-1212-efde-1523-785fef13d123");
public UUID Charac_UUID = UUID.FromString("0000b1e0-1212-efde-1523-785fef13d123") ;
public UUID Descr_UUID = UUID.FromString("00002902-1212-efde-1523-785fef13d123");
protected BluetoothGattCharacteristic _charac;
....
....
this._charac = App.Current.State.SelectedService.GetCharacteristic(Charac_UUID0);
BluetoothLEManager.Current.ConnectedDevices[App.Current.State.SelectedDevice].SetCharacteristicNotification(_charac, true);
BluetoothGattDescriptor descriptor = _charac.GetDescriptor(Descr_UUID0);
descriptor.SetValue(BluetoothGattDescriptor.EnableNotificationValue.ToArray());
BluetoothLEManager.Current.ConnectedDevices[App.Current.State.SelectedDevice].WriteDescriptor(descriptor);
The code always give me an error at descriptor.SetValue and it indicate me that the descriptor is NULL meaning that _charac.GetDescriptor didn't return any value.
I suspect the Descriptor UUID value (Descr_UUID) is not correct. I don't know excatly how can I determine the Descr_UUID but I saw many example in the internet of people replacing the custom UUID of the caracteristic by 2902 which give me in my case a 128 descriptor UUID equal to 00002902-1212-efde-1523-785fef13d123.
But there is a problem here. The descriptor UUID for both characteristic will be the same because the base UUID is the same for both characteristic?
Any solution?
3 years later im sure you figured it out but, 2902 is the 16 bit value for a Client Characteristic Configuration Descriptor, and I believe it should also be inflated using the "BASE UUID" not just whatever your characteristic descriptor uses. See this: answer
This will convert your 16 (or 32) bit uuids to full 128 bit uuids using the BASE UUID:
public static UUID ConvertUuid(uint uuid)
{
const long msbMask = 0x0000000000001000;
const ulong lsb = 0x800000805f9b34fb;
var msb = msbMask | ((ulong)(uuid & uint.MaxValue) << 32);
return new UUID((long)msb, unchecked((long)lsb));
}

Transfer large binary string to BLE device from ios app using corebluetooth

I want send large binary string to BLE device(peripheral) from my ios app(central device). Its working fine with small string, but when iam trying to send large string, It was not receiving and the connection was automatically disconnecting. I have read that we need to divide the large data into multiple chunks to send it. But i didn't find any working sample on that.
Please look at the code send the string
let stringToSend = "0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000,0001010101010101111111111111000000#"
.
let data : NSData = stringToSend.dataUsingEncoding(NSUTF8StringEncoding)!
if positionCharacteristic != nil {
self.polarH7HRMPeripheral.writeValue(data, forCharacteristic: positionCharacteristic, type: .WithoutResponse)
self.polarH7HRMPeripheral.setNotifyValue(true, forCharacteristic: positionCharacteristic)
}
Thanks in advance
Some devices registers are limited in size. They can't contain more than X bytes for processing.
Let's assume said BLE device expects a long command in a format of a few short commands.
Let's also assume said device able to receive short commands as well.
How would the device know the difference between a short command and a partial long command? Using a command format which states command type.
For example:
A command will contain 1 header byte, 6 content bytes, 1 command type byte.
Partial long command will have 11111111 as its command type with the final part as 11111110.
Short command will have 00000000 as the its command type.
This is how I "defined" a simple protocol for difference commands for a device.
I would recommend you look for that protocol in the developer manual of that device
Some device accepts 20 bytes at most, so you have to spit your string.
for strMsgPart in stringToSend.split(by: 20) {
if positionCharacteristic != nil {
self.polarH7HRMPeripheral.writeValue(strMsgPart, forCharacteristic: positionCharacteristic, type: .WithoutResponse)
self.polarH7HRMPeripheral.setNotifyValue(true, forCharacteristic: positionCharacteristic)
}
}

RSA decryption fails in iOS

I'm trying to do RSA2048 in iOS and am following the example codes from Apple and also this question RSA implementations in Objective C. I have tested on iPhone 5c with iOS 8.4.1, but the sample codes fail at decryption with private key, with error code -9809 (An underlying cryptographic error was encountered), even though encryption with public key. I understand the basic approach is to generate an RSA key pair, secure them in keychain and use public key ref to encrypt and private key to decrypt. I'm completely lost why decryption shall fail, and not always, there are times when decryption succeeded.
Full codes can be found at https://gist.github.com/aceisScope/372e6d6f92650ce03624. The decryption part that throws an error is below, where from time to time status = -9809, and other times it works and returns 0:
status = SecKeyDecrypt(privateKey,
PADDING,
cipherBuffer,
cipherBufferSize,
plainBuffer,
&plainBufferSize
);
I have also set a check that if such key pair has already generated, next time encryption/decryption is called, it will directly using the already-generated-and-stored key pair from key chain without generating a new pair.
Update:
I came across this post iPhone Public-Key Encryption SecKeyEncrypt returns error 9809 (errSSLCrypto) which found out wrong cipher buffer size may cause -9809 error to encryption. Yet even if I make sure both the cipher buffer size in encryption and plain buffer size in decryption is the same as key block size and private key block size, encryption always works but with decryption failing from time to time.
I found the problem. By the end of encryption, when converting cipher buffer to NSData, in the following code
NSMutableData *data=[[NSMutableData alloc] init];
[data appendBytes:cipherBuffer length:strlen( (char*)cipherBuffer ) + 1];
the length is not correct. It should be the size of the cipher buffer, which is the same as key block size.
So after changing it to
NSData *data = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];
decryption works now.

Data encryption with AES

I'm building an app that will communicate with a server (php), and this communication (probably will be with json) i want to encrypt. After a lot of searching and reading i found the AESCrypt-Objc project.
While testing the encryption (i'm using a web tool AES Encryption test) i found that in the encryption result i'm missing 16 byte of data.
Here's the example i'm using
In the AES project:
String to be encrypted: "The quick brown fox jumped over the lazy dog".
Password: "12345678901234561234567890123456"
The result:
<7eda336b 82f3e279 ae7638fe cccfffc6 5fbef8da 6df76d97 67d8cfa8 5bce2ae9>
My Code:
self.strnToBeEnc = #"The quick brown fox jumped over the lazy dog";
self.appKey = #"12345678901234561234567890123456";
NSData *data2 = [self.strnToBeEnc dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"%#", data2);
NSData *s2 = [data2 AES256EncryptedDataUsingKey:self.appKey error:nil];
NSLog(#"%#", s2);
WEB Tool:
Same string and password
The result:
<7eda336b 82f3e279 ae7638fe cccfffc6 5fbef8da 6df76d97 67d8cfa8 5bce2ae9 ca2ed34a 48f85af2 909654d5 b0de0fb7>
As you can see i'm missing some bytes...:)
I've tried adding to the buffer in the algorithm, but with no success.
Any advice?
Thanks
(if the question is not Detailed enough please let me know)
I know you were trying to avoid this but I think you might need to spend some time in the source code of AESCrypt-Objc as I suspect it is somehow not encrypting the last block.
Step into the code and see if you actually get to the CCCryptorFinal call, and note its results. This can be found in the AESCrypt-ObjC/NSData+CommonCrypto.m _runCryptor:result: . Another thing to look into is the default padding type they are using which appears to be kCCOptionPKCS7Padding this will also have an effect on your ending bytes.
Do your testing first with non-arbitrary length bytes that are multiples of the AES block size, then once you have validated that move on to the variable length ones you have here.

iOS: sending .jpg image as base64 to tcp server

This one is going to kill me. I'm so close to getting this done except for this one stupid problem. And I am not sure I will be able to adequately describe the problem, but I'll try.
My enterprise app uses the iPhone camera to take pictures of receipts of purchases made by our field personnel. I used a real cool API for turning the jpeg data to base 64 (https://github.com/nicklockwood/Base64) to send via TCP connection to the VB 2010 server, which reads it as a text string and converts it back to a binary.
When the base64 file is created, it is first saved to disk on the phone, because there may be more images. Then when ready to send, the process will read each base64 file and send it one at a time.
The text string created by the base64 function is quite large, and at first it was only sending about 131,000 bytes, which would convert back to binary easily enough but would render about 1/4 to 1/3 of the image. I just figured that the data was being truncated because the app was trying to get ahead of itself.
So then I found a nice snippet that showed me how to use the NSStreamEventHasSpaceAvailable event to split the base64 string into several chunks and send them sequentially. (http://www.ios-developer.net/iphone-ipad-programmer/development/tcpip/tcp-client) That works great insofar as it sends the full file -- that is, the resulting file received by the server is the correct size, the same as the base64 file before it's sent.
The problem here is that at some point the file received by the server is corrupted because it seems to start all over at the beginning of the file... in other words, the data starts to repeat itself.
The odd part is that the repeating part starts at exactly the same spot in the received file every time: at position 131016. It doesn't start the repetition at the end of the file, it just interrupts the file at that point and jumps back to the beginning. And it happens that that was the size of the file that was sent before I started using the HasSpaceAvailable event. I can't figure out what the significance of the value 131,016 is. Maximum buffer size somewhere?
Using all kinds of NSLogs and breakpoints, I have pretty much determined that the data is leaving the phone that way, and not being scrambled by the server. I also wrote in an NSMailComposeViewer method that would email me the base64 file as an attachment, and it comes through perfectly.
Here is the code for when the file is read from disk and sent to the server:
int i;
for (i = 0; i < [imageList count];i++){
NSArray *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory= [documentsPath objectAtIndex:0]; //Get the docs directory
NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:imageFileName];
imageFileName = [imageList objectAtIndex:i] ;
NSLog(#"Image index: %d - image file name: %#",i,imageFileName);
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:imagePath];
if(fileExists == YES){
NSString *imageReceipt = [NSString stringWithContentsOfFile:imagePath encoding:NSASCIIStringEncoding error:nil];
int32_t imageStringLen = [imageReceipt length];
NSString *imageSize = [NSString stringWithFormat: #"%d",imageStringLen];
NSString *currentImage = [NSString stringWithFormat:#"image,%#,%#,%#",imageFileName,imageSize,imageReceipt]; //creates a CSV string with a header string with the filename and file size, and then appends the image data as the final comma-separated string.
data = [[NSMutableData alloc] initWithData:[currentImage dataUsingEncoding:NSASCIIStringEncoding]];
[outputStream write:[data bytes] maxLength:[data length]];
And then here is the code that uses the HasSpaceAvailable event:
case NSStreamEventHasSpaceAvailable:
if (data != nil)
{
//Send rest of the packet
int ActualOutputBytes = [outputStream write:[data bytes] maxLength:[data length]];
int totalLength = [data length];
if (ActualOutputBytes >= totalLength)
{
//It was all sent
data = nil;
}
else
{
//Only partially sent
[data replaceBytesInRange:NSMakeRange(0, ActualOutputBytes) withBytes:NULL length:0]; //Remove sent bytes from the start
}
}
break;
(I especially like this code because it would allow placing a ProgressView control on the screen.)
The network stream event handler code is in the root view controller, but the image data in base64 is being sent from another view controller. My instinct tells me that this is not a problem because it has worked fine until now, but with much shorter strings.
Now, there's one other issue that may be related -- and probably is. I can't seem to complete the transfer of the data unless I close the app. The server doesn't see it until the connection is closed, I guess. I have tried placing [outputStream close] in various places in the code to no avail. I've also tried terminating the base64 string with a linefeed or carriage return or both.
The server is programmed to save the file when it has seen the correct number of bytes, but that never happens until the app is closed. I know by using WireShark on the server that some of the data is being received, but the remaining data, as I have said, doesn't arrive until the app is closed.
I suspect that this last part (completing the transfer) is the problem, but for the life of me, I can't find anything online that addresses this, unless I am just too ignorant to know what search terms to use.... which is highly likely.
I hope I have given enough information. Can anyone help me?
EDIT
The solution to the problem appeared to be different than what was suspected in the original answer. Through the discussion in the comments the QP has been led to a solution. Here is a summary:
The transmission of data through a raw TCP socket requires thorough handling of the enqueing logic, which was not properly taken into account by the QP. I recommended to use the socket library CocoaAsyncSocket which handles this part of the task and which in turn led the QP to a working solution.
Original Answer:
I'd guess NSString is not up to the task. It's made to hold, well, strings.
Try to read the file into an NSData directly instead and sending it as binary. (Its ascii in the end, isn't it?) Besides, this will be much more resource friendly than your current code.

Resources