Different AES256 result between Java and OpenSSL on iOS

0 投票
最新提问 用户: (220 分)

I've a Java web service returns AES byte array, and other function returns encrypted data (byte array) with this key,

From the other side, I've ios app that calls get AES key, then calls get encrypted data, I included OpenSSL lib on ios app, and it will decrypt encrypted data with AES key that returned before,

My code in Java:

public static byte[] encryptWithAES(byte[] message, Key AESkey) throws Exception {
    byte[] decryptedMessage = null;
    try {
        Cipher encrypt = Cipher.getInstance("AES");
        encrypt.init(Cipher.ENCRYPT_MODE, AESkey);
        decryptedMessage = encrypt.doFinal(message);
    } catch (Exception ex) {
        System.err.println(ex.getMessage());
        throw ex;
    }
    return decryptedMessage;
}

The code in ios:

unsigned char* ucKey = (unsigned char*)[self.AESKeyByte bytes];
AES_KEY wctx;
AES_set_encrypt_key(ucKey, 256, &wctx);
unsigned char* dataDec = (unsigned char *)calloc(size, sizeof(unsigned char*));
unsigned char* encryptedData = (unsigned char*)[value bytes];
AES_decrypt(encryptedData, dataDec, &wctx);
int sizeoddatadec = (int)strlen((char*)dataDec);
NSData* decryptedData = [NSData dataWithBytes:(const void *)dataDec length:sizeof(unsigned char)*sizeoddatadec];
NSString* stringDec = [NSString stringWithUTF8String:[decryptedData bytes]];

The AES key on java is:

ec d6 55 8b 43 70 e9 e4 9f 8c 62 d4 42 b2 c7 46 19 ff 13 c8 10 bb d0 04 ed e4 5b 78 11 1d c7 5d

plain text is: "AChamieh"

And the self.AESKeyByte on ios is:

ec d6 55 8b 43 70 e9 e4 9f 8c 62 d4 42 b2 c7 46 19 ff 13 c8 10 bb d0 04 ed e4 5b 78 11 1d c7 5d

Decrypted data: 64 ee 6a b8 2c 29 16 17 9f 78 cf cb b6 ad e5 cd

Any help for this issue please?

发表于 用户: (2.5k 分)
You should not use AES_encrypt and friends. That's a software-only implementation, so you will not enjoy hardware support, like AES-NI. You should be using EVP_* functions. See EVP Symmetric Encryption and Decryption on the OpenSSL wiki. In fact, you should probably be using authenticated encryption because it provides both confidentiality and authenticity. See EVP Authenticated Encryption and Decryption on the OpenSSL wiki.
发表于 用户: (220 分)
Many thanks @jww, I'll try it.

2 个回答

0 投票
最新回答 用户: (220 分)

Edit (1) to add CBC:

For AES 256 ECB:

I changed my Java code as below:

public static byte[] encryptWithAES(byte[] message, Key AESkey) throws Exception {
byte[] decryptedMessage = null;
try {
    Cipher encrypt = Cipher.getInstance("AES/ECB/PKCS5Padding"); // here is the change
    encrypt.init(Cipher.ENCRYPT_MODE, AESkey);
    decryptedMessage = encrypt.doFinal(message);
} catch (Exception ex) {
    System.err.println(ex.getMessage());
    throw ex;
}
return decryptedMessage;
}

And the Objective c as below:

- (NSData *) encryptAESECB:(NSData *) dataToEncrypt withKey:(NSData*) key{

CCCryptorStatus ccStatus = kCCSuccess;
// Begin to calculate bytesNeeded....
size_t bytesNeeded = 0;

ccStatus = CCCrypt(kCCEncrypt,
                   kCCAlgorithmAES, // for AES if you don't know the size
                   kCCOptionECBMode | kCCOptionPKCS7Padding,  // for AES ECB
                   [key bytes],
                   [key length],
                   nil,
                   [dataToEncrypt bytes],
                   [dataToEncrypt length],
                   NULL,   // for AES if  you don't know the size 
                   0,      // for AES if you don't know the size
                   &bytesNeeded); // for AES if you don't know the size, to get it

if(kCCBufferTooSmall != ccStatus){

    NSLog(@"Here it must return BUFFER TOO SMALL !!");
    return nil;
}

// .....End
// Now i do the real Crypting

char* cypherBytes = malloc(bytesNeeded);
size_t bufferLength = bytesNeeded;

if(NULL == cypherBytes)
    NSLog(@"cypherBytes NULL");

ccStatus = CCCrypt(kCCEncrypt,
                   kCCAlgorithmAES,
                   kCCOptionECBMode | kCCOptionPKCS7Padding,
                   [key bytes],
                   [key length],
                   nil,
                   [dataToEncrypt bytes],
                   [dataToEncrypt length],
                   cypherBytes,     // after get the AES size
                   bufferLength,    // after get the AES size
                   &bytesNeeded);   

if(kCCSuccess != ccStatus){
    NSLog(@"kCCSuccess NO!");
    return nil;
}

return [NSData dataWithBytes:cypherBytes length:bufferLength];
}

