How to send integer through NSOutputStream? - iphone

So I'm making an iOS app that constantly sends and array of points through NSStreams, but because sometimes the sender writes two arrays before the receiver receives one, I decided to first write the length, then the array data itself, so that the receiver knows how many bytes to process.
sender:
if (_outStream && [_outStream hasSpaceAvailable]){
const uint8_t *buffer = [data bytes];
uint64_t length = CFSwapInt64HostToLittle([data length]);
NSLog(#"Sending bytes with length: %llu", length);
int er1 = [_outStream write:(const uint8_t *)&length maxLength:sizeof(length)];
int er2 = [_outStream write:buffer maxLength:length];
if (er1 < 0 || er2 < 0) {
[self _showAlert:#"Failed sending data to peer"];
}
}
receiver:
case NSStreamEventHasBytesAvailable:
{
if (stream == _inStream) {
uint8_t *b;
int len = 0;
len = [_inStream read:b maxLength:8];
uint64_t dataLength = CFSwapInt64LittleToHost(*b);
NSLog(#"Received bytes with length: %llu", dataLength);
if(len < 0) {
if ([stream streamStatus] != NSStreamStatusAtEnd)
[self _showAlert:#"Failed reading data from peer"];
} else if (len > 0){
uint8_t bytes[dataLength];
int length = [_inStream read:bytes maxLength:dataLength];
[currentDownload appendBytes:bytes length:length];
id pointsArray = [NSKeyedUnarchiver unarchiveObjectWithData:currentDownload];
[currentDownload release];
currentDownload = [[NSMutableData alloc] init];
if ([pointsArray isKindOfClass:[NSArray class]]) {
[drawScene addNewPoint:[[pointsArray objectAtIndex:0] CGPointValue] previousPoint:[[pointsArray objectAtIndex:1] CGPointValue]];
}
}
}
break;
}
The problem is that the receiver receives an incorrect integer, hence it reads an incorrect amount of bytes.
Can anyone help me with this?

Could it be that when you read the data, you're starting with the introductory bits intended to convey length, rather than starting with the actual data?
For:
[currentDownload appendBytes:bytes length:length];
try substituting something like this:
NSRange rangeLeftover = NSMakeRange(sizeof(uint8_t), [currentDownload length] - sizeof(uint8_t));
NSData *dataLeftover = [currentDownload subdataWithRange:rangeLeftover];
uint8_t bytesLeftover[[dataLeftover length]];
[dataLeftover getBytes:&bytesLeftover length:[dataLeftover length]];
currentDownload = [NSMutableData data]; // clear
[currentDownload appendBytes:bytesLeftover length:[dataLeftover length]];

Related

blowfish algorithm objective c

I have to use Blowfish algorithm in my code for encryption and decryption. After calling the decryption method, blowfishDecrypt, I am getting the value in NSData but it give me always null when I convert it to NSString.
I am using the following code :
-(void)methodCalled
{
syncTime=#"c7c937169084b20c3ff882dcda193a59";
NSData* data = [syncTime dataUsingEncoding:NSUTF8StringEncoding];
NSData* data2 = [#"R=U!LH$O2B#" dataUsingEncoding:NSUTF8StringEncoding];
NSData* dycryptData=[self blowfishDecrypt:data usingKey:data2];
// prints <0eec37b6 2b76c2df cdf72356 0f033ed8 d6bd37dd 5223bf66 5c318ebe 07f3cf71>
NSLog(#"%#",dycryptData);
NSString *dSync=[[NSString alloc] initWithBytes:[dycryptData bytes]
length:[dycryptData length]
encoding:NSUTF8StringEncoding];
// prints (null)
NSLog(#"Sync timeis %#",dSync);
}
-(NSData *)blowfishDecrypt:(NSData *)messageData
usingKey:(NSData *)secretKeyData {
NSMutableData *decryptedData = [messageData mutableCopy];
BLOWFISH_CTX ctx;
Blowfish_Init (&ctx, (unsigned char*)[secretKeyData bytes], [secretKeyData length]);
NSRange aLeftRange, aRightRange;
NSData *aLeftBox, *aRightBox;
unsigned long dl = 0, dr = 0;
for (int i = 0; i< [decryptedData length]; i += 8) { // Divide data into octets...
// …and then into quartets
aLeftRange = NSMakeRange(i, 4);
aRightRange = NSMakeRange(i + 4, 4);
aLeftBox = [decryptedData subdataWithRange:aLeftRange];
aRightBox = [decryptedData subdataWithRange:aRightRange];
// Convert bytes into unsigned long
[aLeftBox getBytes:&dl length:sizeof(unsigned long)];
[aRightBox getBytes:&dr length:sizeof(unsigned long)];
// Decipher
Blowfish_Decrypt(&ctx, &dl, &dr);
// Put bytes back
[decryptedData replaceBytesInRange:aLeftRange withBytes:&dl];
[decryptedData replaceBytesInRange:aRightRange withBytes:&dr];
}
return decryptedData;
}
Blowfish library code can be found eg. here
HINT#1 //general answer
NSString provides an initializer for this purpose. You can see more info using the docs here.
NSString * dSync = [[NSString alloc] initWithData: dycryptData
encoding:NSUTF8StringEncoding];
Assuming you use ARC.
HINT#2 // the answer for this particular question
I tried your code and confirm the above NSString conversion returns null. So why it is not working? dycryptData is stream of bytes represented as hex, so I tried the following and received the desired result:
int dycryptData_len = [dycryptData length];
NSMutableString *dSync_hex = [NSMutableString stringWithCapacity:dycryptData_len*2];
const unsigned char *dycryptData_bytes = [dycryptData bytes];
for (int i = 0; i < dycryptData_len; ++i) {
[dSync_hex appendFormat:#"%02x", dycryptData_bytes[i]];
}
NSLog(#"dSync_hex=%#",dSync_hex);
I can see this result in log output:
dSync_hex=0eec37b62b76c2dfcdf723560f033ed8d6bd37dd5223bf665c318ebe07f3cf71

Can't receive jpeg image from server

I am trying to receive a jpeg image from my c# server. The weird thing is when I run it with the debugger and have a break point anywhere in the method it works perfectly fine. Without a breakpoint then I get this error
Corrupt JPEG data: premature end of data segment
Here is my code
(void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
NSMutableData *data;
data = [NSMutableData new];
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
uint8_t buffer[1024];
int len;
while([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0)
{
[data appendBytes:(const void*)buffer length:sizeof(buffer)];
}
}
UIImage *images = [[UIImage alloc]initWithData:data];
[dvdCover setImage:images];
} break;
case NSStreamEventEndEncountered:
{
//UIImage *images = [[UIImage alloc]initWithData:data];
//[dvdCover setImage:images];
} break;
}
}
hi you can check this code hop it will help you...
case NSStreamEventHasBytesAvailable:
{
uint32_t max_size = 1000000; // Max size of the received imaged you can modify it as your reqirement.
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: max_size];
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] maxLength: max_size];
if (bytesRead != 0) {
while (bytesRead > 0 && totalBytesRead + bytesRead < max_size) {
totalBytesRead+= bytesRead;
bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] + totalBytesRead maxLength: max_size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
[buffer setLength: totalBytesRead];
yourImageName.image = [UIImage imageWithData: buffer];
[buffer release];
} break;
It seems you are assuming the whole JPEG image will be transferred in one chunk, and you can just read it with one occurence of 'HasBytesAvailable' event. However you should also consider the case where the JPEG image is transferred to you in multiple chunks.
It might work for you if you set breakpoint, because your code execution might be halted somewhere, and your network buffer had plenty time to receive all bytes of the image. But without breakpoints it might not have time to do so.
Try refactoring your code to accumulate the bytes chunk, and only assume it's done when all bytes have been transferred. (Normally you have to know beforehand how many bytes the image is going to be -- or you can just capture the end of stream event)

How to decrypt a file in Objective C/IOS that is encrypted in php?

I have googled too much for this error but found nothing useful.
I am getting a file that is encrypted in php using the following code:
mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $privateencryptkey, base64_encode(file), MCRYPT_MODE_CBC, $hardvector);
I am unable to decrypt it in IOS. I had tried many libraries like NSDATA+CommonCrypto, NSFileManager-AES, NSDATA-aes but i have not got success in decrypting the file.
Following is the objective-C code used:
- (NSData *)AESDecryptWithPassphrase:(NSString *)pass
{
NSMutableData *ret = [NSMutableData dataWithCapacity:[self length]];
unsigned long rk[RKLENGTH(KEYBITS)];
unsigned char key[KEYLENGTH(KEYBITS)];
const char *password = [pass UTF8String];
for (int i = 0; i < sizeof(key); i++)
key[i] = password != 0 ? *password++ : 0;
int nrounds = rijndaelSetupDecrypt(rk, key, KEYBITS);
unsigned char *srcBytes = (unsigned char *)[self bytes];
int index = 0;
while (index < [self length])
{
unsigned char plaintext[16];
unsigned char ciphertext[16];
int j;
for (j = 0; j < sizeof(ciphertext); j++)
{
if (index >= [self length])
break;
ciphertext[j] = srcBytes[index++];
}
rijndaelDecrypt(rk, nrounds, ciphertext, plaintext);
[ret appendBytes:plaintext length:sizeof(plaintext)];
}
return ret;
}
This code works well for text but unable to decrypt files.
When i save the decrypted files then it says the file system error. Those decrypted files cannot be opened on any system, i think the file format is disturbed in the process.
I also tried the following code but no success:
- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
key: (id) key // data or string
initializationVector: (id) iv // data or string
options: (CCOptions) options
error: (CCCryptorStatus *) error
{
CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;
NSParameterAssert([key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]);
NSParameterAssert(iv == nil || [iv isKindOfClass: [NSData class]] || [iv isKindOfClass: [NSString class]]);
NSMutableData * keyData, * ivData;
if ( [key isKindOfClass: [NSData class]] )
keyData = (NSMutableData *) [key mutableCopy];
else
keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
if ( [iv isKindOfClass: [NSString class]] )
ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
else
ivData = (NSMutableData *) [iv mutableCopy]; // data or nil
[keyData autorelease];
[ivData autorelease];
// ensure correct lengths for key and iv data, based on algorithms
FixKeyLengths( algorithm, keyData, ivData );
status = CCCryptorCreate( kCCDecrypt, algorithm, options,
[keyData bytes], [keyData length], [ivData bytes],
&cryptor );
if ( status != kCCSuccess )
{
if ( error != NULL )
*error = status;
return ( nil );
}
NSData * result = [self _runCryptor: cryptor result: &status];
if ( (result == nil) && (error != NULL) )
*error = status;
CCCryptorRelease( cryptor );
return ( result );
}
2nd function from above code:
- (NSData *) _runCryptor: (CCCryptorRef) cryptor result: (CCCryptorStatus *) status
{
size_t bufsize = CCCryptorGetOutputLength( cryptor, (size_t)[self length], true );
void * buf = malloc( bufsize );
size_t bufused = 0;
size_t bytesTotal = 0;
*status = CCCryptorUpdate( cryptor, [self bytes], (size_t)[self length],
buf, bufsize, &bufused );
if ( *status != kCCSuccess )
{
free( buf );
return ( nil );
}
bytesTotal += bufused;
// From Brent Royal-Gordon (Twitter: architechies):
// Need to update buf ptr past used bytes when calling CCCryptorFinal()
*status = CCCryptorFinal( cryptor, buf + bufused, bufsize - bufused, &bufused );
if ( *status != kCCSuccess )
{
free( buf );
return ( nil );
}
bytesTotal += bufused;
return ( [NSData dataWithBytesNoCopy: buf length: bytesTotal] );
}
I haven't been able to solve this for a week...
One thing to note is the file parameter to mcrypt_encrypt, it appears that the file is being base64 encoded prior to encryption (not that it makes any sense), that would imply you would have to base64 decode after decryption.
The other parameters are straight forward:
MCRYPT_RIJNDAEL_128 is AES, 128 with a 128 bit key
MCRYPT_MODE_CBC is cbc mode, the default for CommonCrypto.
The padding to block size is with null characters, rather nonstandard so the non-padded length may be a problem.
Not that you need yet another AES method, this is the one I use:
#import <CommonCrypto/CommonCryptor.h>
+ (NSData *)doCipher:(NSData *)dataIn
iv:(NSData *)iv
key:(NSData *)symmetricKey
context:(CCOperation)encryptOrDecrypt
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0; // Number of bytes moved to buffer.
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
ccStatus = CCCrypt( encryptOrDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
symmetricKey.bytes,
kCCKeySizeAES128,
iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus != kCCSuccess) {
NSLog(#"CCCrypt status: %d", ccStatus);
}
dataOut.length = cryptBytes;
return dataOut;
}
// Also add Security.framework to your project.
Note that it expects NSData input and the padding is specified as standard PKCS.
See CommonCryptor.h

Receive an image on the iPhone (TCP Client)

I'm programming a client on the iPhone. I want to send some strings, and receive an image from the server.
I found this tutorial (http://www.devx.com/wireless/Article/43551), it has been very useful. It works if I want to receive strings, but now I want to receive an image, and I can't make it work.
This is my code when the iPhone receives data. It's a mix made with the tutorial and this answer from JeremyP (http://stackoverflow.com/questions/4613218):
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventHasBytesAvailable: {
if (data == nil) {
data = [[NSMutableData alloc] init];
}
uint8_t buf[102400];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:102400];
if(len) {
[data appendBytes:(const void *)buf length:len];
// Recibir img
uint8_t size; // Let's make sure size is an explicit width.
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [iStream read: &size maxLength: sizeof size];
while (bytesRead > 0 && totalBytesRead + bytesRead < sizeof size) {
totalBytesRead+= bytesRead;
bytesRead = [iStream read: &size + totalBytesRead maxLength: (sizeof size) - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail
}
if (totalBytesRead < sizeof size) {
// connection closed before we got the whole size, report and bail
}
size = ntohl(size); // assume wire protocol uses network byte ordering
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: size];
totalBytesRead = 0;
bytesRead = [iStream read: [buffer mutableBytes] maxLength: size];
while (bytesRead > 0 && totalBytesRead + bytesRead < size) {
totalBytesRead+= bytesRead;
bytesRead = [iStream read: [buffer mutableBytes] + totalBytesRead maxLength: size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
if (totalBytesRead < size) {
// connection closed before we got the whole image, report and bail (not forgetting to release buffer)
}
else {
[buffer setLength: size];
}
imgResultado.image = [UIImage imageWithData: buffer];
[buffer release];
[data release];
data = nil;
}
else {
NSLog(#"No data.");
}
} break;
}}
It doesn't work... could you help me?
Well, I made it work this way, but I'm no sure if there's a better way.
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
switch(eventCode) {
case NSStreamEventHasBytesAvailable:
{
uint32_t max_size = 1000000; // Max size of the received imaged.
NSMutableData* buffer = [[NSMutableData alloc] initWithLength: max_size];
NSInteger totalBytesRead = 0;
NSInteger bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] maxLength: max_size];
if (bytesRead != 0) {
while (bytesRead > 0 && totalBytesRead + bytesRead < max_size) {
totalBytesRead+= bytesRead;
bytesRead = [(NSInputStream *)stream read: [buffer mutableBytes] + totalBytesRead maxLength: max_size - totalBytesRead];
}
if (bytesRead >= 0) {
totalBytesRead += bytesRead;
}
else {
// read failure, report error and bail (not forgetting to release buffer)
}
[buffer setLength: totalBytesRead];
imgResultado.image = [UIImage imageWithData: buffer];
[buffer release];
}
} break;
}}
With this method, the received image must be smaller than max_size.
If you know a better way to do this, please let me know! ;)
If all you want to do is download an image from the server to display, take a look at this:
https://github.com/michaelkamprath/iPhoneMK/tree/master/Views/MKNetworkImageView
There are a lot of built in functions to the iOS that will handle image downloading for you. That is, if you can encapsulate the entities you want to download as separate URLs (e.g., a web server).
If, however, you are trying to send and receive data across the same TCP connection, I would strongly advise that you change to a more RESTful approach. Partly because it is easier to implement from the client side, partly because you don't have to worry (as much) about the underlying TCP connection.

How to create byte array from NSData

Please any one guide me how to create bytes array from nsdata here is my code for createing nsdata
NSData* data = UIImagePNGRepresentation(img);
If you only want to read them, there's a really easy method :
unsigned char *bytes = [data bytes];
If you want to edit the data, there's a method on NSData that does this.
// Make your array to hold the bytes
NSUInteger length = [data length];
unsigned char *bytes = malloc( length * sizeof(unsigned char) );
// Get the data
[data getBytes:bytes length:length];
NB Don't forget - if you're copying the data, you also have to call free(bytes) at some point ;)
Here is fastest way (but pretty danger) to get array:
unsigned char *bytesArray = data.bytes;
NSUInteger lengthOfBytesArray = data.length;
before trying to get byte#100 you should check lengthOfBytesArray like:
if (lengthOfBytesArray > 100 + 1)
{
unsigned char byteWithOffset100 = bytesArray[100];
}
And another safe and more objc-like way:
- (NSArray*) arrayOfBytesFromData:(NSData*) data
{
if (data.length > 0)
{
NSMutableArray *array = [NSMutableArray arrayWithCapacity:data.length];
NSUInteger i = 0;
for (i = 0; i < data.length; i++)
{
unsigned char byteFromArray = data.bytes[i];
[array addObject:[NSValue valueWithBytes:&byteFromArray
objCType:#encode(unsigned char)]];
}
return [NSArray arrayWithArray:array];
}
return nil;
}