I am uploading an image to PHP from an iPhone but in PHP the image is not visible. The image was saving in bytes.
-(void)uploadMyImage:(UIImage *)img
{
NSData *data = UIImageJPEGRepresentation(img, 90);
NSMutableString *urlString = [[NSMutableString alloc] init];
[Base64 initialize];
[urlString appendFormat:#"image=%#",[Base64 encode:data]];
NSString *baseurl = #"http://projectleads.info/spirits/images/imageupload1.php" ;
NSData *postData = [urlString dataUsingEncoding:NSUTF8StringEncoding];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSURL *url = [NSURL URLWithString:baseurl];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
[urlRequest setHTTPMethod: #"POST"];
[urlRequest setValue:postLength forHTTPHeaderField:#"Content-Length"];
[urlRequest setValue:#"application/x-www-form-urlencoded"
forHTTPHeaderField:#"Content-Type"];
[urlRequest setHTTPBody:postData];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:urlRequest delegate:self];
[connection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
resData=[[NSMutableData alloc]init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[resData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString* newStr = [[NSString alloc] initWithData:resData
encoding:NSUTF8StringEncoding];
}
And my php code is
<?php
$base=$_REQUEST['image'];
if(empty($base))
{
echo 'No data';
}
else
{
echo $base;
$binary=base64_decode($base);
header('Content-Type: bitmap; charset=utf-8');
// print($binary);
//$theFile = base64_decode($image_data);
$dbser='localhost';
$dbuser='spirit';
$dbpwd='123456';
$dbname='spirit';
$db= mysql_connect($dbser,$dbuser,$dbpwd);
$dbcon=mysql_select_db($dbname);
function generate_chars()
{
$num_chars = 4; //max length of random chars
$i = 0;
$my_keys = "123456789abcdefghijklmnopqrstuvwxyz"; //keys to be chosen from
$keys_length = strlen($my_keys);
$url = "";
while($i<$num_chars)
{
$rand_num = mt_rand(1, $keys_length-1);
$url .= $my_keys[$rand_num];
$i++;
}
return $url;
}
function isUnique($chars)
{
//check the uniqueness of the chars
global $link;
$q = "SELECT * FROM `url` WHERE `randname`='".$chars."'";
$r = mysql_query($q, $link);
//echo mysql_num_rows($r); die();
if( mysql_num_rows($r)>0 ):
return false;
else:
return true;
endif;
}
$chars = generate_chars();
while( !isUnique($chars) )
{
$chars = generate_chars();
}
$query=mysql_query("insert into url (randname) values ('".$chars."')");
$test=$chars.".jpg";
$file = fopen($test, 'wb');
fwrite($file, $binary);
fclose($file);
echo 'success';
echo '<img src=test.jpg>';
}
?>
For iPhone :
Check here How to upload Image on PHP Server
Also this Upload Image
And For converting UIImage into String using Base64 Ecoding use Base64 Ecoding Method
I hope this will helps You
Your PHP code is just fine, the problem is in the base 64 encoding. I have successfully uploaded an image with your code, do the following to correctly encode the data.
Copy and paste this method in your code (taken from Creating a base-64 string from NSData)
- (NSString*)base64forData:(NSData*) theData {
const uint8_t* input = (const uint8_t*)[theData bytes];
NSInteger length = [theData length];
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
NSInteger i;
for (i=0; i < length; i += 3) {
NSInteger value = 0;
NSInteger j;
for (j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger theIndex = (i / 3) * 4;
output[theIndex + 0] = table[(value >> 18) & 0x3F];
output[theIndex + 1] = table[(value >> 12) & 0x3F];
output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}
Now to get the encoded string do
NSString *encodedString = [[self base64forData:data] stringByReplacingOccurrencesOfString:#"+" withString:#"%2B"];
Append the encoded string as follows
[urlString appendFormat:#"image=%#", encodedString];
Related
I am trying to do AES128 encryption with key and iv and then convert into hex string.My problem is that when I encrypt string into aes128 and convert into hex it give me a hex string.but when i try this same thing in php I am getting diffrent hex string.So when I try to decrypt php hex string, its decrypted successfully. But when I try to decrypt my hex string in php it's give me special characters.
NSString *str = #"hello";
NSString *key = #"1234abcd5678abcd1234abcd5678abcd";
NSString *IV = #"1234567812345678";
NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];
NSData* responseData = [data AES128EncryptedDataWithKey:key iv:IV];
NSLog(#"%#",[self hexRepresentationWithSpaces_AS:NO withdata:responseData]);
- (NSData *)AES128Operation:(CCOperation)operation key:(NSString *)key iv:(NSString *)iv
{
char keyPtr[kCCKeySizeAES128 + 1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
char ivPtr[kCCBlockSizeAES128 + 1];
bzero(ivPtr, sizeof(ivPtr));
if (iv) {
[iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
}
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(operation,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
keyPtr,
kCCBlockSizeAES128,
ivPtr,
[self bytes],
dataLength,
buffer,
bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}
-(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces withdata:(NSData*)data
{
const unsigned char* bytes = (const unsigned char*)[data bytes];
NSUInteger nbBytes = [data length];
//If spaces is true, insert a space every this many input bytes (twice this many output characters).
static const NSUInteger spaceEveryThisManyBytes = 4UL;
//If spaces is true, insert a line-break instead of a space every this many spaces.
static const NSUInteger lineBreakEveryThisManySpaces = 4UL;
const NSUInteger lineBreakEveryThisManyBytes = spaceEveryThisManyBytes * lineBreakEveryThisManySpaces;
NSUInteger strLen = 2*nbBytes + (spaces ? nbBytes/spaceEveryThisManyBytes : 0);
NSMutableString* hex = [[NSMutableString alloc] initWithCapacity:strLen];
for(NSUInteger i=0; i<nbBytes; ) {
[hex appendFormat:#"%02X", bytes[i]];
//We need to increment here so that the every-n-bytes computations are right.
++i;
if (spaces) {
if (i % lineBreakEveryThisManyBytes == 0) [hex appendString:#"\n"];
else if (i % spaceEveryThisManyBytes == 0) [hex appendString:#" "];
}
}
return hex ;
}
and In php I am using
$td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
mcrypt_generic_init($td, $key, $iv);
$encrypted = mcrypt_generic($td, $str);
mcrypt_generic_deinit($td);
// mcrypt_module_close($td);
echo $hexdata = bin2hex($encrypted);
echo "<br>";
$bindata = '';
for ($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
echo $bindata;
echo "<br>";
mcrypt_generic_init($td, $key, $iv);
$decrypted = mdecrypt_generic($td,$encrypted);
mcrypt_generic_deinit($td);
echo "encrypted : ".$encrypted;
echo "<br>";
echo "decrypted : ".$decrypted;
mcrypt is a very old library that does not even implement PKCS#7 compatible padding, which you are obviously using in your iOS code. So at the end you are left with a character representation of the padding, which will probably replaced with replacement characters.
A wrong IV will result in 16 characters being wrong, a wrong key in all characters being wrong. You may also want to match the UTF-8 encoding to be able to display characters with a code point above 0x7F.
I am trying to AES128 encryption of a string or NSDictaionary, using following code
NSString *str =#"Hello";
NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];
NSData *cipher = [data AES128EncryptWithKey:key];
//After that I converts nsdata into hex string
NSLog(#"%#",[self hexRepresentationWithSpaces_AS:NO withdata:cipher]);
-(NSData *)AES128EncryptWithKey:(NSString *)key
{
// ‘key’ should be 16 bytes for AES128
char keyPtr[kCCKeySizeAES128 + 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];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That’s why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc( bufferSize );
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt( kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
#"1234567812345678" /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted );
if( cryptStatus == kCCSuccess )
{
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free( buffer ); //free the buffer
return nil;
}
-(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces withdata:(NSData*)data
{
const unsigned char* bytes = (const unsigned char*)[data bytes];
NSUInteger nbBytes = [data length];
//If spaces is true, insert a space every this many input bytes (twice this many output characters).
static const NSUInteger spaceEveryThisManyBytes = 4UL;
//If spaces is true, insert a line-break instead of a space every this many spaces.
static const NSUInteger lineBreakEveryThisManySpaces = 4UL;
const NSUInteger lineBreakEveryThisManyBytes = spaceEveryThisManyBytes * lineBreakEveryThisManySpaces;
NSUInteger strLen = 2*nbBytes + (spaces ? nbBytes/spaceEveryThisManyBytes : 0);
NSMutableString* hex = [[NSMutableString alloc] initWithCapacity:strLen];
for(NSUInteger i=0; i<nbBytes; ) {
[hex appendFormat:#"%02X", bytes[i]];
//We need to increment here so that the every-n-bytes computations are right.
++i;
if (spaces) {
if (i % lineBreakEveryThisManyBytes == 0) [hex appendString:#"\n"];
else if (i % spaceEveryThisManyBytes == 0) [hex appendString:#" "];
}
}
return hex ;
}
On server side following decryption code added
function decrypt($code) {
//$key = $this->hex2bin($key);
$code = $this->hex2bin($code);
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$decrypted = mdecrypt_generic($td, $code);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return utf8_encode(trim($decrypted));
}
protected function hex2bin($hexdata) {
$bindata = '';
for ($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}
I problem is that on generated encrypt string not decrypting in php
WE are trying to follow this link
Take a look at this code, it will decrypt & encrypt clear text in both ways using AES128 (Rijndael) with CBC and PKCS7 Padding in PHP and C using CommonCrypto in OSX/iOS and MCRYPT in PHP:
OSX/iOS Code in C:
#include <CommonCrypto/CommonCryptor.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* Encrypt text */
char *encryptText(const unsigned char *clearText, char myKey[20], char myIv[20])
{
CCCryptorStatus status;
unsigned char cipherKey[kCCKeySizeAES128];
unsigned char cipherIv[kCCKeySizeAES128];
unsigned char cipherText[strlen((const char *)clearText) + kCCBlockSizeAES128];
size_t nEncrypted;
for (int i=0 ; i<kCCKeySizeAES128; i++)
{
cipherKey[i] = myKey[i];
cipherIv[i] = myIv[i];
}
status = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, cipherKey, kCCKeySizeAES128, cipherIv, clearText, strlen((const char *)clearText), cipherText, sizeof(cipherText), &nEncrypted);
if (status != kCCSuccess)
{
printf("CCCrypt() failed with error %d\n", status);
}
size_t cipherSize = nEncrypted;
char *encoded_data = b64_encode((const unsigned char*)cipherText, cipherSize);
return encoded_data;
}
/* Decrypt text */
int decode(unsigned char *dest, const char *buf)
{
char b[3];
int i;
b[2] = 0;
for(i=0; buf[i] ;i+=2)
{
b[0] = buf[i];
b[1] = buf[i+1];
dest[i/2] = (int) strtol(b, NULL, 0x10);
}
return 0;
}
char *decryptText(const unsigned char *cipherText, char myKey[20], char myIv[20])
{
unsigned char cipherKey[kCCKeySizeAES128];
unsigned char cipherIv[kCCKeySizeAES128];
for (int i=0 ; i<kCCKeySizeAES128; i++)
{
cipherKey[i] = myKey[i];
cipherIv[i] = myIv[i];
}
int lenKey = strlen((const char *)cipherKey);
char hex_key[(lenKey*2)+1];
char2hex((char *)cipherKey, hex_key);
int lenIv = strlen((const char *)cipherIv);
char hex_iv[(lenIv*2)+1];
char2hex((char *)cipherIv, hex_iv);
size_t cipherSize = strlen((const char *)cipherText);
unsigned char *decoded_data = b64_decode((const char*)cipherText, cipherSize);
int lenData = strlen((const char *)decoded_data);
char *hexcipherText;
hexcipherText = bin2hex(decoded_data, lenData);
CCCryptorStatus status;
int len = strlen((const char *)hexcipherText) / 2;
unsigned char clearText[len];
unsigned char decodedCipherText[len];
unsigned char decodedKey[len];
unsigned char decodedIv[len];
size_t nDecrypted;
int i;
decode(decodedKey, (const char *)hex_key);
decode(decodedCipherText, (const char *)hexcipherText);
decode(decodedIv, (const char *)hex_iv);
status = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, decodedKey, kCCKeySizeAES128, decodedIv, decoded_data, len, clearText, sizeof(clearText), &nDecrypted);
if (status != kCCSuccess)
{
printf("CCCrypt() failed with error %d\n", status);
}
int extraInfo = strlen((const char *)clearText);
char* toReturn = malloc(extraInfo + 1);
strcpy(toReturn, (const char *)clearText);
strcat(toReturn, "\0");
return toReturn;
}
Note the base64 encode & decode function (b64_encode, b64_decode):
#ifdef b64_USE_CUSTOM_MALLOC
extern void* b64_malloc(size_t);
#endif
#ifdef b64_USE_CUSTOM_REALLOC
extern void* b64_realloc(void*, size_t);
#endif
int bufc = 0;
char* b64_buf_malloc()
{
char* buf = b64_malloc(B64_BUFFER_SIZE);
bufc = 1;
return buf;
}
char* b64_buf_realloc(unsigned char* ptr, size_t size)
{
if (size > bufc * B64_BUFFER_SIZE)
{
while (size > bufc * B64_BUFFER_SIZE) bufc++;
char* buf = b64_realloc(ptr, B64_BUFFER_SIZE * bufc);
if (!buf) return NULL;
return buf;
}
return (char *)ptr;
}
/* Encode in b64 */
char *b64_encode(const unsigned char *src, size_t len)
{
int i = 0;
int j = 0;
char *enc = NULL;
size_t size = 0;
unsigned char buf[4];
unsigned char tmp[3];
enc = (char *) b64_buf_malloc();
if (NULL == enc) { return NULL; }
while (len--)
{
tmp[i++] = *(src++);
if (3 == i)
{
buf[0] = (tmp[0] & 0xfc) >> 2;
buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
buf[3] = tmp[2] & 0x3f;
enc = (char *) b64_buf_realloc((unsigned char *)enc, size + 4);
for (i = 0; i < 4; ++i)
{
enc[size++] = b64_table[buf[i]];
}
i = 0;
}
}
if (i > 0)
{
for (j = i; j < 3; ++j)
{
tmp[j] = '\0';
}
buf[0] = (tmp[0] & 0xfc) >> 2;
buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
buf[3] = tmp[2] & 0x3f;
for (j = 0; (j < i + 1); ++j)
{
enc = (char *) b64_buf_realloc((unsigned char *)enc, size + 1);
enc[size++] = b64_table[buf[j]];
}
while ((i++ < 3))
{
enc = (char *) b64_buf_realloc((unsigned char *)enc, size + 1);
enc[size++] = '=';
}
}
enc = (char *) b64_buf_realloc((unsigned char *)enc, size + 1);
enc[size] = '\0';
return enc;
}
/* Decode b64 */
unsigned char *b64_decode(const char *src, size_t len)
{
return b64_decode_ex(src, len, NULL);
}
unsigned char *b64_decode_ex(const char *src, size_t len, size_t *decsize)
{
int i = 0;
int j = 0;
int l = 0;
size_t size = 0;
unsigned char *dec = NULL;
unsigned char buf[3];
unsigned char tmp[4];
dec = (unsigned char *) b64_buf_malloc();
if (NULL == dec) { return NULL; }
while (len--)
{
if ('=' == src[j]) { break; }
if (!(isalnum(src[j]) || '+' == src[j] || '/' == src[j])) { break; }
tmp[i++] = src[j++];
if (4 == i)
{
for (i = 0; i < 4; ++i)
{
for (l = 0; l < 64; ++l)
{
if (tmp[i] == b64_table[l])
{
tmp[i] = l;
break;
}
}
}
buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
dec = (unsigned char *) b64_buf_realloc(dec, size + 3);
if (dec != NULL)
{
for (i = 0; i < 3; ++i)
{
dec[size++] = buf[i];
}
}
else
{
return NULL;
}
i = 0;
}
}
if (i > 0)
{
for (j = i; j < 4; ++j)
{
tmp[j] = '\0';
}
for (j = 0; j < 4; ++j)
{
for (l = 0; l < 64; ++l)
{
if (tmp[j] == b64_table[l])
{
tmp[j] = l;
break;
}
}
}
buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
dec = (unsigned char *)b64_buf_realloc(dec, size + (i - 1));
if (dec != NULL)
{
for (j = 0; (j < i - 1); ++j)
{
dec[size++] = buf[j];
}
}
else
{
return NULL;
}
}
dec = (unsigned char *)b64_buf_realloc(dec, size + 1);
if (dec != NULL)
{
dec[size] = '\0';
}
else
{
return NULL;
}
if (decsize != NULL)
{
*decsize = size;
}
return dec;
}
Also note the bin2hex & char2hex function:
/* Char to Hex conversion */
void char2hex(char* input, char* output)
{
int loop;
int i;
i=0;
loop=0;
while(input[loop] != '\0')
{
sprintf((char*)(output+i),"%02X", input[loop]);
loop+=1;
i+=2;
}
output[i++] = '\0';
}
/* Bin to Hex conversion */
static char hexconvtab[] = "0123456789abcdef";
static char* bin2hex(const unsigned char *old, const size_t oldlen)
{
char *result = (char*) malloc(oldlen * 2 + 1);
size_t i, j;
for (i = j = 0; i < oldlen; i++)
{
result[j++] = hexconvtab[old[i] >> 4];
result[j++] = hexconvtab[old[i] & 15];
}
result[j] = '\0';
return result;
}
Now, the PHP Code:
/* Encrypt text */
function encRijndael($text, $key, $iv)
{
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$padding = $block - (strlen($text) % $block);
$text .= str_repeat(chr($padding), $padding);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);
return base64_encode($crypttext);
}
/* Decrypt Text */
function decRijndael($encrypted, $key, $iv)
{
$iv_utf = mb_convert_encoding($iv, 'UTF-8');
$toreturn = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($encrypted), MCRYPT_MODE_CBC, $iv_utf);
$toreturn = filter_var($toreturn, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
return $toreturn;
}
I learned this code reading the book O'Reilly, Hacking and Securing iOS Applications from Jonathan Zdziarski.
I tried looking through all of the other questions and nothing seemed to fix this issue. I have narrowed it down so the response from https://sandbox.itunes.apple.com/verifyReceipt is simply {"status":21002}. Any help would be greatly appreciated, I've copied the related code below.
NSString *completeString = #"http://www.mysite.com/verify.php";
NSURL *urlForValidation = [NSURL URLWithString:completeString];
NSMutableURLRequest *validationRequest = [[NSMutableURLRequest alloc] initWithURL:urlForValidation];
[validationRequest setHTTPMethod:#"POST"];
NSString *strTest = [NSString stringWithFormat:#"receipt=%#", [self createEncodedString:transaction.transactionReceipt]];
[validationRequest setHTTPBody:[NSData dataFromBase64String:strTest]];
NSData *responseData = [NSURLConnection sendSynchronousRequest:validationRequest returningResponse:nil error:nil];
NSString *response = [[NSString alloc] initWithData: responseData encoding: NSUTF8StringEncoding];
NSLog(#"%#", response);
- (NSString*) createEncodedString:(NSData*)data {
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
const int size = ((data.length + 2)/3)*4;
uint8_t output[size];
const uint8_t* input = (const uint8_t*)[data bytes];
for (int i = 0; i < data.length; i += 3)
{
int value = 0;
for (int j = i; j < (i + 3); j++)
{
value <<= 8;
if (j < data.length)
value |= (0xFF & input[j]);
}
const int index = (i / 3) * 4;
output[index + 0] = table[(value >> 18) & 0x3F];
output[index + 1] = table[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < data.length ? table[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < data.length ? table[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithBytes:output length:size encoding:NSASCIIStringEncoding];
}
Finally this is the PHP code used:
$url = 'https://sandbox.itunes.apple.com/verifyReceipt';
$receipt = "{%s}" % $_POST["receipt"];
$purchase_encoded = base64_encode( $receipt );
$encodedData = json_encode( Array(
'receipt-data' => $purchase_encoded
) );
//Open a Connection using POST method, as it is required to use POST method.
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $encodedData);
$encodedResponse = curl_exec($ch);
curl_close($ch);
//Decode response data using json_decode method to get an object.
echo $encodedResponse;
$response = json_decode( $encodedResponse );
echo $response;
After a lot of fiddling I was able to figure it out. I believe the biggest error was with how I was setting the HTTP body. Finalized code is below, hopefully this can help someone else out!
Objective-C:
NSString *completeString = #"http://www.mysite.com/verify.php";
NSURL *urlForValidation = [NSURL URLWithString:completeString];
NSMutableURLRequest *validationRequest = [[NSMutableURLRequest alloc] initWithURL:urlForValidation];
[validationRequest setHTTPMethod:#"POST"];
NSString *strTest = [NSString stringWithFormat:#"receipt=%#", [self base64forData:transaction.transactionReceipt]];
[validationRequest setHTTPBody:[strTest dataUsingEncoding:NSUTF8StringEncoding]];
NSData *responseData = [NSURLConnection sendSynchronousRequest:validationRequest returningResponse:nil error:nil];
NSString *response = [[NSString alloc] initWithData: responseData encoding: NSUTF8StringEncoding];
NSLog(#"%#", response);
PHP:
$url = 'https://sandbox.itunes.apple.com/verifyReceipt';
$encodedData = json_encode( Array(
'receipt-data' => $_POST["receipt"]
) );
//Open a Connection using POST method, as it is required to use POST method.
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $encodedData);
$encodedResponse = curl_exec($ch);
curl_close($ch);
$response = json_decode( $encodedResponse );
/*
echo "Status Code:";
echo $response->{'status'};
*/
if ($response->{'status'} != 0) {
echo "FAIL";
} else {
echo "SUCCESS";
}
nlutterman's answer is correct! It helped me so much.
In case anyone is trying to get his solution to work, it would only work if you use the following method to encode the receipt data to base64 (in-app).
- (NSString*)base64forData:(NSData*)theData {
const uint8_t* input = (const uint8_t*)[theData bytes];
NSInteger length = [theData length];
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
NSInteger i;
for (i=0; i < length; i += 3) {
NSInteger value = 0;
NSInteger j;
for (j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger theIndex = (i / 3) * 4;
output[theIndex + 0] = table[(value >> 18) & 0x3F];
output[theIndex + 1] = table[(value >> 12) & 0x3F];
output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; }
The normal base64EncodedStringWithOptions: wouldn't work.
I am trying to make a equilvant of these php functions to encrype/decrypt in objective c but with no luck so far.
I counld't find any base64_en/decode methods in obj-c, is there any?
function encrypt($string, $key) {
$result = '';
 for($i = 0; $i < strlen($string); $i++) {
$char = substr($string, $i, 1);
$keychar = substr($key, ($i % strlen($key))-1, 1);
$char = chr(ord($char) + ord($keychar));
$result .= $char;
 }

return base64_encode($result);
}
function decrypt($string, $key) {
$result = '';
$string = base64_decode($string);
for($i = 0; $i < strlen($string); $i++) {
$char = substr($string, $i, 1);
$keychar = substr($key, ($i % strlen($key))-1, 1);
$char = chr(ord($char) - ord($keychar));
$result.=$char;
}
return $result;
}
Ty already!
Check out this category I use for this very task, it's an NSString category for converting strings to md5, base64 etc...
https://gist.github.com/3907443
From NSString to NSData:
+ (NSString *)encodeBase64WithString:(NSString *)strData {
return [NSString encodeBase64WithData:[strData dataUsingEncoding:NSUTF8StringEncoding]];
}
Encode from NSData:
+ (NSString *)encodeBase64WithData:(NSData *)objData {
const unsigned char * objRawData = [objData bytes];
char * objPointer;
char * strResult;
// Get the Raw Data length and ensure we actually have data
int intLength = [objData length];
if (intLength == 0) return nil;
// Setup the String-based Result placeholder and pointer within that placeholder
strResult = (char *)calloc(((intLength + 2) / 3) * 4, sizeof(char));
objPointer = strResult;
// Iterate through everything
while (intLength > 2) { // keep going until we have less than 24 bits
*objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
*objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
*objPointer++ = _base64EncodingTable[((objRawData[1] & 0x0f) << 2) + (objRawData[2] >> 6)];
*objPointer++ = _base64EncodingTable[objRawData[2] & 0x3f];
// we just handled 3 octets (24 bits) of data
objRawData += 3;
intLength -= 3;
}
// now deal with the tail end of things
if (intLength != 0) {
*objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
if (intLength > 1) {
*objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
*objPointer++ = _base64EncodingTable[(objRawData[1] & 0x0f) << 2];
*objPointer++ = '=';
} else {
*objPointer++ = _base64EncodingTable[(objRawData[0] & 0x03) << 4];
*objPointer++ = '=';
*objPointer++ = '=';
}
}
// Terminate the string-based result
*objPointer = '\0';
// Return the results as an NSString object
return [NSString stringWithCString:strResult encoding:NSASCIIStringEncoding];
}
Decode:
+ (NSData *)decodeBase64WithString:(NSString *)strBase64 {
const char * objPointer = [strBase64 cStringUsingEncoding:NSASCIIStringEncoding];
int intLength = strlen(objPointer);
int intCurrent;
int i = 0, j = 0, k;
unsigned char * objResult;
objResult = calloc(intLength, sizeof(char));
// Run through the whole string, converting as we go
while ( ((intCurrent = *objPointer++) != '\0') && (intLength-- > 0) ) {
if (intCurrent == '=') {
if (*objPointer != '=' && ((i % 4) == 1)) {// || (intLength > 0)) {
// the padding character is invalid at this point -- so this entire string is invalid
free(objResult);
return nil;
}
continue;
}
intCurrent = _base64DecodingTable[intCurrent];
if (intCurrent == -1) {
// we're at a whitespace -- simply skip over
continue;
} else if (intCurrent == -2) {
// we're at an invalid character
free(objResult);
return nil;
}
switch (i % 4) {
case 0:
objResult[j] = intCurrent << 2;
break;
case 1:
objResult[j++] |= intCurrent >> 4;
objResult[j] = (intCurrent & 0x0f) << 4;
break;
case 2:
objResult[j++] |= intCurrent >>2;
objResult[j] = (intCurrent & 0x03) << 6;
break;
case 3:
objResult[j++] |= intCurrent;
break;
}
i++;
}
// mop things up if we ended on a boundary
k = j;
if (intCurrent == '=') {
switch (i % 4) {
case 1:
// Invalid state
free(objResult);
return nil;
case 2:
k++;
// flow through
case 3:
objResult[k] = 0;
}
}
// Cleanup and setup the return NSData
NSData * objData = [[[NSData alloc] initWithBytes:objResult length:j] autorelease];
free(objResult);
return objData;
}
I have spent a huge amount of time with no success trying to decrypt an encrypted string ("yIH7EYW0e4HuxkHApkG7xQ==") on the PHP server side. The string was encrypted on iOS platform and encoded into text using base64 format.
Anyway, could someone please correct my mistake with the PHP side (I am a little weak on this side)? I am aware the method is not very secure as is. I just need a temporary solution until I can research better methods with openssl.
PHP:
$str_encrypted = "yIH7EYW0e4HuxkHApkG7xQ=="; // base64encoded
$mykey = "my password";
$decrypted = decrypt_data($str_encrypted =, $mykey);
function decrypt_data($str_encrypted =, $mykey)
{
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypted_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $encryptionkey, $text, MCRYPT_MODE_ECB, $iv);
return $decrypted_text;
}
IOS:
- (NSString *)AES128EncryptWithKey:(NSString *)key
{
NSData *plainData = [self dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [plainData AES128EncryptWithKey:key];
NSString *encryptedString = [encryptedData base64Encoding];
return encryptedString;
}
IOS:
- (NSString *)base64Encoding
{
const unsigned char *bytes = [self bytes];
NSMutableString *result = [NSMutableString stringWithCapacity:self.length];
unsigned long ixtext = 0;
unsigned long lentext = self.length;
long ctremaining = 0;
unsigned char inbuf[3], outbuf[4];
unsigned short i = 0;
unsigned short charsonline = 0, ctcopy = 0;
unsigned long ix = 0;
while( YES )
{
ctremaining = lentext - ixtext;
if( ctremaining <= 0 ) break;
for( i = 0; i < 3; i++ )
{
ix = ixtext + i;
if( ix < lentext ) inbuf[i] = bytes[ix];
else inbuf [i] = 0;
}
outbuf [0] = (inbuf [0] & 0xFC) >> 2;
outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
outbuf [3] = inbuf [2] & 0x3F;
ctcopy = 4;
switch( ctremaining )
{
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for( i = 0; i < ctcopy; i++ )
[result appendFormat:#"%c", encodingTable[outbuf[i]]];
for( i = ctcopy; i < 4; i++ )
[result appendString:#"="];
ixtext += 3;
charsonline += 4;
}
return [NSString stringWithString:result];
}