Edit2
This problem have been solved.The answer is about my other question.And thanks for Hot Licks.
------- Edit separate------------------------------------------------
Edit1: I am sure my ciphertext and my key is correct. Because my workmate decrypt it with C++ and get no problem.By the way, it is ECB mode.
I work very hard on this problem for a week,but I still can't solve it.I really do not know what to do now.
I am developing a cocoa Application,and My server return a ciphertext that encrypt by AES to me.I must decrypt this ciphertext for some information to go next step.
My ciphertext is:
NSString *aesString = #"8DFE2F9A9384573FA0FFAE17C3BEF4CC2BA056CC5CBBFAB57AC78C83AF4EF8A48EA1728D904E87613845377821E01E07CC6C9DEA35516DC595421E0FFC7CAA7A19671E713BB74D84D1DD4FB2C972DD8FACF5D74AD32662E992EA13D2417ABCAEE4137098322394BA76BADBAF4C1DB344704BBF9ED8A1513FF4B2E766526C98A2808B7AE67D1866CB9B489764E70662B1499D8D467A8817D1304AAB8F92EBDDD3E871CC1374CAE96A1428F0C2AFCB3F43E705CDD7649BDE5A363D59125980D0ACBBE32879B96AB15E93F74C08D435B787A8EE734E2773E16AE8F4CB4A5DDAD989F92CF1C609F0F8B81FEDB67F974AE583548B13C86B6FE1925A33A47CBDA8ED54C20F2D8020650BA7FABBF8CBAC00493B6DE423880EF1A1AF8CDDC457C064CD6150AA30D34456E422EA707C313C7FBB428CE1C4E534EA8EDD8C21B62D526522606E6944C4058E631DAFC6F9A539F9A4DFD8AFECCEF51A8A4904A3EFA0A76F3CA55AB56C726B0787D9EBB261CA91F5ABBF985096B327A6269399AC11A23CAFB0B3A6B3FB4AA357FC1644C89B7DEE396C51AF734738E598B765B2384EB8931F4B65D9F4B6C73EE3F1F6C5AA17871D14335153E4058AB9BC0FCAD35DBDB924D00B0A71B985E20CDF530FA5479E2DD8F14D269CE59DA365BAC03FCCB037963E7E3F175A09DD7EFC66E450DF5A16E7233EA55009E4891EF238D003D5837F077C12167428AD19D3DA45D569AA252D5FFD736E134AD3B5654FD82506822BE9B78731C9CA5EE56685153E657E8B385013FF14BBE5A1F5938801E94FE498495C2D94C84A937E1C36A4667A16DFECED471C3902B4B3D1DAA9F2C72A09AF736EF51EBE39F0006667D60DDC9EC20C5C29CC8933E5FB9E293560DB6B152DF4864BD9CF02B0D40D5B24D0326F1D7E251A0CBC692B68FA37212A57F34588D18D6F4F7E59D997A8C4B5E452FE883645B90BD7EE3A4B38754616CA7A9D430620036DBEAD2EC03BEBB5C69E92F9A33951C22E83E68DD85350C7";
and my key is:
NSString *key = #"810B16E3541EF7A4";
I use nicerobot'answer to decrypt my ciphertext and try many other ways. I hope somebody can tell me what to do next.
Convert your encrypted string text to an NSData object using the following code.
NSData* stringData = [encryptedStringText dataUsingEncoding:NSUTF8StringEncoding];
Create the category shown below for NSData and then use it to AES decrypt the NSData content.
NSData* unencryptedData = [stringData AES256DecryptWithKey:keyText];
Convert your NSData object to an NSString.
NSString* unencryptedStringText = [NSString stringWithUTF8String:[unencryptedData bytes]];
#pragma mark -
#pragma mark NSData Encryption Category
// ---------------------------------------------------------
// NSData Category to add Encryption
// ---------------------------------------------------------
#interface NSData (NSDataAESEncryption)
- (NSData *)AES256EncryptWithKey:(NSString *)key;
- (NSData *)AES256DecryptWithKey:(NSString *)key;
#end
#implementation NSData (NSDataAESEncryption)
- (NSData *)AES256EncryptWithKey:(NSString *)key {
char keyPtr[kCCKeySizeAES256+1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL ,
[self bytes], dataLength,
buffer, bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer);
return nil;
}
- (NSData *)AES256DecryptWithKey:(NSString *)key {
char keyPtr[kCCKeySizeAES256+1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
NULL ,
[self bytes], dataLength,
buffer, bufferSize,
&numBytesDecrypted);
if (cryptStatus == kCCSuccess) {
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer);
return nil;
}
#end
AES accepts an initialization vector. What are you using for that?
If the data is in Hex or Base64, I don't see enough bits in your key for AES-128 (the shortest kind). If the key is the Ascii text of the hex string, that would be 128 bits but that seems a bit hokey. Such things happen but it would not be my first choice.
AES encrypts in multiple, not completely compatible modes, CBC and ECB are two I have worked with.
Anyway, I monkeyed around with this for fifteen minutes and I can’t get anything out of that but trash. I have to agree with HotLicks who suggested that you start with an encrypt/decrypt that runs within the same program.
Good luck,
/Bob Bryan
Try this
+ (NSData *)doCipher:(NSData *)dataIn
iv:(NSData *)iv
key:(NSData *)symmetricKey
context:(CCOperation)encryptOrDecrypt // kCCEncrypt or kCCDecrypt
error:(NSError **)error
{
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
ccStatus = CCCrypt( encryptOrDecrypt,
kCCAlgorithmAES128,
0, //kCCOptionPKCS7Padding,
symmetricKey.bytes,
kCCKeySizeAES128,
iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus == kCCSuccess) {
dataOut.length = cryptBytes;
}
else {
if (error) {
*error = [NSError errorWithDomain:#"kEncryptionError"
code:ccStatus
userInfo:nil];
}
dataOut = nil;
}
return dataOut;
}
Related
I am building an iPhone app which gets a encrypt string and sent it to backend.
In PHP I am encrypting the string like this:
$encrypt_method = "AES-256-CBC";
$secret_key = 'This is my secret key';
$secret_iv = 'This is my secret iv';
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
if( $action == 'encrypt' ) {
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
}
How I do the same like that but in Objective C
#import <CommonCrypto/CommonCryptor.h>
#define key #"YOUR_KEY"
#define iv #"YOUR_IV"
- (NSData *) cryptOperation:(CCOperation)operation
{
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keys[kCCKeySizeAES256 + 1];
[key getCString:keys maxLength:sizeof(keys) encoding:NSUTF8StringEncoding];
// Perform PKCS7Padding on the key.
unsigned long bytes_to_pad = sizeof(keys) - [key length];
if (bytes_to_pad > 0)
{
char byte = bytes_to_pad;
for (unsigned long i = sizeof(keys) - bytes_to_pad; i < sizeof(keys); i++)
keys[i] = byte;
}
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 status = CCCrypt(operation, kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
keys, kCCKeySizeAES256,
[iv UTF8String],
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
if (status == kCCSuccess)
{
//the returned NSData takes ownership of buffer and will free it on dealloc
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
- (NSData *)AES256Encrypt
{
return [self cryptOperation:kCCEncrypt];
}
- (NSData *)AES256Decrypt
{
return [self cryptOperation:kCCDecrypt];
}
you can use this method by following way..
NSString *receivedDataDecryptString = [self decrypt:#"YOUR_STRING"];
NSString *receivedDataEncryptString = [self encrypt:#"YOUR_STRING"];
-(NSString *)encrypt:(NSString *)string
{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSData *dataEncrypted = [data AES256Encrypt];
NSString *strRecordEncrypted = [dataEncrypted base64EncodedStringWithOptions:0];
return strRecordEncrypted;
}
-(NSString *)decrypt:(NSString *)string
{
if([string containsString:#"\n"] || [string containsString:#"\t"])
{
string = [[string componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:#""];
string = [string stringByReplacingOccurrencesOfString:#"\t" withString:#""];
}
NSData *keyData = [[NSData alloc] initWithBase64EncodedString:string options:0];
NSData *dataDecrypted = [keyData AES256Decrypt];
NSString *receivedDataDecryptString = [[NSString alloc]initWithData:dataDecrypted encoding:NSUTF8StringEncoding];
return receivedDataDecryptString;
}
Thanks Nirav Kotecha for your answer.
I ended up using CrytoSwift and Add Extension class NSString and String to call it.
Java code is done to generate 3DES result, segment code as below:
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] result = cipher.doFinal(data);
Now, I need to implement same result in objective-C, below is my try, but the result is not even close.
+(NSString *) try3DES:(NSString *)plainText key:(NSString *)key
{
NSString *ciphertext = nil;
NSData *textData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
NSUInteger dataLength = [textData length];
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding,
[key UTF8String],
kCCKeySizeDES,
nil,
[textData bytes],
dataLength,
buffer,
1024,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
ciphertext = [self convertDataToHexStr:data];
}
return ciphertext;
}
Could anybody can help?
I have been struggling with this problem for several days now and i can't seem to figure it out
I tried using CCCrypt to decrypt an encrypted string, I have the encrypted string encoded with Base64 encode, I have the key and the iv. The encryption is AES256 CBC with PKCS7Padding.
This is the code i am using right now:
- (NSData *)AES256DecryptWithKey:(NSString *)key
{
char keyPtr[kCCKeySizeAES128+1];
bzero(keyPtr, sizeof(keyPtr));
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc( bufferSize );
unsigned char *iv = [#"IV String" cStringUsingEncoding:NSUTF8StringEncoding];
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
iv,
[self bytes],
dataLength,
buffer,
bufferSize,
&numBytesDecrypted);
if( cryptStatus == kCCSuccess )
{
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free( buffer );
return nil;
}
But cryptStatus keeps returning 0 and I couldn't find a way to figure out why.
What am i doing wrong?
Thanks in advance!
My cocos2d game saves data using CCCrypt() encryption. I use the mac address as the encryption key. The save file encrypted in IOS5 can't decrypt with the same mac address in IOS6. That means that a user who updated their game will lose all their data!
Is there any way to decrypt the old file?
Here's code:
#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
You'd need to give details on how you implemented your encryption, particularly what options you used.
The most common cause of failed decrypts on iOS 6 in my experience is the CTR bug that they changed/fixed. In iOS 5, there was the option kCCModeOptionCTR_LE which was a lie. It actually encrypted with kCCModeOptionCTR_BE. In iOS 6, they fixed this, and if you try to used kCCModeOptionCTR_LE you'll get an "unimplemented" error. But CCCrypt() doesn't generally use CTR mode, so I don't know if this applies.
Ok, I found the solution.
Key point here:
I add two methods to NSData to encrypt and decrypt with code based IOS5 lib.
#implementation NSData (AESAdditions)
-(NSData*)AES256EncryptWithKey:(NSString*)key;
-(NSData *)AES256DecryptWithKey:(NSString *)key
Now in IOS6 lib,NSData might be changed,so two methods worked different,it can't decrypt the file encrypt in IOS5.
In my code based IOS6,I wrote methods in my class.
like this:
- (NSData*)AES256EncryptWithKey:(NSString*)key data:(NSData *)data;
- (NSData *)AES256DecryptWithKey:(NSString *)key data:(NSData *)data;
the code work well same as in IOS5.
In my application, i need to encrypt the file before sending it over the network and on the other end, it will get decrypt, This is my code,
-(void)doEncryptTest:(NSString *)pFileName{
// read the NSData;
NSStringEncoding encoding =NSUTF8StringEncoding;
NSString *pFileContent = #"xaaaaaaxxaaaaaax";
NSString *pKey = #"01234567012345670123456701234567";
NSData *pData = [pFileContent dataUsingEncoding:encoding];
NSData *pEncryptedData = [pData AES256EncryptWithKey:pKey];
NSData *decrypted=[pEncryptedData AES256DecryptWithKey:pKey Data:pEncryptedData];
NSString* pDecryptedDataStr = [[NSString alloc] initWithData:decrypted
encoding:encoding];
}
This is working fine , only and only if Data size is 16 byte, in real time case, when i sent the file of size 151186 bytes, size of [pEncryptedData] is 15200 , and in fact size of decrypted data is same as original data,
But pDecryptedDataStr is blank, any guess what is going wrong,
please refer below, Encryption and decryption function,
int keySize = kCCKeySizeAES256;
int padding = kCCOptionPKCS7Padding;
char ivKey[16]={0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0};
//////////////*Encryption*///////////////////
- (NSData *)AES256EncryptWithKey:(NSString *)key{
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[keySize + 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 );
char ivVector[kCCBlockSizeAES128+1];
// fetch key data
[key getCString:ivVector maxLength:sizeof( ivVector ) encoding:NSUTF8StringEncoding];
bzero( ivVector, sizeof( ivVector ) ); // fill with zeroes (for padding)
const void *iv=NULL;
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt( kCCEncrypt, kCCAlgorithmAES128, padding,
keyPtr, keySize,
ivKey /* 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 Data:(NSData*)EncryptedData{
bool same =[self isEqualToData:EncryptedData];
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[keySize+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 = [EncryptedData 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 );
const void *iv=NULL;
char ivVector[kCCBlockSizeAES128+1];
// fetch key data
[key getCString:ivVector maxLength:sizeof( ivVector ) encoding:NSUTF8StringEncoding];
bzero( ivVector, sizeof( ivVector ) ); // fill with zeroes (for padding)
size_t numBytesDecrypted = 0;
NSData *output_decrypt = [[NSData alloc] init];
CCCryptorStatus cryptStatus = CCCrypt( kCCDecrypt, kCCAlgorithmAES128, padding,
keyPtr, keySize,
ivKey /* initialization vector (optional) */,
[EncryptedData bytes], dataLength, /* input */
buffer,bufferSize ,//bufferSize, /* output */
&numBytesDecrypted );
output_decrypt = [NSMutableData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
same =[self isEqualToData:output_decrypt];
if( cryptStatus == kCCSuccess )
{
//the returned NSData takes ownership of the buffer and will free it on deallocation
NSData *pData = [[NSData alloc]initWithBytes:buffer length:numBytesDecrypted];
return pData;
}
free( buffer ); //free the buffer
return nil;
}
Thanks for looking at this, this was the problem,
output_decrypt = [NSMutableData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
same =[self isEqualToData:output_decrypt];
if( cryptStatus == kCCSuccess )
{
//the returned NSData takes ownership of the buffer and will free it on deallocation
**NSData *pData = [[NSData alloc]initWithBytes:buffer length:numBytesDecrypted];**
return pData;
}
and solutions was;
output_decrypt = [NSMutableData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
same =[self isEqualToData:output_decrypt];
if( cryptStatus == kCCSuccess )
{
//the returned NSData takes ownership of the buffer and will free it on deallocation
return output_decrypt;
}
Not sure, why it was causing problem, of-course i need to change return type and do some handling in the calling function to release the memory.