Here's an Obj-C class using CommonCrypto that I've used before in one of my games.
Thanks to Greg Haywood's code that this is mostly based on.
http://greghaygood.com/2009/01/17/symmetric-encryption-with-the-iphone-sdk-and-securityframework
// SafetyFirst.h
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonDigest.h>
#define kChosenCipherBlockSize kCCBlockSizeAES128
#define kChosenCipherKeySize kCCKeySizeAES128
@interface SafetyFirst : NSObject {
}
- (NSData*) GetMD5:(NSString*) str;
- (NSData*) encrypt:(NSData*) theData key:(NSData*) aSymmetricKey padding:(CCOptions*) pkcs7;
- (NSData*) decrypt:(NSData*) theData key:(NSData *)aSymmetricKey padding:(CCOptions*) pkcs7;
- (NSData*) doCipher:(NSData*) theData key:(NSData*) aSymmetricKey
context:(CCOperation) encryptOrDecrypt padding:(CCOptions*) pkcs7;
@end
The implementation file
// SafetyFirst.m
#import "SafetyFirst.h"
@implementation SafetyFirst
- (id) init {
if ( (self = [super init]) ) {
// initialize
}
return self;
}
- (NSData*) GetMD5:(NSString*) str {
const char* cStr = [str UTF8String];
unsigned char result[ CC_MD5_DIGEST_LENGTH ];
CC_MD5( cStr, strlen( cStr ), result );
return [NSData dataWithBytes:result length:16];
}
- (NSData*) encrypt:(NSData*) theData key:(NSData*) aSymmetricKey padding:(CCOptions*) pkcs7 {
return [self doCipher:theData key:aSymmetricKey context:kCCEncrypt padding:pkcs7];
}
- (NSData*) decrypt:(NSData*) theData key:(NSData*) aSymmetricKey padding:(CCOptions*) pkcs7 {
return [self doCipher:theData key:aSymmetricKey context:kCCDecrypt padding:pkcs7];
}
- (NSData*) doCipher:(NSData*) theData key:(NSData*) aSymmetricKey
context:(CCOperation) encryptOrDecrypt padding:(CCOptions*) pkcs7 {
CCCryptorStatus ccStatus = kCCSuccess;
// Symmetric crypto reference.
CCCryptorRef thisEncipher = 0;
// Cipher Text container.
NSData* cipherOrPlainText = nil;
// Pointer to output buffer.
uint8_t* bufferPtr = 0;
// Total size of the buffer.
size_t bufferPtrSize = 0;
// Remaining bytes to be performed on.
size_t remainingBytes = 0;
// Number of bytes moved to buffer.
size_t movedBytes = 0;
// Length of plainText buffer.
size_t theBufferSize = 0;
// Placeholder for total written.
size_t totalBytesWritten = 0;
// A friendly helper pointer.
uint8_t* ptr;
// Initialization vector; dummy in this case 0's.
uint8_t iv[ kChosenCipherBlockSize ];
memset((void*) iv, 0x0, (size_t) sizeof(iv));
// NSLog(@"doCipher: theData: %@", theData);
// NSLog(@"doCipher: key length: %d", [aSymmetricKey length]);
theBufferSize = [theData length];
// NSLog(@"pkcs7: %d", *pkcs7);
// We don't want to toss padding on if we don't need to
if ( encryptOrDecrypt == kCCEncrypt ) {
if ( *pkcs7 != kCCOptionECBMode ) {
if ( (theBufferSize % kChosenCipherBlockSize) == 0 ) {
*pkcs7 = 0x0000;
} else {
*pkcs7 = kCCOptionPKCS7Padding;
}
}
} else if( encryptOrDecrypt != kCCDecrypt ) {
// wrong type of command
}
// Create and Initialize the crypto reference.
ccStatus = CCCryptorCreate( encryptOrDecrypt, kCCAlgorithmAES128, *pkcs7, (const void*)[aSymmetricKey bytes],
kChosenCipherKeySize, (const void*) iv, &thisEncipher );
if ( ccStatus != kCCSuccess ) {
NSLog(@"Problem creating the context, ccStatus == %d.", ccStatus );
}
// Calculate byte block alignment for all calls through to and including final.
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, theBufferSize, true);
// Allocate buffer.
bufferPtr = (uint8_t*) malloc( bufferPtrSize * sizeof(uint8_t) );
// Zero out buffer.
memset((void*) bufferPtr, 0x0, bufferPtrSize);
// Initialize
ptr = bufferPtr;
// Set up initial size.
remainingBytes = bufferPtrSize;
// Actually perform the encryption or decryption.
ccStatus = CCCryptorUpdate( thisEncipher, (const void*) [theData bytes], theBufferSize, ptr, remainingBytes, &movedBytes );
// update bytes moved
ptr += movedBytes;
remainingBytes -= movedBytes;
totalBytesWritten += movedBytes;
// remaining to output buffer.
ccStatus = CCCryptorFinal(thisEncipher, ptr, remainingBytes, &movedBytes );
totalBytesWritten += movedBytes;
if ( thisEncipher ) {
(void) CCCryptorRelease(thisEncipher);
thisEncipher = 0;
}
if ( ccStatus == kCCSuccess ) {
cipherOrPlainText = [NSData dataWithBytes:(const void*) bufferPtr length:(NSUInteger) totalBytesWritten];
} else {
cipherOrPlainText = nil;
}
if ( bufferPtr) {
free( bufferPtr );
}
return cipherOrPlainText;
}
@end
Usage example:
const char* aKey = dRT76popWeelFincap33987qpMTZ9042012mayan!"
CCOptions padding = kCCOptionPKCS7Padding;
NSString* recoil = [NSString stringWithFormat:@"%s", aKey];
// To ENCRYPT
NSString* fileToEncryptPath = [[NSBundle mainBundle] pathForResource:bFile202 ofType:@"bin"];
NSData* file_data2 = [NSData dataWithContentsOfFile:fileToEncryptPath];
NSData* file_encryptedData = [sFirst encrypt:file_data2 key:[sFirst GetMD5:recoil] padding:&padding];
// write out to mem
if ( [file_encryptedData writeToFile:@"/bFile202.pgz" atomically:NO] == NO ) {
NSLog(@"file_encryptedData - Failed to write data to file");
}
// To DECRYPT
NSString* fileToDecryptPath = [[NSBundle mainBundle] pathForResource:@"bFile202" ofType:@"pgz"];
NSData* file_data = [NSData dataWithContentsOfFile:fileToDecryptPath];
NSData* file_decryptedData = [sFirst decrypt:file_data key:[sFirst GetMD5:recoil] padding:&padding];
myTextureID = [self LoadTextureMapWithData:file_decryptedData width:512 height:512];
Handy routine to convert raw texture data into a mapped texture in memory:
- (GLuint) LoadTextureMapWithData:(NSData*) tData width:(int) width height:(int) height {
GLuint textureID;
GLint saveName;
// NSLog(@"decrypted data: %@", data);
NSUInteger lenT = [tData length];
uint8_t* byteData = (uint8_t*) malloc( lenT );
memcpy(byteData, (uint8_t*)[tData bytes], lenT);
glGenTextures(1, &textureID);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &saveName);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &byteData[4]);
glBindTexture(GL_TEXTURE_2D, saveName);
free( byteData );
return textureID;
}