To calculate a checksum in code, use the CC_SHA1 function:
NSData *data = ...;
uint8_t output[CC_SHA1_DIGEST_LENGTH]; CC_SHA1(data.bytes, data.length, output);
NSData *digest = [NSData dataWithBytes:output length:CC_SHA1_DIGEST_LENGTH];
NSData *data, *key;
unsigned int length = CC_SHA1_DIGEST_LENGTH; unsigned char output[length];
CCHmac(kCCHmacAlgSHA1, key.bytes, key.length, data.bytes, data.length, output);
The first step is to create a function that generates a PBKDF2 key from a salted password. A salt is random data used as an additional input to a one-way function performed on a password.
static NSData * AES128PBKDF2KeyWithPassword(NSString *password, NSData *salt,
NSError * __autoreleasing *error)
{
NSCParameterAssert(password);
NSCParameterAssert(salt);
NSMutableData *mutableDerivedKey = [NSMutableData dataWithLength:kCCKeySizeAES128];
CCCryptorStatusstatus =
CCKeyDerivationPBKDF(kCCPBKDF2,
[password UTF8String],
[passwordlengthOfBytesUsingEncoding:NSUTF8StringEncoding],
[salt bytes],
[salt length],
kCCPRFHmacAlgSHA256,
1024,
[mutableDerivedKey mutableBytes],
kCCKeySizeAES128);
NSData *derivedKey = nil;
if (status != kCCSuccess)
{
if (error)
{
*error = [[NSError alloc] initWithDomain:nil code:status userInfo:nil];
}
}
else
{
derivedKey = [NSData dataWithData:mutableDerivedKey];
}
return derivedKey;
}
Next, a function to encrypt the data can be created, which takes the data to encrypt and password, and returns the generated salt and initialization, as well as any error encountered in performing the operation, as out arguments:
static NSData * AES128EncryptedDataWithData(NSData *data, NSString *password,
NSData * __autoreleasing *salt, NSData * __autoreleasing *initializationVector,
NSError * __autoreleasing *error)
{
NSCParameterAssert(initializationVector);
NSCParameterAssert(salt);
uint8_t *saltBuffer = malloc(8);
SecRandomCopyBytes(kSecRandomDefault, 8, saltBuffer);
*salt = [NSData dataWithBytes:saltBuffer length:8];
NSData *key = AES128PBKDF2KeyWithPassword(password, *salt, error);
uint8_t *initializationVectorBuffer = malloc(kCCBlockSizeAES128);
SecRandomCopyBytes(kSecRandomDefault,kCCBlockSizeAES128, initializationVectorBuffer);
*initializationVector = [NSData dataWithBytes:initializationVector length:kCCBlockSizeAES128];
size_t size = [data length] + kCCBlockSizeAES128;
void *buffer = malloc(size);
size_t numberOfBytesEncrypted = 0;
CCCryptorStatusstatus =
CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
[key bytes],
[key length],
[*initializationVector bytes],
[data bytes],
[data length],
buffer,
size,
&numberOfBytesEncrypted);
NSData *encryptedData = nil;
if (status != kCCSuccess)
{
if (error)
{
*error = [[NSError alloc] initWithDomain:nil code:status userInfo:nil];
}
}
else
{
encryptedData = [[NSData alloc] initWithBytes:buffer length:numberOfBytesEncrypted];
}
return encryptedData;
}
Finally, to decrypt the data, do the same process in reverse, this time passing the data and password along with the salt and initialization vector generated from the encryption function:
staticNSData*AES128DecryptedDataWithData(NSData*data,NSString*password, NSData *salt, NSData *initializationVector, NSError * __autoreleasing *error)
{
NSData *key = AES128PBKDF2KeyWithPassword(password, salt, error);
size_t size = [data length] + kCCBlockSizeAES128;
void *buffer = malloc(size);
size_t numberOfBytesDecrypted = 0;
CCCryptorStatusstatus =
CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
[key bytes],
[key length],
[initializationVector bytes],
[data bytes],
[data length],
buffer,
size,
&numberOfBytesDecrypted);
NSData *encryptedData = nil;
if (status != kCCSuccess)
{
if (error)
{
*error = [[NSError alloc] initWithDomain:nil code:status userInfo: nil];
}
}
else
{
encryptedData = [[NSData alloc] initWithBytes:buffer length:numberOfBytesDecrypted];
}
return encryptedData;
}