I have to generate encrypted key on my php server and send it to the ipad app to decrypt it.
What I did in the php server side :
$iv = mcrypt_create_iv(32);
$privatEencryptKey = "1111";
$data = "2222";
$encryptedData = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $privateEncryptKey, base64_encode($data), MCRYPT_MODE_CBC, $iv);
$decryptedData = base64_decode(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $privateEncryptkey, $encryptedData, MCRYPT_MODE_CBC, $iv));
echo base64_encode($encryptedData); //output = WT7LorzZ1EQo2BeWxawW3Q==
echo $decryptedData; // output = 2222
echo base64_encode($iv); // output = fZTj4BxWSdCYQW/scUHvx9QoiTNXmxNrGWb/n7eFkR4=
and in the xcode I import the sercurity.framwork and I added 3rd party for base64 (encoding & decoding) and I use the (CommonCryptor.h) also and here is my code :
+ (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,
0,
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;
}
+ (void) testCipher{
NSData *dataIn = [[#"WT7LorzZ1EQo2BeWxawW3Q==" base64DecodedString] dataUsingEncoding:NSUTF8StringEncoding];
NSData *key = [#"1111" dataUsingEncoding:NSUTF8StringEncoding];
NSData *iv = [[#"fZTj4BxWSdCYQW/scUHvx9QoiTNXmxNrGWb/n7eFkR4=" base64DecodedString] dataUsingEncoding:NSUTF8StringEncoding];
NSData *dataOut = [Utils doCipher:dataIn iv:iv key:key context:kCCDecrypt];
NSString* strOut = [[[NSString alloc] initWithData:dataOut
encoding:NSUTF8StringEncoding] base64DecodedString];
NSLog(#"%#", strOut);
}
I got the nil for strOut..... :(
Any help please......
You should use 16-byte Key and IV for AES-128. Mcrypt_encrypt otherwise pads this with zero.
Most likely you should manually add PKCS#5 padding to the input since the mcrypt_encrypt pads data with zero, which is not common practice.
Related
I need to convert the encryption/decryption method follows in our server side, please check the below code
-------------------------------------------------------------------------------------------------------------------------------------
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "a16byteslongkey!";
$plaintext = "iphone";
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
$ciphertext = base64_encode($ciphertext);
echo "ciphertext: ".$ciphertext."<br/>";
$ciphertextinput = base64_decode($ciphertext);
$cipherdetext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertextinput, MCRYPT_MODE_CBC, $iv);
echo "decryptText:".$cipherdetext."<br/>";
I tried with AES 256 encryption but it gives different results,
Encryption
- (NSData *)AES256EncryptWithKey:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
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];
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, kCCKeySizeAES256,
NULL /* 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;}
Decryption
- (NSData *)AES256DecryptWithKey:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
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 ivPtr = "";
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 numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;}
OriginalText: iphone
ciphertext: SXNepKfh0IrlDDdkq4EdmQ==
Whats wrong here, Please give some suggestion for decrypt encrypted text from PHP. How to get exact "iphone" word from base 64 encode string SXNepKfh0IrlDDdkq4EdmQ==
Also, Please let me know how to use ECB Mode in AES encryption.
Thanks!
The problem:
`mcrypt uses non-standard null data padding, the iOS code is using PKCS#7 padding.
The fix, three choices:
Use PKCS#7 padding, for mcrypt add PKCS#7 padding the prior to encryption and remove it after decryption. (recommended)
or
Use null padding, for Common Crypto do not specify kCCOptionPKCS7Padding, add null padding prior to encryption and remove after decryption. (not recommended)
or
It is best not to use mcrypt, it is abandonware, has not been updated in years and does not support standard PKCS#7 (née PKCS#5) padding, only non-standard null padding that can't even be used with binary data. mcrypt has many outstanding bugs dating back to 2003. The mcrypt-extension is deprecated will be removed in PHP 7.2. Instead consider using defuse or RNCryptor, they provide a complete solution and are being maintained and is correct.
I have a problem ... and It kills me
Below is my code:
PHP
1-I did not use any kind of pre-padding and generated the IV with 16 bytes.
2-I forced the pbkdf2 function to return 8 bytes for key & hmacKey
$key = "myKey";
$plainText = "iphone";
$iv = mcrypt_create_iv(16, MCRYPT_RAND);
$keySalt = '12345678';
$hmacSalt = '12345678';
$_key = pbkdf2('SHA1', $key, $keySalt, 10000, 8, true);
$_hmacKey = pbkdf2('SHA1', $key, $hmacSalt, 10000, 8, true);
$cipherText = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $_key, $plainText, MCRYPT_MODE_CBC, $iv);
$dataWithoutHMAC = chr(2).chr(1).$keySalt.$hmacSalt.$iv.$cipherText;
3-first try I passed the cipher text to the hash_hmac
$data = base64_encode($dataWithoutHMAC.hash_hmac('SHA256',$cipherText,$_hmacKey, true));
and I got "et.robnapier.RNCryptManager error -4301" while decrypting in iOS. "which mean too small buffer as I think"
4-second try I passed the header (chr(2).chr(1).$keySalt.$hmacSalt.$iv) + cipher text to the hash_hmac (but I got the same result for the first try [-4301])
$data = base64_encode($dataWithoutHMAC.hash_hmac('SHA256',$dataWithoutHMAC,$_hmacKey, true));
In iOS
decryptionError = nil;
NSData *fromPHPData = [#"AgExMjM0NTY3ODEyMzQ1Njc4WvrmgsFy6IoWNmm2hYL9N2jNVxU13Eo15cRyQRakRZ9WsjZ2CY/B5y4YkmG9uGdB2vHFpmpjsnm3O4d59Ex7Nw==" base64DecodedData];
NSData *fromPHPDecryptedData = [RNDecryptor decryptData:fromPHPData withPassword:#"myKey" error:&decryptionError];
NSLog(#"decryptionError %#", decryptionError);
NSString *fromPHPEcryptedStr = [fromPHPDecryptedData base64EncodedString];
NSLog(#"data : %#", fromPHPEcryptedStr);
the error I got in iOS is : "The operation couldn’t be completed. (net.robnapier.RNCryptManager error -4301.)"
I am fairly new to this. My PHP echo is returning garbage. I think there's an encoding step I'm missing.
My OBJ-C code
NSString *key = #"12345678901234561234567890123456";
//main path for account login PHP file
NSString *accountURL = [NSString stringWithFormat:configManager.accountURL, username, password];
//convert password to data and encrypt
NSData *crypt = [[[password stringValue]dataUsingEncoding:NSUTF8StringEncoding]AES256EncryptWithKey:key];
NSString *variables = [NSString stringWithFormat:#"?username=%#&access=%#&page=%ld",[username stringValue], crypt, [sender tag]];
// get rid of spaces in encoded URL
NSString *niceURLString = [variables stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//tack niceURL on to end of base URL
NSString *goToURL = [accountURL stringByAppendingString:niceURLString];
NSLog(#"%#", goToURL);
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:goToURL]];
PHP
$upswd = $_GET['access'];
$key = "12345678901234561234567890123456";
$upswd = trim($upswd, "<>"); //remove these brackets from url
$result = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $upswd, 'ecb');
//$result = utf8_decode($result);
echo ($result);
mcrypt_create_iv(
mcrypt_get_iv_size(
MCRYPT_RIJNDAEL_256,
MCRYPT_MODE_ECB
)
You are creating an new IV, you need to use the original IV. It is usually passed along with the encrypted text seperated by a delimiter commonly used delimiters are . or | you then have PHP split the encrypted string at the delimiter, use the IV for the decrypt function and use the other part as the encrypted data.
I've checked all the related Stack Overflow questions. Also checked the links in that answers but didn't got any usable solution.
Here is my php script and I've nothing to do with this script (as I can't change the script).
function encrypt($message,$secretKey) {
return base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_256,
$secretKey,
$message,
MCRYPT_MODE_ECB
)
);
}
I'm unable to decrypt it in Objective C. I've used a number of Categories like Strong Encryption for Cocoa / Cocoa Touch etc, also I followed this question How do I do base64 encoding on iOS?
Here is the objective C codes that I used for decryption (found in cocoa-aes Category NSData+AES.h)
- (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)];
NSString* s = [[NSString alloc] initWithBytes:plaintext length:sizeof(plaintext) encoding:NSASCIIStringEncoding];
NSLog(#"%#",s);
}
return ret;
}
Also I tried this decoder
- (NSData*) aesDecryptWithKey:(NSString *)key initialVector:(NSString*)iv
{
int keyLength = [key length];
if(keyLength != kCCKeySizeAES128)
{
DebugLog(#"key length is not 128/192/256-bits long");
///return nil;
}
char keyBytes[keyLength+1];
bzero(keyBytes, sizeof(keyBytes));
[key getCString:keyBytes maxLength:sizeof(keyBytes) encoding:NSUTF8StringEncoding];
size_t numBytesDecrypted = 0;
size_t decryptedLength = [self length] + kCCBlockSizeAES128;
char* decryptedBytes = malloc(decryptedLength);
CCCryptorStatus result = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128 ,
(iv == nil ? kCCOptionECBMode | kCCOptionPKCS7Padding : kCCOptionPKCS7Padding),
keyBytes,
keyLength,
iv,
[self bytes],
[self length],
decryptedBytes,
decryptedLength,
&numBytesDecrypted);
if(result == kCCSuccess){
NSData* d=[NSData dataWithBytesNoCopy:decryptedBytes length:numBytesDecrypted];
NSLog(#"%#",[NSString stringWithUTF8String:[d bytes]]);
return d;
}
free(decryptedBytes);
return nil;
}
From the looks of it, that php function does two things.
mcrypt using MCRYPT_RIJNDAEL_256
base64 encodes the output of (1)
That would by why simply using base64 doesn't work. I'm going to guess from the name that MCRYPT_RIJNDAEL_256 is just AES 256.
Hope that helps.
Edit:
The code you added above looks ok. You just have to base64 decode the data first.
The php script does this:
aes encrypt
base64 encode
So you want to do this in your cocoa app:
base64 decode
aes decrypt
If you're having trouble, you might want to play around and see if you can get cocoa to do the same thing as the php script: encrypt and base64 encode the data. If you can get the output of your encryption function to be the same as the output of the php encryption function, you're in a good place to get it decrypting.
I want to use AES to encrypt a password in Objective-C, and then decrypt it in PHP, but I have two problems.
I encrypt the password, but it's an NSData object, so I encode it with base64, but when I decode in PHP, the result is nil. So I can't decrypt it.
I can encrypt and decrypt the password in Objective-C, so it is the PHP that is the problem, but when I encrypt with AES and then encode with base64, the results are not the same.
Here is my code:
PHP:
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "a16byteslongkey!";
$plaintext = "iphone";
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_ECB, $iv);
$ciphertext = base64_encode($ciphertext);
echo "ciphertext: ".$ciphertext."<br/>";
$ciphertext = base64_decode($ciphertext);
$plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext, MCRYPT_MODE_ECB, $iv);
echo "plaintext: ".$plaintext."<br/>";
output:
ciphertext: SXNepKfh0IrlDDdkq4EdmQ==
plaintext: iphone
Objective-C: (Get the full source code here: https://gist.github.com/838614)
NSString *key = #"a16byteslongkey!";
NSString *plaintext = #"iphone";
NSString *ciphertext = [plaintext AES256EncryptWithKey: key];
NSLog(#"ciphertext: %#", ciphertext);
plaintext = [ciphertext AES256DecryptWithKey: key];
NSLog(#"plaintext: %#", plaintext);
output:
ciphertext: D19l3gsgXJlrLl7B2oCT6g==
plaintext: iphone
i replace kCCKeySizeAES256 with kCCKeySizeAES128, and replace "kCCOptionPKCS7Padding" with "kCCOptionPKCS7Padding | kCCOptionECBMode",
i have slove the problem.
don't change the code from https://gist.github.com/838614
the key should be 32 byte.
the results of encryt are not the same, but they'll be the same if you decrypt.
objective-c:
NSString *key = #"a16byteslongkey!a16byteslongkey!";
NSString *plaintext = #"iphone";
NSString *ciphertext = [plaintext AES256EncryptWithKey: key];
NSLog(#"ciphertext: %#", ciphertext);
plaintext = [ciphertext AES256DecryptWithKey: key];
NSLog(#"plaintext: %#", plaintext);
output:
ciphertext: I3chV+E2XUHeLCcJAhBaJQ==
plaintext: iphone
php:
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = 'a16byteslongkey!a16byteslongkey!';
$plaintext = "iphone";
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_ECB);
$base64encoded_ciphertext = base64_encode($ciphertext);
echo "ciphertext: ".$base64encoded_ciphertext."<br/>";
$plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($base64encoded_ciphertext), MCRYPT_MODE_ECB);
echo "plaintext: ".$plaintext."<br/>";
$base64encoded_ciphertext = "I3chV+E2XUHeLCcJAhBaJQ==";
$plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($base64encoded_ciphertext), MCRYPT_MODE_ECB);
echo "plaintext: ".trim($plaintext);
output:
ciphertext: kUr+YsYtb3Uy34li/GPcjg==
plaintext: iphone
plaintext: iphone
fixed use some thing like
$iv2 = '';
for ($i = 0; $i < 16; $i++) {
$iv2 .= "\0";
}
mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv2);
don't change the code from https://gist.github.com/838614
the key should be 32 byte
the results of encryt and decrypt are not the same
I have tried to test with this string:
$plaintex = "fskfladsadsadfsfs dfskl;dfs a jadfsa ds'a' j afdjdfsaadfs' jdfas af 'ksfegfffffffffffffffffffffsdfsfgfsfdsdfddfsg"
and the results are different. Anybody here know what the reason could be?
I suspect that it's the padding routine. I've approached this by making sure that the text to be encrypted is padded to 32 char with spaces, and before the result is returned from teh decryption routine, trim off the extra spaces.
There are official padding algorithms, but I found they didn't work. If you encrypt a string that is a multiple of 32 characters long, then even if the padding routine is wrong it will ignore it.