3

This is my java code. Now I want to implement same functionality in Objective-C.

Cipher encryptCipher;
IvParameterSpec iv = new IvParameterSpec(key);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = encryptCipher.doFinal(dataToEncrypt.getBytes());
Log.d("TAG", "encrypted string:"
        + Base64.encodeToString(encrypted, Base64.DEFAULT));
return Base64.encodeToString(encrypted, Base64.DEFAULT).trim();

This is my iOS implementation

- (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;
}

This is my hash key generating function. this function return same key in android and ios

int dkLen = 16;
    NSData *keyData = [hash_key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *salt    = [saltKey dataUsingEncoding:NSUTF8StringEncoding];
    uint    rounds  = 1000;
    uint    keySize = kCCKeySizeAES128;

    NSMutableData *derivedKey = [NSMutableData dataWithLength:keySize];





    CCKeyDerivationPBKDF(kCCPBKDF2,               // algorithm
                         keyData.bytes,           // password
                         keyData.length,          // passwordLength
                         salt.bytes,              // salt
                         salt.length,             // saltLen
                         kCCPRFHmacAlgSHA1,       // PRF
                         rounds,                  // rounds
                         derivedKey.mutableBytes, // derivedKey
                         dkLen*8);
 return derivedKey;

I am getting a different output. I am doing anything wrong?.please help me to find out.

Askarc Ali
  • 318
  • 4
  • 21
  • Since you're still seem to have a problem, you can improve the question further: (1) Show the input and the output of both versions (in Hex); (2) Provide runnable code snippets in your favorite online IDE like [ideone.com](http://ideone.com/) (it does support Java and Objective-C). – Artjom B. Nov 09 '15 at 14:08
  • could you please give me any similar example – Askarc Ali Nov 10 '15 at 07:00
  • @ Artjom B ,your helping is appreciable . please see this https://gist.github.com/askarali/401e1056c5d2c3ad29d9 – Askarc Ali Nov 11 '15 at 09:11

2 Answers2

6

One problem is that the Java code used CBC mode, the iOS code used ECB mode.

Next, from the referenced project:
//result= yHbhApwTpQ2ZhE97AKF/g==
is invalid Base64, it does not contain a multiple of 4 bytes.

With these options: CBC, PKCS#7 padding

inputs:  
   data in: "hello" which will be null padded to the block length of 16-bytes  
   key:  
      base64: VQQhu+dUdqXGoE7RZL2JWg==  
      hex: 550421bbe75476a5c6a04ed164bd895a  
   iv:   
      base64: VQQhu+dUdqXGoE7RZL2JWg==  
      hex: 550421bbe75476a5c6a04ed164bd895a  
encrypted output:  
   hex: ff21db840a704e943666113dec0285fe  
   base64: /yHbhApwTpQ2ZhE97AKF/g==  

This is the test code:

NSString *base64Key  = @"VQQhu+dUdqXGoE7RZL2JWg==";
NSString *dataString = @"hello";

NSData *key  = [[NSData alloc] initWithBase64EncodedString:base64Key  options:0];
NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];

NSLog(@"key:  %@", key);
NSLog(@"data: %@", data);

NSData *encryptedData = [TestClass crypt:data
                                 iv:key
                                key:key
                            context:kCCEncrypt];

NSLog(@"encryptedData: %@", encryptedData);
NSString *encryptedBase64Data = [encryptedData base64EncodedStringWithOptions:0];
NSLog(@"encryptedBase64Data: %@", encryptedBase64Data);

This is the encryption method (in the class TestClass):

+ (NSData *)crypt:(NSData *)dataIn
                  iv:(NSData *)iv
                 key:(NSData *)symmetricKey
             context:(CCOperation)encryptOrDecrypt
{
    CCCryptorStatus ccStatus   = kCCSuccess;
    size_t          cryptBytes = 0;    // Number of bytes moved to buffer.
    NSMutableData  *dataOut    = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];

    ccStatus = CCCrypt( encryptOrDecrypt,
                       kCCAlgorithmAES128,
                       kCCOptionPKCS7Padding,
                       symmetricKey.bytes,
                       kCCKeySizeAES128,
                       iv.bytes,
                       dataIn.bytes,
                       dataIn.length,
                       dataOut.mutableBytes,
                       dataOut.length,
                       &cryptBytes);

    if (ccStatus != kCCSuccess) {
        NSLog(@"CCCrypt status: %d", ccStatus);
    }

    dataOut.length = cryptBytes;

    return dataOut;
}

Note: I keep separate the encryption and data conversions. Conflating them just makes testing more complicated.

If you use an on-line encryption implementation the padding will probably not be PKCS#7 because mcrypt does not support it, instead it does non-standard null padding. Since the pad bytes are just the count of pad bytes the padding can be simulated in the input. Here is an example using AES – Symmetric Ciphers Online

