How to get the same result as the following objective-c encrypting method with the command line openssl ?
- (NSData *)AES256EncryptWithKey:(NSString *)key {
NSData *returnData = nil;
char keyPtr[kCCKeySizeAES256+1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding | kCCOptionECBMode,
keyPtr,
kCCBlockSizeAES128,
NULL,
[self bytes],
dataLength,
buffer,
bufferSize,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
returnData = [[NSData alloc] initWithBytes:buffer length:numBytesEncrypted];
}
free(buffer);
return returnData;
}
I tried the following ones (with and without -nosalt), but unsuccessfully:
openssl aes-256-ecb -nosalt -in original.txt -out encrypted.txt
openssl aes-128-ecb -nosalt -in original.txt -out encrypted.txt
While it may be possible, you shouldn't. This ObjC encryption code is very broken. It's creating the key incorrectly, which is why you're having trouble with OpenSSL (which also creates keys poorly, but better, and in a different way). If you want an ObjC encryption module compatible with OpenSSL, see RNCryptor which is designed to handle this problem. If possible, I'd avoid OpenSSL, but there isn't currently a simple commandline replacement that I recommend.
See the docs for RNCryptor for why this ObjC code is broken, and also the problems with OpenSSl's aes encryption routines.
Related
I'm trying to ultimately encrypt a file with OpenSSL and decrypt with Objective-c CommonCrypto, but before that works I need both approaches to encrypt the same way.
This is what I have:
String to encrypt: "This is the string"
Key: "thisisthekey"
OpenSSL:
openssl enc -aes256 -a -e -nosalt -in InputFileWithString.txt -out OutputFile.txt thisisthekey
Resulting base 64 encoded string from openSSL: HncUM4ryxSR7Rdi7Z49HPl9veOPxkk3l8GYIgorBhbk=
Objective-c CommonCrypto:
+(NSString *)encryptText:(NSString *)text withKey:(NSString *)key{
NSData *plainData = [text dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [plainData AES256EncryptWithKey:key];
NSString *base64String = [encryptedData base64EncodedStringWithOptions:0];
return base64String;
}
- (NSData*)AES256EncryptWithKey:(NSString*)key {
char keyPtr[kCCKeySizeAES256 + 1];
bzero(keyPtr, sizeof(keyPtr));
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger 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;
}
The resulting base 64 encoded string: gNCs4d0GAxZHRcOtu8RVpLgN0ONKk1r5XkJ4GtL7W2I=
As you can see, each approach is producing a different encrypted string. Any ideas how to make these both produce the same string?
Use a full length key, 256-bits which is 32-bytes, do not rely on padding. CCCrypt expects a 32-byte key due to kCCKeySizeAES256 but you are supplying 12 bytes and zero padding the remaining key space.
The default for CCCrypt is CBC mode but you provide a NULL IV. This will essentially give you ECB mode but it is better to speciky the option: kCCOptionECBMode.
A good working example is located here:
https://richardwarrender.com/2016/04/encrypt-data-using-aes-and-256-bit-keys/
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.
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;
}
I am trying to use the following snippet to decrypt file, which was encrypted with 32 byte key. So when I am trying to encrypt file data, everything is going ok. But when I am trying do decrypt, program even don't pass the condition if (cryptStatus == kCCSuccess) in CryptoExtensions.m. I am really tired figuring out a problem. I was trying to use Base64 decoding, but my file is saved in UTF8 encoding, so I have no problems when I just put it's content in log from NSData:
NSData *fileData = [[[NSData alloc] initWithContentsOfFile:destPath] autorelease];
NSLog(#"File data:%#",[[NSString alloc] initWithData:fileData encoding:NSUTF8StringEncoding]);
But when I am trying to decrypt it, I am getting nil from CryptoExtensions method:
NSData *aesResponse = [fileData AES256DecryptWithKey:#"4QXcCZlgRAIchiaqkMVpF3nkpARmdL3z"];
NSLog(#"AES:%#",[[NSString alloc] initWithData:aesResponse encoding:NSUTF8StringEncoding]);
This is contents of crypto snippet:
CryptoExtensions.h
#import <Foundation/Foundation.h>
#interface NSData (CryptoExtensions)
- (NSData*)AES256EncryptWithKey:(NSString*)key;
- (NSData*)AES256DecryptWithKey:(NSString*)key;
#end
CryptoExtensions.m
#import "CryptoExtensions.h"
#import <CommonCrypto/CommonCryptor.h>
#implementation NSData (CryptoExtensions)
- (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
This code has significant security issues. It incorrectly constructs the AES key, drastically reducing the keyspace and has no IV, creating problems for the first block. I strongly recommend against this code.
I'm most of the way through developing a replacement for this commonly-used snippet. See https://github.com/rnapier/RNCryptor. If it doesn't work for you out of the box, let me know. I'm trying to make it easy enough to use for all the common cases that people will stop using AES256EncryptWithKey.
For a much longer discussion about the problems with this code, see Properly encrypting with AES with CommonCrypto. I love that someone wrapped up AES encryption into an easy to use category. I just wish that it hadn't had so many security issues.
EDIT: Coming back to your actual question, did you use AES256EncryptWithKey to encrypt this data? If not, then the specific format is likely radically different. Almost every AES encryption implementation uses a different approach in generating its input parameters and then generating its output (most don't document this well, either). You have to match the parameters and format. For example, you can't use AES256EncryptWithKey to decrypt something generated with openssl enc.