user3023387
user3023387

Reputation: 13

Decrypt AES-128 encrypted data on iOS

I am trying to decrypt AES encrypted data (encrypted in .NET), but my decrypted result string appears to be non-readable, and I don't get any errors.

The data was encrypted using:

I have InItVector, PassCode, salt, and NumberOfPassword (3) iterations.

Here is my code:

//I am retrieving my encrypted data from sqlite database:
NSString *strEncryptedData = [NSString stringWithUTF8String:(char *)sqlite3_column_blob(mysqlStatement, 0)];
NSData *dataToDecrypt = [[NSData alloc] initWithBase64EncodedString:strEncryptedData options:0];

NSString *password = @"somesecurepassword";
NSData *saltData = [@"mysalt" dataUsingEncoding:NSUTF8StringEncoding];
NSData *ivData = [@"myIV16charvalue1" dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;

NSData *decryptedData = [RNCryptManager decryptedDataForData:encoded password:password iv:ivData salt:saltData HMACSalt:NULL HMAC:NULL error:&error];

NSString *str = [[NSString alloc] initWithData:decryptedData encoding:NSASCIIStringEncoding];

NSLog(@"decrypted string: %@", str);

//Here is the code to encrypt the data on the .NET side:

static string hashAlgorithm = "SHA1";
static int passwordIterations = 3;
static string initVector = "myIV16charvalue1";
static int keySize = 128;
static string passPhrase = "somesecurepassword";
static string saltValue = "mysalt";

public static string EncryptData(string plainText)
{
    byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
    byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);
    byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

    PasswordDeriveBytes password = new PasswordDeriveBytes(
        passPhrase,
        saltValueBytes,
        hashAlgorithm,
        passwordIterations);

    byte[] keyBytes = password.GetBytes(keySize / 8);

    RijndaelManaged symmetricKey = new RijndaelManaged();

    // It is reasonable to set encryption mode to Cipher Block Chaining
    // (CBC). Use default options for other symmetric key parameters.
    symmetricKey.Mode = CipherMode.CBC;
    symmetricKey.BlockSize = 128;
    symmetricKey.Padding = PaddingMode.PKCS7;


    ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
        keyBytes,
        initVectorBytes);
        MemoryStream memoryStream = new MemoryStream();
    CryptoStream cryptoStream = new CryptoStream(memoryStream,
        encryptor,
        CryptoStreamMode.Write);

    // Start encrypting.
    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);

    // Finish encrypting.
    cryptoStream.FlushFinalBlock();
    byte[] cipherTextBytes = memoryStream.ToArray();

    memoryStream.Close();
    cryptoStream.Close();

    string cipherText = Convert.ToBase64String(cipherTextBytes);

    return cipherText;
}

Upvotes: 1

Views: 2265

Answers (1)

Rob Napier
Rob Napier

Reputation: 299355

There are several errors here. It looks like decryptedDataForData:... is a modified version of RNCryptManager, but there have been several mistakes injected. In particular, it looks like the author copied the encryption method (encryptedDataForData:...), and then just changed the operation. You can't do that. The decryption method is different from the encryption method. In the above code, the decryptor ignores the salt and IV that are passed to it, and creates random ones (which is how the encryptor works, not the decryptor).

Some other issues:

  • In your encryptor, you're setting the PBKDF2 iterations to 3. In the decryptor you're setting them to 2. This value is very, very low BTW. It is usually at least 1000, and more often at least 10,000.

  • Your IV is the wrong length. It has to be exactly 16 bytes. Ideally the IV should be different for every message, and should be sent along to the decryptor. If you have a static IV, then you reduce the security of the encryption.

  • While not a cause of your issue, the salt should also random for every message and sent along to the decryptor. A static salt makes it much easier to perform password attacks.


EDIT: (Note that you're still using a hacked version of encryptedDataWithData: to do decryption. I recommend using the decryptedDataWithData: method linked above. The way you've hacked encryptedDataWithData: will likely work, but just because the buffer it creates happens to be too long.)

The deeper problem is that you're using the wrong KDF in C#. You're using PasswordDeriveBytes which implements PBKDF1. You should be using Rfc2898DeriveBytes, which implements PBKDF2.

Note that there is a bug in the version of RNCryptManager that you're using. In AESKeyForPassword:salt:, this line:

password.length,  // passwordLength

Should be:

[password lengthOfBytesUsingEncoding:UTF8StringEncoding],

Upvotes: 3

Related Questions