I found an AES sample for encryption and decryption from http://pastie.org/pastes/297563/text
It works fine except for the decryption scenario. when I encrypt a custom email string with a long string ( myfullname@mycompanytech.com ), there is no problem encrypting and decrypting. After encryption, I store in the plist file and then read it later for decryption. But, when I encrypt an email string with a short long string (for example: me@company.com ), the encryption is OK, but when I try to decrypt the string and put it in the label, I found that decryption gives an error, for example, Problem with ccStatus encryption == -4301 "
Udpate . I found that this decryption problem only happens when the string length is "16", otherwise it always works fine. Any help please?
Please find the code below. This is the code for encryption and decryption.
import "CryptoHelper.h"
#define LOGGING_FACILITY(X, Y) \
if(!(X)) { \
NSLog(Y); \
}
#define LOGGING_FACILITY1(X, Y, Z) \
if(!(X)) { \
NSLog(Y, Z); \
}
@interface CryptoHelper(Private)
- (NSData *)doCipher:(NSData *)plainText key:(NSData *)theSymmetricKey context:(CCOperation)encryptOrDecrypt padding:(CCOptions *)pkcs7;
- (NSString *)base64EncodeData:(NSData*)dataToConvert;
- (NSData*)base64DecodeString:(NSString *)string;
@end
@implementation CryptoHelper
static CryptoHelper *MyCryptoHelper = nil;
const uint8_t kKeyBytes[] = "abcdefgh0123456";
static CCOptions pad = 0;
static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- (NSString*)encryptString:(NSString*)string
{
NSRange fullRange;
fullRange.length = [string length];
fullRange.location = 0;
uint8_t buffer[[string length]];
[string getBytes:&buffer maxLength:[string length] usedLength:NULL encoding:NSUTF8StringEncoding options:0 range:fullRange remainingRange:NULL];
NSData *plainText = [NSData dataWithBytes:buffer length:[string length]];
NSData *encryptedResponse = [self doCipher:plainText key:symmetricKey context:kCCEncrypt padding:&pad];
return [self base64EncodeData:encryptedResponse];
}
- (NSString*)decryptString:(NSString*)string
{
NSLog(@"string: %@", string);
NSData *decryptedResponse = [self doCipher:[self base64DecodeString:string] key:symmetricKey context:kCCDecrypt padding:&pad];
NSString *result = [NSString stringWithFormat:@"decryptedResponse: %@", decryptedResponse];
NSLog(@"decryptedResponse: %@", result);
return [NSString stringWithCString:[decryptedResponse bytes] length:[decryptedResponse length]];
}
- (NSData *)doCipher:(NSData *)plainText key:(NSData *)theSymmetricKey context:(CCOperation)encryptOrDecrypt padding:(CCOptions *)pkcs7
{
CCCryptorStatus ccStatus = kCCSuccess;
CCCryptorRef thisEncipher = NULL;
NSData * cipherOrPlainText = nil;
uint8_t * bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t remainingBytes = 0;
size_t movedBytes = 0;
size_t plainTextBufferSize = 0;
size_t totalBytesWritten = 0;
uint8_t * ptr;
uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));
LOGGING_FACILITY(plainText != nil, @"PlainText object cannot be nil." );
LOGGING_FACILITY(theSymmetricKey != nil, @"Symmetric key object cannot be nil." );
LOGGING_FACILITY(pkcs7 != NULL, @"CCOptions * pkcs7 cannot be NULL." );
LOGGING_FACILITY([theSymmetricKey length] == kCCKeySizeAES128, @"Disjoint choices for key size." );
plainTextBufferSize = [plainText length];
LOGGING_FACILITY(plainTextBufferSize > 0, @"Empty plaintext passed in." );
if(encryptOrDecrypt == kCCEncrypt)
{
if(*pkcs7 != kCCOptionECBMode)
{
if((plainTextBufferSize % kCCBlockSizeAES128) == 0)
{
*pkcs7 = 0x0000;
}
else
{
*pkcs7 = kCCOptionPKCS7Padding;
}
}
}
else if(encryptOrDecrypt != kCCDecrypt)
{
LOGGING_FACILITY1( 0, @"Invalid CCOperation parameter [%d] for cipher context.", *pkcs7 );
}
ccStatus = CCCryptorCreate( encryptOrDecrypt,
kCCAlgorithmAES128,
*pkcs7,
(const void *)[theSymmetricKey bytes],
kCCKeySizeAES128,
(const void *)iv,
&thisEncipher
);
LOGGING_FACILITY1( ccStatus == kCCSuccess, @"Problem creating the context, ccStatus == %d.", ccStatus );
bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t) );
memset((void *)bufferPtr, 0x0, bufferPtrSize);
ptr = bufferPtr;
remainingBytes = bufferPtrSize;
ccStatus = CCCryptorUpdate( thisEncipher,
(const void *) [plainText bytes],
plainTextBufferSize,
ptr,
remainingBytes,
&movedBytes
);
LOGGING_FACILITY1( ccStatus == kCCSuccess, @"Problem with CCCryptorUpdate, ccStatus == %d.", ccStatus );
ptr += movedBytes;
remainingBytes -= movedBytes;
totalBytesWritten += movedBytes;
ccStatus = CCCryptorFinal( thisEncipher,
ptr,
remainingBytes,
&movedBytes
);
totalBytesWritten += movedBytes;
if(thisEncipher)
{
(void) CCCryptorRelease(thisEncipher);
thisEncipher = NULL;
}
LOGGING_FACILITY1( ccStatus == kCCSuccess, @"Problem with encipherment ccStatus == %d", ccStatus );
cipherOrPlainText = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten];
if(bufferPtr) free(bufferPtr);
return cipherOrPlainText;
}
#pragma mark -
#pragma mark Base64 Encode/Decoder
- (NSString *)base64EncodeData:(NSData*)dataToConvert
{
if ([dataToConvert length] == 0)
return @"";
char *characters = malloc((([dataToConvert length] + 2) / 3) * 4);
if (characters == NULL)
return nil;
NSUInteger length = 0;
NSUInteger i = 0;
while (i < [dataToConvert length])
{
char buffer[3] = {0,0,0};
short bufferLength = 0;
while (bufferLength < 3 && i < [dataToConvert length])
buffer[bufferLength++] = ((char *)[dataToConvert bytes])[i++];
characters[length++] = encodingTable[(buffer[0] & 0xFC) >> 2];
characters[length++] = encodingTable[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)];
if (bufferLength > 1)
characters[length++] = encodingTable[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)];
else characters[length++] = '=';
if (bufferLength > 2)
characters[length++] = encodingTable[buffer[2] & 0x3F];
else characters[length++] = '=';
}
return [[[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES] autorelease];
}
- (NSData*)base64DecodeString:(NSString *)string
{
if (string == nil)
[NSException raise:NSInvalidArgumentException format:nil];
if ([string length] == 0)
return [NSData data];
static char *decodingTable = NULL;
if (decodingTable == NULL)
{
decodingTable = malloc(256);
if (decodingTable == NULL)
return nil;
memset(decodingTable, CHAR_MAX, 256);
NSUInteger i;
for (i = 0; i < 64; i++)
decodingTable[(short)encodingTable[i]] = i;
}
const char *characters = [string cStringUsingEncoding:NSASCIIStringEncoding];
if (characters == NULL)
return nil;
char *bytes = malloc((([string length] + 3) / 4) * 3);
if (bytes == NULL)
return nil;
NSUInteger length = 0;
NSUInteger i = 0;
while (YES)
{
char buffer[4];
short bufferLength;
for (bufferLength = 0; bufferLength < 4; i++)
{
if (characters[i] == '\0')
break;
if (isspace(characters[i]) || characters[i] == '=')
continue;
buffer[bufferLength] = decodingTable[(short)characters[i]];
if (buffer[bufferLength++] == CHAR_MAX)
{
free(bytes);
return nil;
}
}
if (bufferLength == 0)
break;
if (bufferLength == 1)
{
free(bytes);
return nil;
}
bytes[length++] = (buffer[0] << 2) | (buffer[1] >> 4);
if (bufferLength > 2)
bytes[length++] = (buffer[1] << 4) | (buffer[2] >> 2);
if (bufferLength > 3)
bytes[length++] = (buffer[2] << 6) | buffer[3];
}
realloc(bytes, length);
return [NSData dataWithBytesNoCopy:bytes length:length];
}
#pragma mark -
#pragma mark Singleton methods
- (id)init
{
if(self = [super init])
{
symmetricKey = [[NSData dataWithBytes:kKeyBytes length:sizeof(kKeyBytes)] retain];
}
return self;
}
+ (CryptoHelper*)sharedInstance
{
@synchronized(self)
{
if (MyCryptoHelper == nil)
{
[[self alloc] init];
}
}
return MyCryptoHelper;
}
+ (id)allocWithZone:(NSZone *)zone
{
@synchronized(self)
{
if (MyCryptoHelper == nil)
{
MyCryptoHelper = [super allocWithZone:zone];
return MyCryptoHelper;
}
}
return nil;
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (unsigned)retainCount
{
return UINT_MAX;
}
- (void)release
{
}
- (id)autorelease
{
return self;
}
@end
Below is the caller code above,
-(NSString *) getUsername
{
NSString *usernameString = NULL;
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:LOGIN_PLIST];
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
plistPath = [[NSBundle mainBundle] pathForResource:@"LoginInfo" ofType:@"plist"];
}
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSString *errorDesc = nil;
NSPropertyListFormat format;
NSDictionary *temp = (NSDictionary *)[NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc];
if (!temp)
{
}
else
{
NSString *nameStr=[temp objectForKey:@"Username"];
NSLog(@"nameStr: %@",nameStr);
CryptoHelper *pCrypto = [CryptoHelper sharedInstance];
usernameString = [pCrypto decryptString:nameStr];
NSLog(@"usernameString: %@: usernameString length: %ld", usernameString, [usernameString length] );
}
return usernameString;
}