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

I have an iPhone solutions that uses XML to transmit data between the client (mobile) and the server (Java). Some of the parts of the message (XML) must be encrypted because of the type of information transmitted. I planned to use AES 128 to encrypt and decrypt the data between these two endpoints.

First the sensitive data is encrypted using Object-C’s CommonCrypto framework, and then the data is decrypted inside a Java Server (Servlet).

  • Xcode not compiling any project? 'clang failed with exit code 255'
  • How to use custom fonts in iPhone SDK?
  • How to get at a relationship items properties in Core Data?
  • Extract iPod Library raw PCM samples and play with sound effects
  • Xcode 6.4 Export Adhoc “Session has expired”
  • What's the best way to use Obj-C 2.0 Properties with mutable objects, such as NSMutableArray?
  • I’m new to security protocols and standards, and basically my code is a subset of group of informations that I could gather on Apple’s dev forum/resources, and the internet (Google) 🙂

    The basic flow is:

    1. The data is encrypted using AES (using a pre-set key).
    2. The encrypted bytes are putted within the XML (using base64)
    3. The data is gathered from the XML, and decrypted using the same pre-setted key;

    The encryption part of the Object-C code is:

    char keyPtr [ kCCKeySizeAES128 +1 ];
    bzero( keyPtr, sizeof(keyPtr) );
    
    // The secret key is masked for obvious reason, but you can use "12345678912345678912345678912345"
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    NSUInteger dataLength = [data length];
    // Initialization vector; dummy in this case 0's.
    uint8_t iv[ kCCBlockSizeAES128 ];
    memset((void *) iv, 0x0, (size_t) sizeof(iv));
    /*
     For block ciphers, the output size will always be less than or
     equal to the input size plus the size of one block.
    */
    size_t bufferSize = (dataLength + kCCBlockSizeAES128);
    void  *buffer     = malloc(bufferSize);
    memset(buffer, 0x0, bufferSize);
    
    size_t numBytesEncrypted    = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, 
                                          kCCOptionECBMode + kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES128,
                                          iv, [data bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);
    
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    
    free(buffer); //free the buffer;
    return nil;
    

    The Java code part is:

    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    byte[] keyBytes = DES_KEY.getBytes(); //<== The same as above
    
    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    
    try {
        // Return the raw bytes 
        byte []data = Base64.decode(encryptedContent);
    
        // Gets the Cipher...
        final Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
    
        String resultString = new String(cipher.doFinal(data));
    } catch (Exception ex) {
        ...
    }
    

    The error I get when running these solution above in the Java Server is:

    15:57:43,671 ERROR [STDERR] com.iteatros.aim.services.ServiceException: javax.crypto.BadPaddingException: pad block corrupted
    15:57:43,674 ERROR [STDERR]     at com.iteatros.aim.services.security.SecurityWrapper.decrypt3DESBase64StringData(SecurityWrapper.java:109)
    15:57:43,674 ERROR [STDERR]     at com.iteatros.aim.services.db.LoginDAO.login(LoginDAO.java:53)
    15:57:43,674 ERROR [STDERR]     at com.iteatros.aim.services.AbstractService.authenticate(AbstractService.java:278)
    15:57:43,674 ERROR [STDERR]     at com.iteatros.aim.services.AbstractService.doPost(AbstractService.java:165)
    15:57:43,674 ERROR [STDERR]     at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    15:57:43,674 ERROR [STDERR]     at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    15:57:43,674 ERROR [STDERR]     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    15:57:43,675 ERROR [STDERR]     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    15:57:43,675 ERROR [STDERR]     at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
    15:57:43,675 ERROR [STDERR]     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    15:57:43,676 ERROR [STDERR]     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    15:57:43,676 ERROR [STDERR]     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
    15:57:43,676 ERROR [STDERR]     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    15:57:43,676 ERROR [STDERR]     at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
    15:57:43,676 ERROR [STDERR]     at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
    15:57:43,676 ERROR [STDERR]     at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
    15:57:43,676 ERROR [STDERR]     at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
    15:57:43,677 ERROR [STDERR]     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    15:57:43,677 ERROR [STDERR]     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    15:57:43,677 ERROR [STDERR]     at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
    15:57:43,677 ERROR [STDERR]     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    15:57:43,677 ERROR [STDERR]     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
    15:57:43,677 ERROR [STDERR]     at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
    15:57:43,677 ERROR [STDERR]     at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:601)
    15:57:43,677 ERROR [STDERR]     at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    15:57:43,677 ERROR [STDERR]     at java.lang.Thread.run(Thread.java:680)
    

    I know that the full stack wasn’t needed, but anyways…

    Thanx much in advance.

    Joao

    Solutions Collect From Internet About “Encrypting data with Objective-C and decrypt it with Java Problem”

    This code works for me. Give a look:

    AES 128 IOS

    + (NSString *) encrypt:(NSString *) dataToEncrypt withKey:(NSString*) key{    
    
    
    NSData *data = [dataToEncrypt dataUsingEncoding:NSUTF8StringEncoding];
    NSData *mData = [key dataUsingEncoding:NSUTF8StringEncoding];
    
    CCCryptorStatus ccStatus = kCCSuccess;
    
    
    // Begin to calculate bytesNeeded....
    
    size_t bytesNeeded = 0;
    
    ccStatus = CCCrypt(kCCEncrypt,
                       kCCAlgorithmAES,
                       kCCOptionECBMode | kCCOptionPKCS7Padding,
                       [mData bytes],
                       [mData length],
                       nil,
                       [data bytes],
                       [data 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,
                       kCCOptionECBMode | kCCOptionPKCS7Padding,
                       [mData bytes],
                       [mData length],
                       nil,
                       [data bytes],
                       [data length],
                       cypherBytes,
                       bufferLength,
                       &bytesNeeded);
    
    if(kCCSuccess != ccStatus){
        NSLog(@"kCCSuccess NO!");
        return nil;
    }
    
    return [Base64 encode:[NSData dataWithBytes:cypherBytes length:bufferLength]];
    }
    

    JAVA

    public static void encrypt_AES(String message){
    
            Cipher ecipher;
            try {
                // generate secret key using DES algorithm
                SecretKeySpec key = new SecretKeySpec(theKey.getBytes("UTF-8"), "AES");
    
                ecipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
    
                // initialize the ciphers with the given key
                ecipher.init(Cipher.ENCRYPT_MODE, key);
    
                byte[] encrypted = ecipher.doFinal(message.getBytes("UTF-8"));
    
            }catch (Exception e) {
                //    
                e.printStackTrace();
            }
    
        }
    

    I found the Base64 class here: http://www.imthi.com/blog/programming/iphone-sdk-base64-encode-decode.php

    Hope it can help someone