- (NSData *) decryptAESECB:(NSData *) dataToDecrypt withKey:(NSData*) key{

CCCryptorStatus ccStatus = kCCSuccess;
// Begin to calculate bytesNeeded....
size_t bytesNeeded = 0;

ccStatus = CCCrypt(kCCDecrypt,
                   kCCAlgorithmAES,
                   //0x0000,
                   kCCOptionECBMode | kCCOptionPKCS7Padding,
                   [key bytes],
                   [key length],
                   nil,
                   [dataToDecrypt bytes],
                   [dataToDecrypt length],
                   NULL,
                   0,
                   &bytesNeeded);


if(kCCBufferTooSmall != ccStatus){

    NSLog(@"Here it must return BUFFER TOO SMALL !!");
    return nil;
}

// .....End
// Now i do the real Crypting

char* cypherBytes = malloc(bytesNeeded);
size_t bufferLength = bytesNeeded;

if(NULL == cypherBytes)
    NSLog(@"cypherBytes NULL");

ccStatus = CCCrypt(kCCDecrypt,
                   kCCAlgorithmAES,
                   kCCOptionECBMode | kCCOptionPKCS7Padding,
                   [key bytes],
                   [key length],
                   nil,
                   [dataToDecrypt bytes],
                   [dataToDecrypt length],
                   cypherBytes,
                   bufferLength,
                   &bytesNeeded);

if(kCCSuccess != ccStatus){
    NSLog(@"kCCSuccess NO!");
    return nil;
}

return [NSData dataWithBytes:cypherBytes length:bufferLength];
}

For AES 256 CBC:

I changed my Java code as below:

public static byte[] encryptWithAES(byte[] message, Key AESkey, byte[] iv) throws Exception {
byte[] decryptedMessage = null;
try {
    Cipher encrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");  // here is the change
    encrypt.init(Cipher.ENCRYPT_MODE, AESkey,new IvParameterSpec(iv)); // and I add the iv for cbc
    decryptedMessage = encrypt.doFinal(message);
} catch (Exception ex) {
    System.err.println(ex.getMessage());
    throw ex;
}
return decryptedMessage;
}

And the Objective c as below:

- (NSData *) encryptAESCBC:(NSData *) dataToEncrypt withKey:(NSData*) key{

CCCryptorStatus ccStatus = kCCSuccess;
// Begin to calculate bytesNeeded....
size_t bytesNeeded = 0;

ccStatus = CCCrypt(kCCEncrypt,
                   kCCAlgorithmAES,
                   kCCOptionPKCS7Padding, // for AES CBC
                   [key bytes],
                   [key length],
                   self.IV.bytes,   // You need to add the IV array
                   [dataToEncrypt bytes],
                   [dataToEncrypt length],
                   NULL,
                   0,
                   &bytesNeeded);

if(kCCBufferTooSmall != ccStatus){

    NSLog(@"Here it must return BUFFER TOO SMALL !!");
    return nil;
}

// .....End
// Now i do the real Crypting

char* cypherBytes = malloc(bytesNeeded);
size_t bufferLength = bytesNeeded;

if(NULL == cypherBytes)
    NSLog(@"cypherBytes NULL");

ccStatus = CCCrypt(kCCEncrypt,
                   kCCAlgorithmAES,
                   kCCOptionPKCS7Padding,  // for AES CBC
                   [key bytes],
                   [key length],
                   self.IV.bytes,    // You need to add the IV array
                   [dataToEncrypt bytes],
                   [dataToEncrypt length],
                   cypherBytes,
                   bufferLength,
                   &bytesNeeded);

if(kCCSuccess != ccStatus){
    NSLog(@"kCCSuccess NO!");
    return nil;
}

return [NSData dataWithBytes:cypherBytes length:bufferLength];
}

- (NSData *) decryptAESCBC:(NSData *) dataToDecrypt withKey:(NSData*) key{

CCCryptorStatus ccStatus = kCCSuccess;
// Begin to calculate bytesNeeded....
size_t bytesNeeded = 0;

ccStatus = CCCrypt(kCCDecrypt,
                   kCCAlgorithmAES,
                   kCCOptionPKCS7Padding,
                   [key bytes],
                   [key length],
                   self.IV.bytes,
                   [dataToDecrypt bytes],
                   [dataToDecrypt length],
                   NULL,
                   0,
                   &bytesNeeded);


if(kCCBufferTooSmall != ccStatus){

    NSLog(@"Here it must return BUFFER TOO SMALL !!");
    return nil;
}

// .....End
// Now i do the real Crypting

char* cypherBytes = malloc(bytesNeeded);
size_t bufferLength = bytesNeeded;

if(NULL == cypherBytes)
    NSLog(@"cypherBytes NULL");

ccStatus = CCCrypt(kCCDecrypt,
                   kCCAlgorithmAES,
                   kCCOptionPKCS7Padding,
                   [key bytes],
                   [key length],
                   self.IV.bytes,
                   [dataToDecrypt bytes],
                   [dataToDecrypt length],
                   cypherBytes,
                   bufferLength,
                   &bytesNeeded);

if(kCCSuccess != ccStatus){
    NSLog(@"kCCSuccess NO!");
    return nil;
}

return [NSData dataWithBytes:cypherBytes length:bufferLength];
}

