I have been working on this for a while, but can not find a way to tackle the problem. Hopefully one of you can tell me what I am missing.
I am using NSURLConnection to download base64 encoded data containing AES128 encrypted data. What I have is the key, see code, and the knowledge that the first 16 characters of the encrypted data is the IV. What I want is to decode the data and then decrypt it using the key and iv extracted. This is what I have so far:
- (void) connectionDidFinishLoading:(NSURLConnection *) connection {
NSLog(#"Succeeded! Downloaded %d bytes of data", downloadData.length);
NSData *decoded_EncryptedData = [downloadData base64EncodedDataWithOptions:0];
NSString *decoded_EncryptedString = [[NSString alloc] initWithData: decoded_EncryptedData encoding:NSUTF8StringEncoding];
const void *key = #"0000000000000000000000000000000"; // key of length 32 char -> i know standard format for AES128 encryption is 16, maybe this requires 256 AES decryption
const void *iv = (__bridge const void *)([decoded_EncryptedString substringWithRange:NSMakeRange(0,16)]);
NSString *encryptedString = [decoded_EncryptedString substringWithRange:NSMakeRange(16, decoded_EncryptedString.length-16)];
// Now I have no idea what needs to happen, but from online research I found it should be something like this:
NSData encryptedData = [encryptedString dataUsingEncoding:NSUTF8StringEncoding]; // Writing it back into a data file
// Find size of returned data
size_t Size = encryptedData.length + kCCBlockSizeAES128;
// Initialise returned data
NSMutableData *decryptedData = [NSMutableData dataWithLength:Size];
// allocate variable to numBytesDecrypted
size_t numBytesDecrypted;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 0, KCCKeySizeAES128, iv,
[encryptedData bytes], [encryptedData length], [decryptedData bytes], [decryptedData length],
&numBytesDecrypted);
// Now I test whether the decryption process was successful:
if (cryptStatus == kCCSuccess) {
NSLog(#"Successfully decrypted);
NSString *decryptedString = [[NSString alloc] initWithData:decryptedData encoding: NSUTF8StringEncoding];
}
}
The above code does display Successfully decrypted, however the string return null and size 0. Could someone please help me solve this? I would be so grateful.
Kind regards,
Lennaert
You have many problems.
You really need to know if the encryption is AES128 or AES256.
Encryption is data based, not string based. The conversion to a string decoded_EncryptedString is incorrect not should not be done.
The key is an issue, using a string is generally a bad idea, it is expected to be data bytes. Possibly the key is specified in hex so 32 hex characters would be 128 bits. If so conversion to data will be required.
'iv' and encryptedString are strings but they should be data, this a result of 2 above.
The key is not passed to CCCrypt.
Padding is generally used since the data is rarely exactly a block size in length, you probably need to specify PKCS7 padding to CCCrypt. You need to know if padding was used and if so was it PKCS7, php for example uses non-standard padding.
If PKCS7 padding is used the result must be trimmed to the length based on the variable numBytesDecrypted. If some other padding is used that must be trimmed.
If you want more help please supply test data and the result.
Finally, try and check back more frequently.
Related
I want to decrypt and encrypt a data using AES/CBC/PKCS5Padding in IOS,
in android i can use Cipher class to do it, but in IOS dont have those class to use it, right?
Currently i using this to do it, but it seem incorrect.
- (NSData *) DecryptAES: (NSString *) key{
char keyPtr[kCCKeySizeAES128];
bzero( keyPtr, sizeof(keyPtr) );
[key getCString: keyPtr maxLength: sizeof(keyPtr) encoding: NSUTF8StringEncoding];
size_t numBytesEncrypted = 0;
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer_decrypt = malloc(bufferSize);
const unsigned char iv[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
CCCryptorStatus result = CCCrypt( kCCDecrypt , kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128,
iv,
[self bytes], [self length],
buffer_decrypt, bufferSize,
&numBytesEncrypted );
if( result == kCCSuccess )
return [NSData dataWithBytesNoCopy:buffer_decrypt length:numBytesEncrypted];
return nil;}
how do i suppose to do it same like java did?
i have tried a lot diff way to do it, but it still now working, hope you guys can help me,
Thank's.
Additional information:
return data:
{"data":"3557793957617431633179755554443638483834686662707a652b7977454c655a654d344e316463513348324e2f2f6e6e4f54783961564e5a4f56426c6e69675a3850644c66734136446f736950516279366b375a5066302f7a424e654b47454c4153547132354c6746724e38432b4d7a3750514c4b3836796f7a54307764614666574e776373716d49766f517552347877766432337778584a796a49457878374e6c354a4f32434755583034722b4770324c79514658704d686e51586553574c6b6939303045754c6a7954494c454977493242796365496a75394b4a2b456347526136527244682b316168533067303651597a6b47713469717a75764d7856"}
encrypt and decrypt step
Cipher: AES (Rijndael block size = 128)
Key: fTG90HGFyeal3kGw
Mode: CBC
IV: CBC random (must append to crypted data)
*base64 is being used in order to make data transmission possible.
Request steps:
1- Collect required data in key-value format
2- JSON encode the collection
3- Encrypt JSON string
4- Generate random IV and append to head of encrypted data
5- Encode crypted data with base64
6- Post 5th item result under a key named “data”
Response steps:
1- Decode JSON string response
2- Decode the value of key named “data” with base64
3- Substring IV from decoded data
4- Decrypt the data
5- JSON decode the result of 4th item
6- Response in key-value format is
I follow the decrypt step to decrypt, i still not able to decrypt data.
I have the following situation: there is a NSData that i need to decrypt. The data consists of:
fixed length file header
encrypted content
I'm using CCCrypt for decryption, but it probably doesn't matter, because this is more of an NSData related question. This is how i'm separating things now (pseudocode):
int hdrsize; // this contains the size of the header
NSData *data; // this contains full encrypted data with a header
// this gives me information, stored in the header + some additional stuff
NSDictionary *hdr = [self _headerInfoFromData:data];
// THIS IS THE PROBLEM AREA
data = [data subdataWithRange:NSMakeRange(hdrsize, [data length] - hdrsize)];
// And the decryption part
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, MS_SEC_ENC_ALGORITHM, kCCOptionPKCS7Padding,
[key bytes], MS_SEC_ENC_KEY_SIZE,
[[hdrdict objectForKey:#"iv"] bytes],
[data bytes], dataLength,
buffer, bufferSize,
As you can see, my problem here is that for decryption i need to extract the part of NSData without the header. But is there a way to simply somehow "reuse" the bytes that are already there instead of making the copy? Maybe there's some sort of way to create a no-copy byte buffer out of it, skipping first X bytes and passing that into CCCrypt instead?
Thanks for your help
Have you verified that -subdataWithRange: does copy the bytes? If it does, you can always use +dataWithBytesNoCopy:length:, just make sure to handle ownership properly.
EDIT
I'm such a fool. Just do this:
int hdrsize; // this contains the size of the header
NSData *data; // this contains full encrypted data with a header
// this gives me information, stored in the header + some additional stuff
NSDictionary *hdr = [self _headerInfoFromData:data];
// And the decryption part
CCCryptorStatus cryptStatus = CCCrypt(
kCCDecrypt,
MS_SEC_ENC_ALGORITHM,
kCCOptionPKCS7Padding,
[key bytes],
MS_SEC_ENC_KEY_SIZE,
[[hdrdict objectForKey:#"iv"] bytes],
data.bytes + hdrsize,
data.length - hdrsize,
buffer,
bufferSize,
In My App, i'm getting data from xml, where it is encrypted, and i need to decrypt the received nsstring,
UserName = #"QEjbHvzPjk+YuLDVPUJuEA==";
I Need to decrypt this nsstring into regular format, i searched and find aes , but it doesn't make any changes,
NSString* msg = [FBEncryptorAES decryptBase64String:UserName
keyString:#"01234567890abcdefghijklmnopqrstuvwxyz"];
if (msg)
{
UserName = msg;
NSLog(#"decrypted: %#", msg);
} else
{
UserName = #"(failed to decrypt)";
}
How can i decrypt the above nsstring, Thanks in Advance.
The string is not only AES encrypted, it is Base64 encoded. The trailing "==" is typical of base64 padding. Also AES encryption produces data bytes, not ASCII characters and the output is a multiple of the block size. It is common to Base64 encode the result of encryption so it is ASCII and can be included in XML.
For iOS 7 there are several Base64 API methods for NSData. Probably what you want is:
- (id)initWithBase64EncodedString:(NSString *)base64String options:(NSDataBase64DecodingOptions)options
Example:
NSString *userName = #"QEjbHvzPjk+YuLDVPUJuEA==";
NSData *data = [[NSData alloc] initWithBase64EncodedString:userName options:0];
NSLog(#"data: %#", data);
NSLog output:
data: <4048db1e fccf8e4f 98b8b0d5 3d426e10>
The data probably is AES encrypted, it is a multiple of block length, and if so you will need the key and also information on padding, mode and possibly iv.
Note that the FBEncryptorAES class method encryptedBase64String does accept Base64 input but the decryption key string is suspect and the encryption may not match this decryption method due to method and possible iv. So the FBEncryptorAES class may not be what you need.
I have been working on decryption for some time now and cannot get it to work. When I encrypt using the following code:
private static string Decrypt(string plainText, string completeEncodedKey, int keySize)
{
RijndealManaged aesEncryption = new RijndealManaged();
aesEncryption.KeySize = keySize; //keySize is 256
aesEncryption.BlockSize = 128;
aesEncryption.Mode = CipherMode.CBC;
aesEncryption.Padding = PaddingMode.PKCS7;
aesEncryption.IV = Convert.FromBase64String(ASCIIEncoding.ACSII.GetString(Convert.FromBase64String(completeEncodedString)).Split(',')[0]);
aesEncryption.Key = Convert.FromBase64String(ASCIIEncoding.ACSII.GetString(Convert.FromBase64String(completeEncodedString)).Split(',')[1]);
byte[] plainText = Encoding.UTF8.GetBytes(plainStr);
ICryptoTransform crypto = aesEncryption.CreateEncryptor();
byte[] cipherText = crypto.TransformFinalBlock(plainText, 0, plainText.Length);
return Convert.ToBase64String(cipherText);
}
passing the name "Anthony" as the plainText I get uRO2DBKAhFsOed/p10dz+w==
and I decrypt using
-(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;
}
but I get nothing in return. The code gets up to the if(cryptStatus == kCCSuccess){ line and it does not go into the if statement. So the the decryption is returning nil.
Any help on why this is not working would be great. Thanks.
So I think you have a couple of problems here:
You are specifying an IV when encrypting, but you are leaving it
NULL when decrypting. While it's true that the IV is optional, you
must use the same one for encrypting and decrypting.
I'm pretty sure you are not parsing the key correctly when
decrypting. From what I can tell, you seem to be using a
double-base64 encoded string (for some reason) on the server. At
least, this is what I see you doing with it:
1. Base64 decoding the string.
2. Splitting the resulting string on ','.
3. Taking the first part of the split, base64 decoding it again to use as the IV.
4. Taking the second part of the split, base64 decoding it again to use as the key.
You aren't doing any of these things in the Obj-C code. And assuming that you are taking in the key in the same format, you need to. All you are doing in the Obj-C code is taking the NSString object and converting it into a C-string.
My app encrypts and decrypts (or it should) an NSString (the text to be encrypted / decrypted) with another NSString (the keyword) using aes 256-Bit Encryption. When I run my project and run the encrypt method, nothing gets encrypted the textfield just clears itself. Here is the code I have:
-(void)EncryptText {
//Declare Keyword and Text
NSString *plainText = DataBox.text;
NSString *keyword = Keyword.text;
//Convert NSString to NSData
NSData *plainData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
//Encrypt the Data
NSData *encryptedData = [plainData AESEncryptWithPassphrase:keyword];
//Convert the NSData back to NSString
NSString* cypherText = [[NSString alloc] initWithData:encryptedData encoding:NSUTF8StringEncoding];
//Place the encrypted sting inside the Data Box
NSLog(#"Cipher Text: %#", cypherText);
}
The header files can be downloaded by clicking this link: ZIP File containing AES Implementation
I have been told that I need to use Base-64 encoding of my string to get any result. If this is true, then how do I do it?
I have also been told that encryption changed in iOS 5, and my app is an iOS 5+ ONLY app. If this is true, then what do I have to do to make this encryption work on iOS 5 or where can I find another AES 256-bit implementation that will work on NSString.
Why doesn't this code produce a result?
EDIT: The links below refer to an older implementation. The latest version is called RNCryptor.
Your code doesn't use iOS's built-in AES implementation. It has its own custom implementation. AESEncryptWithPassphrase: also incorrectly generates the key, throwing away most of the entropy in the passphrase.
On iOS, you should be using the CCCrypt*() functions for AES. You should also make sure that you understand what is happening in your encryption and decryption routines. It is very easy to write encryption code that looks correct (in that you cannot read the output by inspection), but is extremely insecure.
See Properly encrypting with AES with CommonCrypto for an explanation of the problems with the above implementation, and how to properly use AES on iOS. Note that iOS 5 now has CCKeyDerivationPBKDF available.
There is no requirement to Base-64 encode your string prior to encryption. Base-64 encoding is used in cases where you need to convert binary data into a form that can be easily sent over email or other places where control characters would be a problem. It converts 8-bit binary data in 7-bit ASCII data. That's not necessary or useful here.
EDIT: It is critical that you carefully read the explanation of how to use this code. It is dangerous to simply cut and paste security code and hope it works. That said, the full source to RNCryptManager is available as part of the Chapter 11 example code for iOS 5 Programming Pushing the Limits and may be helpful [EDIT: This is old code; I recommend RNCryptor now, linked at the top of the answer]. The book (which should be available next week despite what the site says) includes a much longer discussion of how to use this code, including how to improve performance and deal with very large datasets.
NSData with category just fine for AES encryption, I didnt check zip file but this should work for you;
#import <CommonCrypto/CommonCryptor.h>
#implementation NSData (AESAdditions)
- (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;
}
#end
Use it wrapper functions like ;
- (NSData*) encryptString:(NSString*)plaintext withKey:(NSString*)key {
return [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
}
- (NSString*) decryptData:(NSData*)ciphertext withKey:(NSString*)key {
return [[[NSString alloc] initWithData:[ciphertext AES256DecryptWithKey:key]
encoding:NSUTF8StringEncoding] autorelease];
}