Java – AES encrypts Android < - > different results of IOS, and the message length is > 15 bytes
I had a real problem understanding the password / encryptor on both devices
1. If we use cipher AES to encrypt messages on IOS and Android and the charlength of the string is not greater than 16 (e.g. "abcdefghijklmno"), we will get the same result after using the same key / password for encryption
2. However, if we need a longer message, we will get different results on IOS and Android (e.g. "abcdefghijklmnop")
I did a lot of research on how to get the same parameters for these two devices. At first, I thought it was safe
This is my password for encryption:
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 //EDITED AFTER RIGHT ANSWER FROM //*** Cipher cipher = Cipher.getInstance("AES"); ***// // TO 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 ""; } 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,keyBytes,length); SecretKeySpec key = new SecretKeySpec(keyBytes,"AES"); return key; }
This is my colleague's IOS Pendant:
- (NSData *)AES128EncryptWithKey:(NSString *)key { // 'key' should be 32 bytes for AES256,// 16 bytes for AES256,will be null-padded otherwise char keyPtr[kCCKeySizeAES128 + 1]; // 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; }
I really want to know what the difference is and how to avoid it The test with a larger string of more than 15 characters gave me a hint, but I don't know why:)
Thank you first!
Solution
Check the padding being used on both systems Different padding will result in different outputs Do not rely on default values, but explicitly set the padding on both sides Your second code snippet explicitly sets the PKCs 7 population Use it at both ends
As a general rule, do not rely on default values between different systems Explicitly set IV, mode, padding, random number or anything else you need Even if the smallest details do not match, encryption will fail