I tried something related to this answer:

Encrypting data with Objective-C and decrypt it with Java Problem

I tried this solution and it's work fine with me.

发表于 用户: (2.9k 分)
Do not use ECB mode, it is insecure, see ECB mode, scroll down to the Penguin. Instead use CBC mode with a random IV, just prefix the encrypted data with the IV for use in decryption, it does not need to be secret.
发表于 用户: (220 分)
Many thanks, @zaph I'll try it
发表于 用户: (2.9k 分)
It is unclear if this is a solution or additional information for the question, that is does this resolve the problem?
发表于 用户: (220 分)
@zaph, No it's a solution, and it's working fine for me.
发表于 用户: (2.9k 分)
The ObjC answer is really incorrect, there is no need for the "buffer to small" check. On encryption add one block size to the receiving buffer, on decryption make the receiving buffer the same size as the encrypted data (or larger). In both cases after success set the receiving buffer size to bytesNeeded size. See ObjC AES, it handles both encrypt and decrypt in one method.
发表于 用户: (220 分)
@zaph thank you for your advice, I saw your post, I need to ask you if we have AES256 bit, Do you have any idea how to represent it on your answer.
0 投票
最新回答 用户: (220 分)

For ECB:

The java code will be

public static byte[] encryptWithAES(byte[] message, Key AESkey) throws Exception {
byte[] decryptedMessage = null;
try {
    Cipher encrypt = Cipher.getInstance("AES/ECB/PKCS5Padding"); // here is the change
    encrypt.init(Cipher.ENCRYPT_MODE, AESkey);
    decryptedMessage = encrypt.doFinal(message);
} catch (Exception ex) {
    System.err.println(ex.getMessage());
    throw ex;
}
return decryptedMessage;
}

For CBC:

The java code will be

    public static byte[] encryptWithAES(byte[] message, Key AESkey, byte[] iv) throws Exception {
byte[] decryptedMessage = null;
try {
    Cipher encrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");  // here is the change
    encrypt.init(Cipher.ENCRYPT_MODE, AESkey,new IvParameterSpec(iv)); // and I add the iv for cbc
    decryptedMessage = encrypt.doFinal(message);
} catch (Exception ex) {
    System.err.println(ex.getMessage());
    throw ex;
}
return decryptedMessage;
}

Edit (2):

Depends on @zaph said the previous objective c will take twice process,

I updated the objective c code :

- (NSData *) AESECB : (NSData *) data withKey :(NSData *) key : (CCOperation) operation{

CCCryptorStatus ccStatus = kCCSuccess;
NSUInteger dataLength = data.length;
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc( bufferSize );

size_t numBytes = 0;

ccStatus = CCCrypt(operation,  // will pass kCCDecrypt or kCCEncrypt
                   kCCAlgorithmAES,
                   kCCOptionECBMode | kCCOptionPKCS7Padding,
                   [key bytes],
                   [key length],
                   nil,
                   [data bytes],
                   [data length],
                   buffer,
                   bufferSize,
                   &numBytes);

if( ccStatus == kCCSuccess )
{
    return [NSData dataWithBytes:buffer length:numBytes];
}

free(buffer);
return nil;
}

- (NSData *) AESCBC : (NSData *) data withKey: (NSData *) key : (CCOperation) operation{
CCCryptorStatus ccStatus = kCCSuccess;
NSUInteger dataLength = data.length;
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc( bufferSize );

size_t numBytes = 0;

ccStatus = CCCrypt(operation,  // will pass kCCDecrypt or kCCEncrypt
                   kCCAlgorithmAES,
                   kCCOptionPKCS7Padding,
                   [key bytes],
                   [key length],
                   self.IV.bytes,
                   [data bytes],
                   [data length],
                   buffer,
                   bufferSize,
                   &numBytes);

if( ccStatus == kCCSuccess )
{
    return [NSData dataWithBytes:buffer length:numBytes];
}

free(buffer);
return nil;
}

Many thanks @zaph for your advice again.

欢迎来到 Security Q&A ,有什么不懂的可以尽管在这里提问,你将会收到社区其他成员的回答。
...