iOS: Decrypt method crash on devices with the A5 chip - ios

I'm trying to decrypt a file, but this method fails on devices with A5 chip. (signal SIGABRT) New devices work fine.
Why is this happening?
- (void) decryptFile{
unsigned char bookhashChar[kCCKeySizeAES128+1];
NSData *stringBytes = [self.bookhash dataUsingEncoding: NSUTF8StringEncoding]; /* or some other encoding */
if (CC_SHA1([stringBytes bytes], (CC_LONG)[self.bookhash length], bookhashChar)) {
/* SHA-1 hash has been calculated and stored in 'digest'. */
}
unsigned char idBookChar[CC_SHA1_DIGEST_LENGTH];
NSData *stringBytesForID = [self.book_id dataUsingEncoding: NSUTF8StringEncoding]; /* or some other encoding */
if (CC_SHA1([stringBytesForID bytes], (CC_LONG)[self.book_id length], idBookChar)) {
/* SHA-1 hash has been calculated and stored in 'digest'. */
}
char resultKey[kCCKeySizeAES128+1];
for (int i = 0; i< kCCKeySizeAES128+1; i++) {
resultKey[i] = (Byte)(bookhashChar[i] ^ idBookChar[i]);
}
char keyPtr[kCCKeySizeAES128 + 1];
bzero(keyPtr, sizeof(keyPtr));
char ivPtr[kCCKeySizeAES128 + 1];
bzero(ivPtr, sizeof(ivPtr));
char ivv[17] = { 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x03, 0x00, 0x06, 0x03, 0x07, 0x00, 0x00, 0x01 };
//[iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
//[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self.downloadedData length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,resultKey, kCCKeySizeAES128,
ivv /* initialization vector (optional) */,
[self.downloadedData bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
self.downloadedData = [[NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted] copy];
}

One error is using kCCKeySizeAES128+1 for the returned size of CCSHA1. Don't mix the value types, AES with SHA1.
The digest size of CCSHA1 is CC_SHA1_DIGEST_LENGTH, 20 bytes.
The size of kCCKeySizeAES128 is 16 bytes.
The buffer for CCSHA1 is to small.
Sooner or later there will be an overwrite of 3 bytes and incorrect operation (possible a crash) will occur.
You may only need kCCKeySizeAES128 bytes but the buffer must be large enough for CCSHA1 and then use the bytes needed.

Related

Set AES key in iOS from a byte array

My service gives me a key as a byte array. For example:
(byte) 0x16, (byte) 0xBB, (byte) 0xAB, (byte) 0xEA, (byte) 0x85, (byte) 0xA7,(byte) 0xD4, (byte) 0xE5, (byte) 0x2F, (byte) 0x7F, (byte) 0x28, (byte) 0x4C, (byte) 0x96, (byte) 0x7D,
In iOS, the AES key is a string. I am trying to use this byte array as a key in iOS.
this OC code ------
//Encrypt AES NOPadding
-(NSData *)AES128Encrypt{
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
// Encrypt Key
Byte keybyte[]={0x77,0x24,0x56,0xf2,0xa7,0x66,0x4c,0xf3,0x39, 0x2c,0x35,0x97,0xe9,0x3e,0x57,0x47};
NSData *keyData=[[NSData alloc]initWithBytes:keybyte length:16];
const void *vKey = (const void *)[keyData bytes];
//Encrypt Iv
Byte ivbyte[]={0x24,0x4e,0x6d,0x8a,0x56,0xac,0x87,0x91,
0x24,0x43,0x2d,0x8b,0x6c,0xbc,0xa2,0xc4};
NSData *IvData=[[NSData alloc]initWithBytes:ivbyte length:16];
const void *vIv = (const void *)[IvData bytes];
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
0x0000,
vKey,
kCCBlockSizeAES128,
vIv,
[self bytes],
dataLength,
buffer,
bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}

AES256Encryption returns data nil on 64 bit device

I am using AES256 to encrypt and decrypt with key. All is working fine and I m getting perfect result with iPhone5, But when I am trying to use it on iPhone6, 6+ simulator in returns me nil data. Is it issue of 64 bit? Not sure.
I m using this two method to encrypt and decrypt data.
My key length is 44 which I am passing to encrypt and decrypt the data.
- (NSData *)AES256EncryptWithKey:(NSString *)key {
BOOL LongKey = NO;
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
- (NSData *)AES256DecryptWithKey:(NSString *)key {
BOOL LongKey = NO;
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
I have tried by Modifying these methods as below. But no success.
- (NSData *)AES256EncryptWithKey:(NSString *)key {
BOOL LongKey = NO;
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
if (key.length>32)
{
LongKey = YES;
key = [key substringToIndex:32];
}
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
if (LongKey) {
keyPtr[0]= 0;
}
keyPtr[32]= 0;
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
- (NSData *)AES256DecryptWithKey:(NSString *)key {
BOOL LongKey = NO;
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
if (key.length>32)
{
LongKey = YES;
key = [key substringToIndex:32];
}
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
if (LongKey) {
keyPtr[0]= 0;
}
keyPtr[32]= 0;
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
Can you please suggest, What can be the issue here?
Thanks.
You have to test it on real device. This also fails for us on emulators (Xcode5/6)

AES256 Encryption/Decryption Error+ IOS SDK 7

I am using AES256 for security and store data in encryption form which is working fine in IOS 6 and below but when i have tested my app in IOS 7, I am not getting my data which was store previously. After debugs, i found decryption is not working is IOS 7 and return blank.
My Code as below:
- (NSData *)AES256DecryptWithKey:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
Can you please help to get my data again in IOS 7?
Thanks
Found the solution on this problem on Apple Devforums.
- (NSData *)encrypt:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
BOOL patchNeeded = ([key length] > kCCKeySizeAES256);
if (patchNeeded) {
key = [key substringToIndex:kCCKeySizeAES256]; // Ensure that the key isn't longer than what's needed (kCCKeySizeAES256)
}
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
if (patchNeeded) {
keyPtr[0] = '\0'; // Previous iOS version than iOS7 set the first char to '\0' if the key was longer than kCCKeySizeAES256
}
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
Of course, copy paste the same patch for the decrypt method.

iOS AES decryption not working

I am encrypting a file using the following command in Terminal on my Mac
openssl enc -aes-256-cbc -salt -in testin.txt -out test.txt
I am then uploading my file to the web and then downloading it in my iOS app, once the download has finished I am decrypting it.
NSString *password = #"myPasswordTextWhichIs32CharsLong";
NSData *decryptedData = [self.testData AES256DecryptWithKey:password];
NSString* decryptedStr = [[NSString alloc] initWithData:decryptedData encoding:NSASCIIStringEncoding];
NSLog(#"decrypted string = %#",decryptedStr);
I then have a NSData-AES.m file containing:
#import "NSData-AES.h"
#import <CommonCrypto/CommonCryptor.h>
#implementation NSData(AES)
- (NSData *)AES256EncryptWithKey:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
- (NSData *)AES256DecryptWithKey:(NSString *)key {
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
The NSLog for decrypted string returns a different string than in the test.txt so I know some sort of decryption is occurring.
Any ideas where I am going wrong and what needs to be changed.
NOTE: I tried the openssl terminal command without -salt but no different

iOS encryption AES128/CBC/nopadding why is not working?

I have an app that needs to encode some data using AES/CBC/no padding. The app is ported also on android. There the encoding is done like this:
byte[] encodedKey = getKey();
SecretKeySpec skeySpec = new SecretKeySpec(encodedKey, "AES");
AlgorithmParameterSpec paramSpec = new IvParameterSpec(initializationVector);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, paramSpec);
int blockSize = cipher.getBlockSize();
int diffSize = decrypted.length % blockSize;
System.out.println("Cipher size: " + blockSize);
System.out.println("Current size: " + decrypted.length);
if (diffSize != 0) {
diffSize = blockSize - diffSize;
byte[] oldDecrypted = decrypted;
decrypted = new byte[decrypted.length + diffSize];
System.arraycopy(oldDecrypted, 0, decrypted, 0, oldDecrypted.length);
for (int i = 0; i < diffSize; i++) {
decrypted[i + oldDecrypted.length] = " ".getBytes()[0];
}
System.out.println("New size: " + decrypted.length);
}
return cipher.doFinal(decrypted);
the initializationVector looks like this:
private byte[] initializationVector = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
on iOS i have something like this for encryption:
- (NSData *)AES128EncryptWithKey:(NSString *)key
{
// 'key' should be 16 bytes for AES128, will be null-padded otherwise
char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
0x0000,
keyPtr,
kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
the method described above is part of a category over NSData.
the method is called like this:
NSData *data = [#"4915200456727" dataUsingEncoding:NSUTF8StringEncoding];
NSData *cipher = [data AES128EncryptWithKey:#"#x#zddXekZerBBw6"];
NSString *ecriptedString = [NSString stringWithFormat:#"%.*s", [cipher length], [cipher bytes]];
the problem that i have is that i don't receive the same encrypted data on iOS and android. On iOS the encrypted data has 0 bytes in length.
Could you give any pointers on how to encrypt a string using AES128 with CBC and no padding and perhaps an example?
Thank you
I found the solution to my problem. In order to make the encryption work without padding i had to add 0x0000 instead of kCCOptionPKCS7Padding or kCCOptionECBMode which are treated.
Also if the data that needs to be encoded doesn't have a length multiple of kCCKeySizeAES128 ( 16 ) then the vector that holds the data must be resized to have the length multiple with kCCKeySizeAES128 and the empty values filled with something. I added spaces.
- (NSData *)AES128EncryptWithKey:(NSString *)key
{
char keyPtr[kCCKeySizeAES128+1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
int dataLength = [self length];
int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
int newSize = 0;
if(diff > 0)
{
newSize = dataLength + diff;
}
char dataPtr[newSize];
memcpy(dataPtr, [self bytes], [self length]);
for(int i = 0; i < diff; i++)
{
dataPtr[i + dataLength] = 0x20;
}
size_t bufferSize = newSize + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
0x0000, //No padding
keyPtr,
kCCKeySizeAES128,
NULL,
dataPtr,
sizeof(dataPtr),
buffer,
bufferSize,
&numBytesEncrypted);
if(cryptStatus == kCCSuccess)
{
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
return nil;
}

Resources