Excuse me if this is a question that has been asked before, if so point me to the right answer.(i couldn't find the answer.)
My Question's:
I have an XML coming in from a NSUrl i need to be able to parse it appropriately,
i will be receiving the responses with Field Perpetrators in them such as ().
Could i have it set up to search a dictionary for Keywords and parse them from the XML?
If so what would be a good start on learning that?
Also is it possible to save the response's and encrypt them until i need to use them in another view?
if so, what is the best way to encrypt on the IOS side?
any guide in the right direction is wonderful!!
I'm not asking for someone to answer all of them but it would be nice, thank you!
The method - (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)mask error:(NSError **)errorPtr
has NSDataWritingFileProtection options that will encrypt the data for you but you have no control over they encryption key.
For encryption use CommonCrypro (part of iOS), aes128, cbc. But the real question is how will you securely save the encryption key?
Here is an encryption/decryption method:
+ (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, // kCCEncrypt or kCCDecrypt
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;
}
Related
I'm just coding basic "encrypt" and "decrypt" methods for AES on iPhone, using CCrypt.
I've been running a few tests and I was really struck about finding that, sometimes, if you try to decrypt an encrypted text using a key different than the one that was used to encrypt the plain text CCrypt would not return any errors.
Here is an example:
- (void) testDecryptTextWithTheWrongKey {
NSData *encryptKey = [Base64 decodeBase64WithString:#"+LtNYThpgIlQs2CaL00R6AuG2C/i6U1Vt1+6wfFeFMk="];
NSData *decryptKey = [Base64 decodeBase64WithString:#"yg7BvhM8npVGpAFpAESDn3IRWpe6qeQWaa1rwHiTsyU="];
NSString *plainText = #"The text to be encrypted";
NSData *plainTextData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NSData *encrypted = [LocalCrypto encryptText:plainTextData key:encryptKey error:&error];
assertThat(error, nilValue());
assertThat(encrypted, notNilValue());
error = nil;
NSData *decrypted = [LocalCrypto decryptText:encrypted key:decryptKey error:&error];
assertThat(error, notNilValue());
assertThat(decrypted, nilValue());
}
My encrypt and decrypt methods defined in LocalCrypto simply call an internal "executeCryptoOperation" method indicating that they want to encrypt or decrypt:
+ (NSData *) executeCryptoOperation:(CCOperation)op key:(NSData *) key input:(NSData *) input error:(NSError **)error {
size_t outLength;
NSMutableData *output = [NSMutableData dataWithLength:input.length + kCCBlockSizeAES128];
CCCryptorStatus result = CCCrypt(op, // operation
kCCAlgorithmAES128, // Algorithm
kCCOptionPKCS7Padding | kCCOptionECBMode, // options
key.bytes, // key
key.length, // keylength
nil, // iv
input.bytes, // dataIn
input.length, // dataInLength,
output.mutableBytes, // dataOut
output.length, // dataOutAvailable
&outLength); // dataOutMoved
if (result == kCCSuccess) {
output.length = outLength;
} else {
*error = [NSError errorWithDomain:kCryptoErrorDomain code:result userInfo:nil];
return nil;
}
return output;
}
Well, my question is: is it normal that CCrypt returns kCCSuccess when we try to decrypt the encrypted text with a different key than the one used during the encrpytion? Am I missing something or doing something wrong?
It is true that even when CCrypt returns success for the decryption, I can't get a proper NSString out of the resulting data but I would certainly expect CCrypt to return some sort of error in this situation (as Java would probably do).
If this is the normal behavior, how am I supposed to know if the decrypt operation returned the real plain text or just a bunch of bytes that don't make any sense?
There is a similar question here, but the answer doesn't really convince me: Returning wrong decryption text when using invalid key
Thanks!
There are cipher algorithms which include padding (like the PKCS#5 padding in your Java implementation), and there are ones which don't.
If your encryption algorithm used padding, the corresponding decryption algorithm expects that there will be well-formed padding in the decrypted plaintext, too. This serves as a cheap partial integrity check, since with a wrong key the output likely will not have a right padding. (The chance that a random n-byte block (n=16 for AES) has a valid PKCS#5 padding is 1/256 + 1/(256^2) + ... + 1/(256^n), which is only slightly more than 1/256.)
It might be that your objective-C CCCrypt function does not check that the padding is valid, only its last byte (or even only some bits of this last byte), to see how many bytes were padded (and are now to be cut off).
If you want to make sure that the key is right, encrypt some known part of the plaintext, and error out if it is not in the decrypted part. (But don't do this with ECB mode, see below.)
If you also want to make sure that the data was not modified, also use a MAC, or use a combined authenticated encryption mode of operation for your block cipher.
Another note: You should not use ECB mode, but instead a secure mode of operation (about any other mode indicated in this article and supported by your implementation will do - standard nowadays is CBC or CTR mode). Some modes (like CFB, OFB and CTR) don't need padding at all.
You're missing the fact that the decryption function has no idea whatsoever what the plaintext (decrypted data) is supposed to look like.
As far as the decryption function is concerned, it got a key and a ciphertext from you, applied the decryption routine to the ciphertext using the key you provided, and no errors arose. Hence, success.
It's your job to verify that the plaintext you got was actually correct/on the format you expected it to be.
I want to write encrypt function in iPhone application that would be decrypt on server in php,
Decrypt function in php is this
function decrypt($input_text)
{
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$enc_key = "0e9d083f3514a69243bb8f1395d332c1";
$out = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $enc_key, $input_text, MCRYPT_MODE_ECB, $iv);
return $out;
}
I'm using following encryption code in iPhone
+(NSString*) encrypt:(NSString*) str key:(NSString*) key
{
NSString *key =key;
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero( keyPtr, sizeof(keyPtr) ); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
char *dataIn = [str UTF8String];
char dataOut[500];// set it acc ur data
bzero(dataOut, sizeof(dataOut));
size_t numBytesEncrypted = 0;
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,kCCOptionPKCS7Padding|kCCOptionECBMode, keyPtr,kCCKeySizeAES128, NULL, dataIn, strlen(dataIn), dataOut, sizeof(dataOut), &numBytesEncrypted);
NSString* strResult = [[[NSString alloc] initWithCString:dataOut] autorelease];
return [strResult copy];
}
but didn't get the original result.
Please anybody can correct me where i'm wrong
Try:
As said, use the same key length in both cases.
In the CCCrypt call you don't store the iv that was generated, instead you pass NULL. You should store this and somehow transport it along the message to your PHP code. There, instead of generating a new, random iv you would reuse the existing one generated by the iPhone.
On top of that, mcrypt does not support PKCS7Padding (also often referred to as PKCS5Padding), so unfortunately you need to implement it yourself. In your case, you first decrypt the iPhone's input and then apply the pkcs5_unpad function described in that article afterwards.
You are using AES with 256-bit key in the decryption and with 128-bit key in the encryption. These are entirely different algorithms.
My app "streams" content (fixed sized files, hence quotation marks) from an HTTP server into a local file. Then there is another component of the app that opens that same file and displays it (plays it).
This is done for caching purposes, so that when the same file is requested next time, it will no longer need to be downloaded from the server.
App's spec requires that all local content is encrypted (even with the most light weight encryption)
Question: has there been done any work, allowing one to simply redirect the stream to a library which will then save the stream encrypted into a file? And then, when I request the stream from the local file, the library returns an on the fly decrypted stream?
I've been searching for a solution with no results so far
Thanks
I ended up writing a custom solution that uses RC4 encryption from the built in Crypt library. It was surprisingly straight forward. Basically it involved creating a function that encrypts/decrypts chunks of NSData and then read/write those chunks to files... Here's the function that does the encryption in case someone else is interested:
- (NSData*)RC4EncryptDecryptWithKey:(NSString *)key operation:(CCOperation)operation
{
// convert to C string..
int keySize = [key length];
char keyPtr[keySize];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr
maxLength:sizeof(keyPtr)
encoding:NSUTF8StringEncoding];
// encode/decode
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength;
void *buffer = malloc(bufferSize);
size_t numBytesOut = 0;
CCCryptorStatus cryptStatus = CCCrypt(operation,
kCCAlgorithmRC4,
kCCOptionECBMode,
keyPtr,
8,
NULL,
[self bytes],
dataLength,
buffer,
bufferSize,
&numBytesOut);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer
length:numBytesOut
freeWhenDone:YES];
}
free(buffer);
return nil;
}
- (NSData*)RC4EncryptWithKey:(NSString*)key {
return [self RC4EncryptDecryptWithKey:key operation:kCCEncrypt];
}
- (NSData*)RC4DecryptWithKey:(NSString*)key {
return [self RC4EncryptDecryptWithKey:key operation:kCCDecrypt];
}
Obviously one could create something more secure (eg AES) or whatever (in fact I used examples of other encryption wrappers to write this one)
I wouldn't worry about encryption just because Apple says so.
Make this work how you want it (without encryption, it sounds like) and submit it for approval. If approved, you're good. If not, worry about it then. If your design requires you to make a decision now, your design might be flawed.
I was to encrypt data on the device and send it by http to our web server then decrypt the data on out .net web app. Is this possible? If yes, which encryption method I should use? and if their are any articles out there?
Thanks
SSL should be the standard solution for HTTP encryption. NSURLConnection supports it out of the box (just load an https:// request), so you would just have to set up your server accordingly.
As you don't want to use SSL (and I agree there are many good reasons not to do so) you can use the built in CommonCrypto framework to encrypt just the data you need to. Here is a simple NSData category to encrypt arbitrary data:
#implementation NSData (AES256)
- (NSData*) encryptedWithKey: (NSString *) key;
{
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyBuffer[kCCKeySizeAES128+1]; // room for terminator (unused)
bzero( keyBuffer, sizeof(keyBuffer) ); // fill with zeroes (for padding)
[key getCString: keyBuffer maxLength: sizeof(keyBuffer) encoding: NSUTF8StringEncoding];
// encrypts in-place, since this is a mutable data object
size_t numBytesEncrypted = 0;
size_t returnLength = ([self length] + kCCKeySizeAES256) & ~(kCCKeySizeAES256 - 1);
// NSMutableData* returnBuffer = [NSMutableData dataWithLength:returnLength];
char* returnBuffer = malloc(returnLength * sizeof(uint8_t) );
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128 , kCCOptionPKCS7Padding | kCCOptionECBMode,
keyBuffer, kCCKeySizeAES128, nil,
[self bytes], [self length],
returnBuffer, returnLength,
&numBytesEncrypted);
if(result == kCCSuccess)
return [NSData dataWithBytes:returnBuffer length:numBytesEncrypted];
else
return nil;
}
#end
Note that this also turns on ECB Mode which you may not want. Also remember that the data that comes back from this call is not suitable for use in URLs you will have to base 64 encode it.
If SSL is not an option use AES encryption in CBC mode. 128 encryption bit is all you need and you can use anything (0 is acceptable) as the IV.
im trying to get a call to amazon web service and im stuck on getting the signature, looked at this but i still have a question on it.
using this example what is the
NSData *keyData;
NSData *clearTextData
? what do i need to pass for these two values?
/*
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]
I just spent like 4 hours Googling and looking for ways to calculate an unkeyed SHA1 on the iPhone that would match the results of the sha1() function in php. Here was the result:
#import <CommonCrypto/CommonDigest.h>
NSString *hashkey = <your data here>;
// PHP uses ASCII encoding, not UTF
const char *s = [hashkey cStringUsingEncoding:NSASCIIStringEncoding];
NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
// This is the destination
uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0};
// This one function does an unkeyed SHA1 hash of your hash data
CC_SHA1(keyData.bytes, keyData.length, digest);
// Now convert to NSData structure to make it usable again
NSData *out = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH];
// description converts to hex but puts <> around it and spaces every 4 bytes
NSString *hash = [out description];
hash = [hash stringByReplacingOccurrencesOfString:#" " withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#"<" withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#">" withString:#""];
// hash is now a string with just the 40char hash value in it
Hopefully this will help others who are struggling with SHA1 on the iPhone
If you are calling the Amazon web service too look up prices or product details, your Amazon web service key will be disabled and your app will stop working.
Look at the terms of service of the Amazon Web Services, use by mobile clients is strictly disallowed:
https://affiliate-program.amazon.com/gp/advertising/api/detail/agreement.html
I found this out the hard way when my own application had my AWS key disabled in a production app. I had read the TOS, but it was not really there as you can see by the link above to some other obscure detail of use. You wouldn't think the affiliate program would have anything to do with the API, but it does.
You can find details of other apps blocked at this TechCrunch article:
http://www.techcrunch.com/2009/07/07/amazon-killing-mobile-apps-that-use-its-data/
Just giving you a heads up and hopefully saving you a lot of work.
// This is my code used in my Twitter connection, and working well for me.
// KeithF's code was a big help!
//
// This is a category added to NSData.
#implementation NSData (EOUtil)
- (NSData*)dataByHmacSHA1EncryptingWithKey:(NSData*)key
{
void* buffer = malloc(CC_SHA1_DIGEST_LENGTH);
CCHmac(kCCHmacAlgSHA1, [key bytes], [key length], [self bytes], [self length], buffer);
return [NSData dataWithBytesNoCopy:buffer length:CC_SHA1_DIGEST_LENGTH freeWhenDone:YES];
}
#end
Take a look at CocoaCryptoHashing for the SHA1 encoding
I posted one solution to this here, that returns the Base64 encoded data that AWS requests.
Apple's iOS developer library has provided an excellent sample titled CryptoExercise which includes a simple function:
- (NSData *)getHashBytes:(NSData *)plainText" to get a SHA-1 hash.
You can see this
maybe it helps you.