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/
Related
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!
I'm having a hard time decrypting NSData with NSData key. While decrypting with NSString everything works fine, yet with data as key, the method returns null NSData, eventhough status is ok, and key is also correct for that data. Here is my call
NSData *decrypted = [AES AES128DecryptWithKey:data key:mute];
NSLog(#"DECRYPTED >> %#", decrypted);
And my method
+ (NSData*)AES128DecryptWithKey:(NSData*) data key:(NSData*)key {
NSUInteger dataLength = [data length];
NSLog(#"trying to decrypt >> %# with key >> %#", data, key );
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void* buffer = malloc(bufferSize);
size_t numBytesDecrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
[key bytes], kCCKeySizeAES128,
NULL /* initialization vector (optional) */,
[data bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
NSLog(#"cryptstatus %d", cryptStatus);
if (cryptStatus == kCCSuccess)
{
return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
}
free(buffer); //free the buffer;
return nil;
}
NSLog output:
trying to decrypt >> <152f052e 79436003 7a9c1a59 3b82f1c4>
with key >> <1b510e76 ac0000a1 027af26a e25ad24a>
cryptstatus 0
DECRYPTED >> <>
Looked into RNEncryptor, yet it only has aes256, while i need 128. Any ideas?
It could be that the single byte block only contains padding bytes. In that case zero bytes would be the expected outcome.
This is not the case for your ciphertext, in your case no padding was applied during encryption, so you will get a failure when you try and unpad the data.
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.
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.