I have some code that downloads a plist from a web server and stores it in the documents directory of the phone. My concern is that if the file becomes corrupt then it will effect the stability and user experience of the app.
I am coding defensively in the data read parts of the app, but wondered what advice is out there for checking the integrity of the file in the first place before the old one is over written. I am thinking of implementing some sort of computed value which is also stored in as a key in the plist for example.
Any thoughts about making this as robust as possible would be greatly appreciated.
Best regards
Dave
Have a look at CommonCrypto/CommonDigest.h.
The CC_MD5(const void *data, CC_LONG len, unsigned char *md); function computes an MD5 hash.
#implementation NSData (MD5)
-(NSString*)md5
{
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5([self bytes], [self length], digest);
NSString* s = [NSString stringWithFormat: #"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1],
digest[2], digest[3],
digest[4], digest[5],
digest[6], digest[7],
digest[8], digest[9],
digest[10], digest[11],
digest[12], digest[13],
digest[14], digest[15]];
return s;
}
#end
As part of the deployment of the files on the server, you can use OpenSSL to compute the hashs. The openssl md5 filename command computes an MD5 hash for a file. This can be integrated in a script.
Then after your application has downloaded a file, it computes the hash of what's been downloaded and compares it to the hash stored on the server.
Obviously, if you want to ensure the integrity of a plist file, this plist cannot contain its own hash.
Related
I have seen this thread, and the encryption techniques mentioned there is working well. But not in all cases.
Requirement:
Simple, take one image, encrypt it, and store the encrypted data. Later, get the encrypted data, decrypt it, recreate the original image and show.
What I have done
From the above mentioned thread, I found NSData additions for AES 256 encryption. I tried to use it but with partial success. This is the code
//encryption
NSData *srcData = UIImageJPEGRepresentation(srcImage, 1.0);
NSLog(#"srcData length : %d",[srcData length]);
NSData *encryptedData = [srcData AES256EncryptWithKey:KEY];
NSLog(#"encrypted data length : %d",[encryptedData length]);
........
//later..
//decryption
decryptedImage = [UIImage imageWithData:[encryptedData AES256DecryptWithKey:KEY]];
imageView.image = decryptedImage;
What is happening
For a small image, say image with resolution 48*48, this code is working successfully. But when I run the code in an image with higher resolutions, say 256 * 256, the method AES256EncryptWithKey failing with error kCCBufferTooSmall (-4301).
Questions
Does AES 256 impose any limit on the size (in bytes) of the payload
to be encrypted?
If the answer to first question is YES, then what kind of
encryption algorithm to use in iphone, to encrypt image (probably
big ones)?
If the answer to the first question is NO, then why this error?
No, not really. Some hash functions do have a maximum, but that's more in the order of 2^64, so generally you don't have to worry.
N/A
It has probably something to do with the dataWithBytesNoCopy in combination with the malloc call, but it is hard to find out without actually running the code.
Note that that wrapper is pretty braindead, as it does require encrypting all at once, without using CCCryptorUpdate. It does not use an IV which jeopardizes security. It handles the keys as strings. Finally, it creates too big a buffer size for decryption. You are better off creating your own using a more reliable source.
I'm writing a database project on the iPhone and I'd like to store some big SQL queries in a separate, project-included file.
Then, I'd like to read this query into an NSString * (or, well, const char * is also ok) reference, and then perform it with an sqlite3.
I'm a newbie to iPhone developing, and I have never worked with files, neither I know any details of their storage.
Could you please give me a hint on:
The appropriate file format to store the strings.
How do I store it into the iPhone;
How do I read from it.
Thanks a lot!
You can use:
Any simple character based (text) file would be more than enough
Just put it in a folder in your project, it will get deployed with your Application
Use NSString class.
For issue #3 you can use:
NSString *sqlString =
[NSString
stringWithContentsOfFile:#"yourqueryfile.sql"
encoding:NSUTF8StringEncoding
errors:nil //unless yuo are interested in errors.
];
I am trying to implement an iphone application which can read some fixed amount of bytes from a file and store in another file. this process will go on up to the end of the file. I am very new to iphone application so please help me on that . Is there any parent classes out there for this specific type of implementation?
I had a very large file which couldn't be read with NSData methods, so I used the following (per TechZen's suggestion for fine grain control).
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
[fileHandle seekToFileOffset:offset];
NSData *data = [fileHandle readDataOfLength:length];
If you just want to copy the file, use NSFileManager's copy functions.
If you just want specific bytes in a file, you can load the file using NSData's file methods then you can get specific blocks of bytes and write them to file.
If you want more fine grain control, use NSFileHandler.
Edit01:
This page has examples for close to what you want. I don't have anything on hand.
I need to store passwords in NSString objects; however, I would like some way to obfuscate them, so they cannot be read directly from memory.
This is a Mac OS X (10.5) application, but a solution that also works on iPhone would be much appreciated.
If you use the keychain for storing passwords then instead of passing strings around you could handle the opaque keychain SecKeychainItemRefs, only retrieving plaintext at the point where it's required. That's also the way Mac users expect their passwords to be dealt with. Unfortunately without knowing why you "need to store passwords in NSString objects" I can't tell if that's really true :-)
Couldn't you just md5 them before putting them in the NSString? Then when you go to test, md5 the input string and compare that with what is stored?
On the iPhone, the sandbox will stop anyone accessing your passwords. on the desktop it's not so easy.
You should store the passwords as hashes rather than cleartext. I believe this will get you the results you want without affecting functionality. The only think you will never be able to do is access the cleartext password again - if you want to analyse it for strength or pass it on to another service. In general though, hashes will not sacrifice functionality.
The following code takes a password in rawPassword and stores its SHA-1 hash in passwordHash.
#import <CommonCrypto/CommonDigest.h>
const char* utf8PasswordRepresentation = [rawPassword UTF8String];
unsigned char * rawHash = malloc(CC_SHA1_DIGEST_LENGTH);
CC_SHA1(utf8PasswordRepresentation, strlen(utf8PasswordRepresentation), rawHash);
NSMutableString* passwordHash = [NSMutableString CC_SHA1_DIGEST_LENGTH*2];
for (int i = 0 ; i< CC_SHA1_DIGEST_LENGTH; i++)
[passwordHash appendFormat:#"%02x" , rawHash[i]];
Note that there is no memory management here.
Check out the wikipedia entry for an explanation of password hashing.
There are many versions of this same code around the intertubes.
I think the poster is referring to obfuscating the password in memory, so you can't just read the contents of the ivar out of memory. The GData library from google has some useful code for XORing passwords stored as NSMutableData in instance variables.
source for GDataServiceBase.m
// XorPlainMutableData is a simple way to keep passwords held in heap objects
// from being visible as plain-text
static void XorPlainMutableData(NSMutableData *mutable) {
// this helps avoid storing passwords on the heap in plaintext
const unsigned char theXORValue = 0x95; // 0x95 = 0xb10010101
unsigned char *dataPtr = [mutable mutableBytes];
NSUInteger length = [mutable length];
for (NSUInteger idx = 0; idx < length; idx++) {
dataPtr[idx] ^= theXORValue;
}
}
You can save/restore the password using XOR (see #password and #setUserCredentialsWithUsername:password: methods in the same file). XOR is not high-tech encryption, but it's good enough to deter casual snooping. In the case of the GData client where you might have a long-lived service/manager object in an application that retains a reference to the password data, I think this is a reasonable approach.
A very useful set of code for storing and retrieving passwords to and from the keychain can be found here:
http://log.scifihifi.com/post/55837387/simple-iphone-keychain-code
I've used it, and it worked well.
For all operation with Amazon services(S3, EC2, SimpleDB) You need to sign all resquest with HMAC-SHA-1 Signature(http://en.wikipedia.org/wiki/HMAC , http://docs.amazonwebservices.com/AWSFWS/latest/DeveloperGuide/index.html?SummaryOfAuthentication.html).
I'm working under asp.net backend and there is no problems. Problem is in the iPhone application. iPhone developer says that there is no way to use HMAC-SHA-1 encoding, and he have no rigths to implement his own algorithm. As programmer I cannot understand why there can be a problem.
So I want too know is iPhone developer right?
I've never coded for iPhone, so I don't even where to search such an information.
CommonCrypto does the trick.
#import <CommonCrypto/CommonHMAC.h>
then later
/*
inputs:
NSData *keyData;
NSData *clearTextData
*/
uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0};
CCHmacContext hmacContext;
CCHmacInit(&hmacContext, kCCHmacAlgSHA1, keyData.bytes, keyData.length);
CCHmacUpdate(&hmacContext, clearTextData.bytes, clearTextData.length);
CCHmacFinal(&hmacContext, digest);
NSData *out = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
CommonCrypto will do it. But if you want code, I have some here:
http://oauth.googlecode.com/svn/code/obj-c/OAuthConsumer/Crypto/
Which I wrote for use in the Cocoa OAuth implementation: http://code.google.com/p/oauthconsumer/wiki/UsingOAuthConsumer
This article demonstrates a little function that will generate an SHA-1 hash digest that will match what the php sha1() function will generate if you give it the same input:
#import <CommonCrypto/CommonDigest.h>
#implementation SHA1
+(NSString*) digest:(NSString*)input
{
const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:input.length];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, data.length, digest);
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
[output appendFormat:#"%02x", digest[i]];
return output;
}
#end
A bit of googling and I found this document.
Exporting of SHA1 is subject to
(United Statese)Federal Government
export controls and exporters are
advised to contact the Department of
Commerce, Bureau of Export
Administration for more information.
I also found this:
People's Republic of China and the
former Soviet Block can import SHA as
long as it's intended for civil
end-user applications rather than for
military purpose. The following
countries are prohibited from
importing SHA: Cuba, Iran, Iraq,
Libya, North Korea, Serbia, Syria, and
Sudan. Please note that this list of
embargo countries changes over time.
(Not a direct answer to your question, but certainly pertinent.)
Not for iPhone in particular, but the library libs3 provides a C API for accessing Amazon's S3 services. It, or the FUSE s3fs component, may be good sources for extracting the routines needed to communicate with Amazon's Web Services. As Objective-C is still C at its core, these routines should work just fine on the iPhone.
I know at least one developer who is using something similar within their iPhone application to communicate with S3 buckets.
I think the CommonCrypto library will do what you want. Look at this file:
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/usr/include/CommonCrypto/CommonHMAC.h
I don't know if this is the case anymore, but there used to be restrictions on encryption algorithms and your right to distribute them to certain countries were restricted.
If this is still the case it could be that Apple don't want/can't restrict certain applications from being downloaded in these countries.