AQDataExtensions is an
NSData category developed in 2005 by Lucas Newman
and distributed with AquaticPrime framework which “allows for easily encrypting
and decrypting NSData objects with AES/Rijndael (i.e. the Advanced Encryption
The methods are:
- (NSData*)dataEncryptedWithPassword:(NSString*)password - (NSData*)dataDecryptedWithPassword:(NSString*)password
AQDataExtensions has the following weaknesses:
- Weak key derivation function.
- No authentication.
- Weak random numbers.
Weak key derivation function
As method names indicate, they expect developers to provide password for encryption. As user-provided passwords may be weak and easily brute-forceable, usually computationally expensive function is used to derive encryption keys from passwords.
AQDataExtensions derive AES key from password:
// Create the key from first 128-bits of the 160-bit password hash unsigned char passwordDigest; SHA1((unsigned char *)[password UTF8String], strlen([password UTF8String]), passwordDigest); AES_KEY aesKey; AES_set_encrypt_key(passwordDigest, 128, &aesKey);
Unfortunately, it uses SHA-1 hash function, which is not computationally expensive and is very fast. This means that weak passwords can be brute-forced more easily.
Data encrypted by
AQDataExtensions is not authenticated, which means that
encrypted text can be changed in such way that after decryption the
plain-text will change as well. This is unacceptable for many uses, so
authentication must be applied after encryption. For example, you can apply
HMAC to encrypted text and append the authenticator to encrypted data. Before decrypting,
apply HMAC, and compare the result with the attached authenticator.
Weak random numbers
AQDataExtensions uses CBC encryption mode, it needs random numbers
for initialization vector. Random bytes are generated by the following code
srand(time(NULL)); int ivIndex; unsigned char iv; for (ivIndex = 0; ivIndex < 16; ivIndex++) iv[ivIndex] = rand() & 0xff;
rand() function to get them, but
rand() is not suitable for
cryptographic purposes. Also, it is predictable in this code because the PRNG
is reseeded for each encryption with current time. You should replace this code
RAND_bytes(iv, 16) from