iPhone and HMAC-SHA-1 encoding - iphone

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.

Related

iPhone encrypt function that would be decrypt on php server

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.

Encode and Decode using UTF-8 in iPhone

I'm looking for an example demonstrating how I can encode and then decode the same string using UTF-8. Encode and then Decode means I want to implement the methods in 2 areas where one can encode it and another is able to decode it.
I have seen the API but I didn't get much success:
stringWithCString:encoding:
stringWithUTF8String:
stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;
EDITED
I have the string øæ-test-2.txt which I am encoding as follows:
char *s = "øæ-test-2.txt";
NSString *enc = [NSString stringWithCString:s encoding:NSASCIIStringEncoding];
but am getting øæ-test-2.txt as output.
Now I want to get back the original string back i.e. øæ-test-2.txt
EDITED
I am getting øæ-test-2.txt from server and I need øæ-test-2.txt by decoding it. I am able to get the output from the link : http://www.cafewebmaster.com/online_tools/utf_decode
Please try to use the link and you will understand my concern.
It would be highly appreciated if anyone can give some hint, tutorial or point me in the right direction.
Regards
To turn an NSString object into a UTF8 C-string, use UTF8String
char *utf8string = [#"A string with ümläuts" UTF8String];
To turn a UTF8 C-string into an NSString object, use stringWithUTF8String: or initWithUTF8String:
NSString *string = [NSString stringWithUTF8String:utf8string];
Note that NSString objects are implemented as UTF-16, so you can't really have a "UTF-8 NSString" (and the encoding should be treated as an implementation detail, anyway).
Instead of
char *utf8string = [#"A string with ümläuts" UTF8String];
This should be
const char *utf8string = [#"A string with ümläuts" UTF8String];
Otherwise you have an incompatible type issue.

Encrypting streaming content onto persistent storage and decrypting it to the stream on iPhone

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.

Compress/Decompress NSString in objective-c (iphone) using GZIP or deflate

I have a web-service running on Windows Azure which returns JSON that I consume in my iPhone app.
Unfortunately, Windows Azure doesn't seem to support the compression of dynamic responses yet (long story) so I decided to get around it by returning an uncompressed JSON package, which contains a compressed (using GZIP) string.
e.g
{"Error":null,"IsCompressed":true,"Success":true,"Value":"vWsAAB+LCAAAAAAAB..etc.."}
... where value is the compressed string of a complex object represented in JSON.
This was really easy to implement on the server, but for the life of me I can't figure out how to decompress a gzipped NSString into an uncompressed NSString, all the examples I can find for zlib etc are dealing with files etc.
Can anyone give me any clues on how to do this? (I'd also be happy for a solution that used deflate as I could change the server-side implementation to use deflate too).
Thanks!!
Steven
Edit 1: Aaah, I see that ASIHTTPRequest is using the following function in it's source code:
//uncompress gzipped data with zlib
+ (NSData *)uncompressZippedData:(NSData*)compressedData;
... and I'm aware that I can convert NSString to NSData, so I'll see if this leads me anywhere!
Edit 2: Unfortunately, the method described in Edit 1 didn't lead me anywhere.
Edit 3: Following the advice below regarding base64 encoding/decoding, I came up with the following code. The encodedGzippedString is as you can guess, a string "Hello, my name is Steven Elliott" which is gzipped and then converted to a base64 string. Unfortunately, the result that prints using NSLog is just blank.
NSString *encodedGzippedString = #"GgAAAB+LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee++997o7nU4n99//P1xmZAFs9s5K2smeIYCqyB8/fnwfPyK+uE6X2SJPiyZ93eaX+TI9Lcuiatvx/wOwYc0HGgAAAA==";
NSData *decodedGzippedData = [NSData dataFromBase64String:encodedGzippedString];
NSData* unGzippedJsonData = [ASIHTTPRequest uncompressZippedData:decodedGzippedData];
NSString* unGzippedJsonString = [[NSString alloc] initWithData:unGzippedJsonData encoding:NSASCIIStringEncoding];
NSLog(#"Result: %#", unGzippedJsonString);
After all this time, I finally found a solution to this problem!
None of the answers above helped me, as promising as they all looked. In the end, I was able to compress the string on the server with gzip using the chilkat framework for .net ... and then decompress it on the iphone using the chilkat framework for iOS (not yet released, but available if you email the guy directly).
The chilkat framework made this super easy to do so big thumbs up to the developer!
Your "compressed" string is not raw GZIP'd data, it's in some encoding that allows those bytes to be stored in a string-- looks like base-64 or something like it. To get an NSData out of this, you'll need to decode it into the NSData.
If it's really base-64, check out this blog post an accompanying code:
http://cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html
which will do what you want.
Once you have an NSData object, the ASIHTTPRequest method will probably do as you like.
This worked for me:
from a string gzipeed, then base64 encoded
to un-gzipped string (all utf8).
#import "base64.h"
#import "NSData+Compression.h"
...
+(NSString *)gunzipBase64StrToStr:(NSString *)stringValue {
//now we decode from Base64
Byte inputData[[stringValue lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];//prepare a Byte[]
[[stringValue dataUsingEncoding:NSUTF8StringEncoding] getBytes:inputData];//get the pointer of the data
size_t inputDataSize = (size_t)[stringValue length];
size_t outputDataSize = EstimateBas64DecodedDataSize(inputDataSize);//calculate the decoded data size
Byte outputData[outputDataSize];//prepare a Byte[] for the decoded data
Base64DecodeData(inputData, inputDataSize, outputData, &outputDataSize);//decode the data
NSData *theData = [[NSData alloc] initWithBytes:outputData length:outputDataSize];//create a NSData object from the decoded data
//NSLog(#"DATA: %# \n",[theData description]);
//And now we gunzip:
theData=[theData gzipInflate];//make bigger==gunzip
return [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding];
}
#end
I needed to compress data on the iPhone using Objective-c and decompress on PHP. Here is what I used in XCode 11.5 and iOS 12.4:
iOS Objective-c Compression Decompression Test
Include libcompression.tbd in the Build Phases -> Link Binary With Library. Then include the header.
#include "compression.h"
NSLog(#"START META DATA COMPRESSION");
NSString *testString = #"THIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TESTTHIS IS A COMPRESSION TEST";
NSData *theData = [testString dataUsingEncoding:NSUTF8StringEncoding];
size_t src_size = theData.length;
uint8_t *src_buffer = (uint8_t*)[theData bytes];
size_t dst_size = src_size+4096;
uint8_t *dst_buffer = (uint8_t*)malloc(dst_size);
dst_size = compression_encode_buffer(dst_buffer, dst_size, src_buffer, src_size, NULL, COMPRESSION_ZLIB);
NSLog(#"originalsize:%zu compressed:%zu", src_size, dst_size);
NSData *dataData = [NSData dataWithBytes:dst_buffer length:sizeof(dst_buffer)];
NSString *compressedDataBase64String = [dataData base64EncodedStringWithOptions:0];
NSLog(#"Compressed Data %#", compressedDataBase64String);
NSLog(#"START META DATA DECOMPRESSION");
src_size = compression_decode_buffer(src_buffer, src_size, dst_buffer, dst_size, NULL, COMPRESSION_ZLIB);
NSData *decompressed = [[NSData alloc] initWithBytes:src_buffer length:src_size];
NSString *decTestString;
decTestString = [[NSString alloc] initWithData:decompressed encoding:NSASCIIStringEncoding];
NSLog(#"DECOMPRESSED DATA %#", decTestString);
free(dst_buffer);
On the PHP side I used the following function to decompress the data:
function decompressString($compressed_string) {
//NEED RAW GZINFLATE FOR COMPATIBILITY WITH IOS COMPRESSION_ZLIB WITH IETF RFC 1951
$full_string = gzinflate($compressed_string);
return $full_string;
}

encrypt data on iphone and dencrypt on a .net web application

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.