4

I'm a complete newbie to this kind of encryption things but I have a Java app and an iOS, and I want them to both be able to ecrypt a text to a same result. I use AES. I found these codes, with a little modification of course, but they return different result

iOS Code:

- (NSData *)AESEncryptionWithKey:(NSString *)key { unsigned char keyPtr[kCCKeySizeAES128] = { 'T', 'h', 'e', 'B', 'e', 's', 't', 'S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' }; size_t bufferSize = 16; void *buffer = malloc(bufferSize); size_t numBytesEncrypted = 0; const char iv2[16] = { 65, 1, 2, 23, 4, 5, 6, 7, 32, 21, 10, 11, 12, 13, 84, 45 }; CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode | kCCOptionPKCS7Padding,, keyPtr, kCCKeySizeAES128, iv2, @"kayvan", 6, dataInLength, buffer, bufferSize, &numBytesEncrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free(buffer); return nil; } 

and the Java code is:

public static void main(String[] args) throws Exception { String password = "kayvan"; String key = "TheBestSecretKey"; String newPasswordEnc = AESencrp.newEncrypt(password, key); System.out.println("Encrypted Text : " + newPasswordEnc); } 

and in another java class (AESencrp.class) I have:

public static final byte[] IV = { 65, 1, 2, 23, 4, 5, 6, 7, 32, 21, 10, 11, 12, 13, 84, 45 }; public static String newEncrypt(String text, String key) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte[] keyBytes= new byte[16]; byte[] b= key.getBytes("UTF-8"); int len = 16; System.arraycopy(b, 0, keyBytes, 0, len); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(IV); System.out.println(ivSpec); cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec); byte[] results = cipher.doFinal(text.getBytes("UTF-8")); String result = DatatypeConverter.printBase64Binary(results); return result; } 

The string I wanted to encrypt is kayvan with the key TheBestSecretKey. and the results after Base64 encoding are:

for iOS: 9wXUiV+ChoLHmF6KraVtDQ==

for Java: /s5YyKb3tDlUXt7pqA5OFA==

What should I do now?

6
  • There's some sort of mismatch between how you're configuring the encryption between the two implementations. As you've no doubt seen, there are a lot of configuration parameters for CCCrypt on iOS. I'm not familiar with Java's Cipher, so you may need to read the documentation for both and make sure you're using the same key size, algorithm, padding... Also, in your Java code above I don't see where you're setting the string you want to encrypt. Is it possible you omitted that step and are encrypting an empty string? Commented Jul 8, 2013 at 21:23
  • yes, there is a lot of parameters and I'm so confused with them. I have to read them again. But about your final question, the string i want to encrypt is set in main method in java. I've edited the question and added this part. Commented Jul 8, 2013 at 21:31
  • Again, I'm not certain about Java Cipher... but it looks like you're using different padding in Objective C. ie: kCCOptionPKCS7Padding vs AES/CBC/PKCS5Padding. (Since you're using a block cipher the algorithm needs to know how to pad the last block, if there isn't enough data to fill the whole block.) However, if I recall correctly PKCS5 and PKCS7 are basically the same algorithm, so I'm not sure that's the problem--you might try changing one or the other implementation to make sure they use the same padding. Commented Jul 8, 2013 at 22:50
  • 1
    Also, it looks like you're using ECB in iOS and CBC in Java. Another problem. Commented Jul 8, 2013 at 22:51
  • I made a gist with iOS/Android/Node.js AES256 same result encoding, gist.github.com/m1entus/f70d4d1465b90d9ee024 Commented May 27, 2014 at 9:10

4 Answers 4

5

And here is the Android Version wich is generating the String for decrypt/encrypt Messages, it uses Cipher and generates the right vector to make the same result as iOS. This is corresponding to the iOS Version of @亚历山大 here in this thread.