Note that "hello" PKCS#7 padded to a block size of 16 bytes adds 11 bytes of the uint8 value 11 or 0x0B: 68656c6c6f0B0B0B0B0B0B0B0B0B0B0B.

Finally the question remains why the Java code does not produce this result?

zaph
  • 111,848
  • 21
  • 189
  • 228
  • thankyou zaph. i have a working implementation in java and c# it is working fine. – Askarc Ali Nov 17 '15 at 05:44
  • For interoperability all that is needed is simply getting all the inputs the same. A problem with libraries that combine many operations is they usually do not document the internals and that makes interoperability difficult. There is something extra going on. Perhaps the strings are not UTF-8? That is why I keep the actual encryption simple, just data bytes and then add the data conversions outside the encryption. By using hex dumps I can see exactly what the data is. – zaph Nov 17 '15 at 13:17
  • One difference is the key size, in the iOS code they key is explicitly specified as 256-bits (32-bytes) but the Java code choses the key size based on the supplied key data which is 128-bits (16-bytes). Another possibility is that the data ("hello") are comprised of unichar (16 bit). – zaph Nov 17 '15 at 13:33
  • this methord we are used in my all project so at present i can't bring improvement – Askarc Ali Nov 18 '15 at 05:47
  • zaph decryption is giving diffrent output – Askarc Ali Nov 18 '15 at 06:47
  • if i change NSString *base64Key = @"VQQhu+dUdqXGoE7RZL2JWg=="; this it give null or <> please help Check http://stackoverflow.com/questions/40485518/convert-aes-encryption-of-android-in-objective-c-xcode?noredirect=1#comment68219359_40485518 – 9to5ios Nov 09 '16 at 10:52
  • I am getting success url response like <==> https://www.google.com/?crypt=@d73a09f9a3d3afe9303613bd2aa2354ce71fe7cc0e532ca1e7c209c8c9742f398a80880549504ad9752a66ad7ae1fb07ae5ce8f003eb8cf5223c29aa96d5a264dacea96d9e82ed628a62b2f0530173d56191fcd5b4a0ad9fcd4829228721a02c.... How to decrypt that to know response? – Reddy Apr 01 '17 at 06:41
  • I love you @zaph . Been trying to get a consistent encrypt + base64 implementation for 2 days straight! Got the correct encrypted code finally due to your "Simplicity". – esh May 20 '21 at 13:48
1

Well, how big is your key? kCCAlgorithmAES128 and kCCKeySizeAES256 assume different key sizes. I'm assuming that you're using a 16 byte key, because your Java code would throw an exception otherwise. If you're using a 128 bit key, then you should use kCCKeySizeAES128.

Additionally, you're not passing in any IV, so it will be assumed that the IV is filled with 0x00 bytes, but in Java, you're using the key as IV.

Don't use the key as IV. That diminishes the use of the IV in the first place that is there to randomize the ciphertext. You need to generate a random IV for each encryption and send it along with the ciphertext, for example by prepending it to the ciphertext.

Yes, PKCS#5 padding and PKCS#7 padding are the same thing.

Community
  • 1
  • 1
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • So, it's a 128 bit key (assuming base64 encoding). If you want to use AES-256, then you need a bigger key and then you won't be able to use the key as an IV directly in Java. – Artjom B. Oct 29 '15 at 12:53
  • i checked both key which is getting from android and ios it is same – Askarc Ali Oct 29 '15 at 12:55
  • I never said that your keys where wrong. I said that you use different IVs in Java and Obj-C. – Artjom B. Oct 29 '15 at 13:09
  • could you please provide a sample code .because i am new to iOS – Askarc Ali Oct 29 '15 at 13:13
  • @ Artjom B, i couldnt fix it – Askarc Ali Oct 31 '15 at 05:43
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. – grebulon Nov 09 '15 at 09:36
  • @grebulon You were [overruled](http://stackoverflow.com/review/low-quality-posts/10142618). I'd like to understand your reasoning. Note: [Your answer is in another castle: when is an answer not an answer?](http://meta.stackexchange.com/q/225370/266187) – Artjom B. Nov 09 '15 at 14:15
  • @askarcali [Here](https://gist.github.com/artjomb/1a96acfbe560a8fa7cdb) is an example of what I mean in my answer. If this doesn't solve your issue, then it's probably the way you're passing the key in. The result of the key derivation is `NSMutableData`, but you're passing it as a string and then impose UTF-8 encoding on it which is wrong, because it might break the byte representation of the key during the conversion. The line `[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];` and those before are the problem. I'm afraid I don't know enough about Obj-C to help. – Artjom B. Nov 10 '15 at 08:33
  • @Artjom B, can you open a chat? and could you share whatever you know – Askarc Ali Nov 10 '15 at 10:48
  • why / is coming at first – Askarc Ali Nov 18 '15 at 06:26