Question

Using PHP 5.4 (mcrypt), RNCryptor 2, iOS 6.

PHP function creates base64 with all headers as referenced from https://github.com/rnapier/RNCryptor/wiki/Data-Format.

PHP decrypt function which can decrypt base64 string from both RNEncryptor and the PHP Encrypt function below return data as expected.

When using RNDecryptor with base64 from PHP Encrypt function below, no data is returned as shown in XCode output below.

PHP Function:

function encrypt($data, $key)
{
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

    $salt = '12345678';

    $_key = $this->pbkdf2('SHA1', $key, $salt, 10000, 32, true);

    $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $_key, $data, MCRYPT_MODE_CBC, $iv);

    $hmac = $this->pbkdf2('SHA1', $key, $salt, 10000, 32, true);

    $data = mb_convert_encoding(chr(1).chr(0).$salt.$salt.$iv.$ciphertext.$hmac, "BASE64", "UTF-8");

    return $data;
}

PHP Function Call:

encrypt('My Data', 'mykey');

iOS:

NSError * error;
NSData *decryptedData = [RNDecryptor decryptData:[NSString base64DataFromString:@"AQBpcGhvbmU2MmlwaG9uZTYyrYk2rJnaoywktnx6TZ4X3YKgYuEHCL1EHv+/MqIvQMq5BmZOyMJr QSRs9P4uxShsOJOg67VYniUGhHbFNTSl1Q=="]
                                    withPassword:@"mykey"
                                           error:&error];

NSLog(@"data = %@, %@", decryptedData, error);

XCode output:

data = <>, (null)

This is done when I comment out HMAC verification in RNDecryptor -finish, once these section is uncommented I receive a HMAC Mismatch error

data = (null), Error Domain=net.robnapier.RNCryptManager Code=1 "HMAC Mismatch" UserInfo=0x1e564280 {NSLocalizedDescription=HMAC Mismatch}

if (self.hasHMAC) {
  NSMutableData *HMACData = [NSMutableData dataWithLength:self.HMACLength];
  CCHmacFinal(&_HMACContext, [HMACData mutableBytes]);

  if (![HMACData isEqualToData:self.inData]) {
    [self cleanupAndNotifyWithError:[NSError errorWithDomain:kRNCryptorErrorDomain
                                                        code:kRNCryptorHMACMismatch
                                                    userInfo:[NSDictionary dictionaryWithObject:@"HMAC Mismatch"
                                                                                         forKey:NSLocalizedDescriptionKey]]];
    return;
  }
}
Was it helpful?

Solution 2

The problem was due to both an incorrect HMAC (was passing the HMAC Key) and PHP encryption needing PKCS7 Padding on the data to be encrypted (not the IV too).

Final PHP function...

function AES256Encrypt($data, $key)
{
    $block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $pad = $block - (strlen($data) % $block);
    $data .= str_repeat(chr($pad), $pad);

    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

    $keySalt = '12345678';
    $hmacSalt = '12345678';

    $_key = $this->pbkdf2('SHA1', $key, $keySalt, 10000, 32, true);
    $_hmacKey = $this->pbkdf2('SHA1', $key, $hmacSalt, 10000, 32, true);

    $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $_key, $data, MCRYPT_MODE_CBC, $iv);

    $data = base64_encode(chr(1).chr(0).$keySalt.$hmacSalt.$iv.$ciphertext.hash_hmac('SHA256',$ciphertext,$_hmacKey, true));
    return $data;
}

OTHER TIPS

mb_convert_encoding() will do base64 conversion, but it will output chunked base64.

The PHP base64 decoder will accept both chunked and unchunked, but iOS...?

Perhaps you need to just encode:

$data = base64_encode(chr(1).chr(0).$salt.$salt.$iv.$ciphertext.$hmac);

You may want to check out iOS/PHP kCCDecodeError for another implementation.

Finally, from the RNCryptor Wiki Data Format, I see (together with a link to the PHP implementation on Stack Overflow)

HMAC is generated using the ciphertext and the HMACKey (above) and the SHA-256 PRF.

...but the HMAC you append seems to me to actually be the HMACKey, not the HMAC...?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top