public class MyCrypter { private static String TAG = "MyCrypter"; public MyCrypter() { } /** * Encodes a String in AES-128 with a given key * * @param context * @param password * @param text * @return String Base64 and AES encoded String * @throws NoPassGivenException * @throws NoTextGivenException */ public String encode(Context context, String password, String text) throws NoPassGivenException, NoTextGivenException { if (password.length() == 0 || password == null) { throw new NoPassGivenException("Please give Password"); } if (text.length() == 0 || text == null) { throw new NoTextGivenException("Please give text"); } try { SecretKeySpec skeySpec = getKey(password); byte[] clearText = text.getBytes("UTF8"); //IMPORTANT TO GET SAME RESULTS ON iOS and ANDROID final byte[] iv = new byte[16]; Arrays.fill(iv, (byte) 0x00); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); // Cipher is not thread safe Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec); String encrypedValue = Base64.encodeToString( cipher.doFinal(clearText), Base64.DEFAULT); Log.d(TAG, "Encrypted: " + text + " -> " + encrypedValue); return encrypedValue; } catch (InvalidKeyException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } return ""; } /** * Decodes a String using AES-128 and Base64 * * @param context * @param password * @param text * @return desoded String * @throws NoPassGivenException * @throws NoTextGivenException */ public String decode(Context context, String password, String text) throws NoPassGivenException, NoTextGivenException { if (password.length() == 0 || password == null) { throw new NoPassGivenException("Please give Password"); } if (text.length() == 0 || text == null) { throw new NoTextGivenException("Please give text"); } try { SecretKey key = getKey(password); //IMPORTANT TO GET SAME RESULTS ON iOS and ANDROID final byte[] iv = new byte[16]; Arrays.fill(iv, (byte) 0x00); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); byte[] encrypedPwdBytes = Base64.decode(text, Base64.DEFAULT); // cipher is not thread safe Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec); byte[] decrypedValueBytes = (cipher.doFinal(encrypedPwdBytes)); String decrypedValue = new String(decrypedValueBytes); Log.d(TAG, "Decrypted: " + text + " -> " + decrypedValue); return decrypedValue; } catch (InvalidKeyException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } return ""; } /** * Generates a SecretKeySpec for given password * @param password * @return SecretKeySpec * @throws UnsupportedEncodingException */ public SecretKeySpec getKey(String password) throws UnsupportedEncodingException { int keyLength = 128; byte[] keyBytes = new byte[keyLength / 8]; // explicitly fill with zeros Arrays.fill(keyBytes, (byte) 0x0); // if password is shorter then key length, it will be zero-padded // to key length byte[] passwordBytes = password.getBytes("UTF-8"); int length = passwordBytes.length < keyBytes.length ? passwordBytes.length : keyBytes.length; System.arraycopy(passwordBytes, 0, keyBytes, 0, length); SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); return key; } public class NoTextGivenException extends Exception { public NoTextGivenException(String message) { super(message); } } public class NoPassGivenException extends Exception { public NoPassGivenException(String message) { super(message); } } } 
Sign up to request clarification or add additional context in comments.

1 Comment

Correct answer for getting the same encrypted data, but that's almost never necessary. So please don't use a fixed IV in production code. crypto.stackexchange.com/a/5095
1

A friend of mine and me created an iOS and Android app which can crypt messages. To use it, you should create an extension of NSData with following code Snippet from this website:

- (NSData *)AES128EncryptWithKey:(NSString *)key { // 'key' should be 32 bytes for AES256, // 16 bytes for AES256, will be null-padded otherwise char keyPtr[kCCKeySizeAES128 + [key length]]; // room for terminator (unused) bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) // insert key in char array [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; // the encryption method, use always same attributes in android and iPhone (f.e. PKCS7Padding) CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES128, NULL /* initialization vector (optional) */, [self bytes], dataLength, /* input */ buffer, bufferSize, /* output */ &numBytesEncrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; } free(buffer); return nil; } - (NSData *)AES128DecryptWithKey:(NSString *)key { // 'key' should be 32 bytes for AES256, will be null-padded otherwise char keyPtr[kCCKeySizeAES128 + [key length]]; // room for terminator (unused) bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) // insert key in char array [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; NSUInteger dataLength = [self length]; size_t bufferSize = dataLength + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); size_t numBytesDecrypted = 0; CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES128, NULL /* initialization vector (optional) */, [self bytes], dataLength, /* input */ buffer, bufferSize, /* output */ &numBytesDecrypted); if (cryptStatus == kCCSuccess) { return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; } free(buffer); return nil; } + (NSData *)base64DataFromString: (NSString *)string { unsigned long ixtext, lentext; unsigned char ch, inbuf[4], outbuf[3]; short i, ixinbuf; Boolean flignore, flendtext = false; const unsigned char *tempcstring; NSMutableData *theData; if (string == nil){ return [NSData data]; } ixtext = 0; tempcstring = (const unsigned char *)[string UTF8String]; lentext = [string length]; theData = [NSMutableData dataWithCapacity: lentext]; ixinbuf = 0; while (true){ if (ixtext >= lentext){ break; } ch = tempcstring [ixtext++]; flignore = false; if ((ch >= 'A') && (ch <= 'Z')){ ch = ch - 'A'; } else if ((ch >= 'a') && (ch <= 'z')){ ch = ch - 'a' + 26; } else if ((ch >= '0') && (ch <= '9')){ ch = ch - '0' + 52; } else if (ch == '+'){ ch = 62; } else if (ch == '=') { flendtext = true; } else if (ch == '/') { ch = 63; } else { flignore = true; } if (!flignore){ short ctcharsinbuf = 3; Boolean flbreak = false; if (flendtext){ if (ixinbuf == 0){ break; } if ((ixinbuf == 1) || (ixinbuf == 2)) { ctcharsinbuf = 1; } else { ctcharsinbuf = 2; } ixinbuf = 3; flbreak = true; } inbuf [ixinbuf++] = ch; if (ixinbuf == 4){ ixinbuf = 0; outbuf[0] = (inbuf[0] << 2) | ((inbuf[1] & 0x30) >> 4); outbuf[1] = ((inbuf[1] & 0x0F) << 4) | ((inbuf[2] & 0x3C) >> 2); outbuf[2] = ((inbuf[2] & 0x03) << 6) | (inbuf[3] & 0x3F); for (i = 0; i < ctcharsinbuf; i++) { [theData appendBytes: &outbuf[i] length: 1]; } } if (flbreak) { break; } } } return theData; } 

Then inside the class you want to use the crypt methods insert at the top:

#import "NSData+Crypt.h" 

And than encrypt your strings like that:

 NSData *value = [aString dataUsingEncoding:NSUTF8StringEncoding]; NSData *encryptedData = [value AES128EncryptWithKey:myKey]; NSString *myString = [encryptedData base64Encoding]; 

And decrypt the data like this:

NSData *myData = [NSData base64DataFromString:_textView.text]; NSData *decryptedData = [myData AES128DecryptWithKey:_textField.text]; NSString *myString2 = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding]; 

I used the method base64DataFromString from the website of Matt Gallagher otherwise if you use

[[NSData alloc] base64EncodedDataWithOptions:NSUTF8StringEncoding]; 

the method is just available on >= iOS 7.0

1 Comment

If you want to use it inside a project, why don't you use the Objective-C class for calculation and access it through swift?
1

Few important things to note while implementing AES encryption:
1. Never use plain text as encryption key. Always hash the plain text key and then use for encryption.
2. Always use Random IV (initialization vector) for encryption and decryption. True randomization is important. In the examples above, no initialization vector is set. This is a security flaw.
I recently wrote cross platform AES encryption and decryption library for C#, iOS and Android which I have posted on Github. You can see it here - https://github.com/Pakhee/Cross-platform-AES-encryption

2 Comments

Random IV (initialization vector) will always be different for Android and iOS...so the encrypted result would always be different for Android and iOS..right?
Because of Randomness IV has to be transmitted with encrypted data which is a common practice . Both parties have to agree that starting digits are IV and needs to be extracted first. I have seen implementations where random Salt is also used so you transmit Random salt + Random IV + Encrypted data.
0

Check this https://github.com/mataprasad/Cross-platform-AES-encryption-128bit working for iOS, Android, Java backend aligned for same result.

e.g.:

password: "abc@123" Key: "12DA321*2X33%@52" AES Encryption: "3E95waIL9bw07q4ErjJDSw==" 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.