I am trying to decrypt a string encrypted via Apple's CommonCrypto API. It is using AES/CBC/PKCS7Padding
. It takes the input string and a user provided password and generates the corresponding encrypted string which is Base64
encoded.
However, I have tried almost everything I found on SO on the related context but failed to decrypt the string. The issue is javax.crypto.BadPaddingException: pad block corrupted
which essentially means a bad key. The iOS encryption manually pads a short key < 25 Bytes (in this case only) by appending a char 0
. Now the CCryptStatus
takes in the key length as 32 Bytes so my first question is that,
- Despite providing a key less than the required length how is CommonCrypto encrypting the string with a short key?
Following are some specs of one such example
input String "XnV6f4YLAzkLvJ2CIJTC5g==2uXT5CSYKLUrL7+MkJ4IDw=="
_core _StringCore
userPassword String "123456789"
paddedKey String "1234567890000000000000000"
keyData NSData? 25 bytes 0x0000600000a4c360
numBytesEncrypted size_t 10
dataLength size_t 16
encryptedData NSMutableData? 10 bytes 0x0000604000842e20
ptrToData UnsafeMutableRawPointer
lengthOfData size_t 32
keyLength size_t 32
operation CCOperation 1
algoritm CCAlgorithm 0
options CCOptions 1
cryptStatus CCCryptorStatus 0
data NSString "Hello Jash" 0x0000600000631500
result String "Hello Jash"
Following is my decrypt method in Java using Cipher API based on a snippet found in a SO question.
String message = "XnV6f4YLAzkLvJ2CIJTC5g==2uXT5CSYKLUrL7+MkJ4IDw==";
String userKey = "123456789";
private static String decrypt (String message, String userKey) throws UnsupportedEncodingException,
NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidKeyException,
ShortBufferException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, NoSuchProviderException {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
if (message.length() >= 48) {
ivFromEncryptedString = message.substring(0, Math.min(message.length(), 24));
messageFromEncryptedString = message.substring(24, message.length());
System.out.println(ivFromEncryptedString);
System.out.println(messageFromEncryptedString);
byte[] data = decodeBase64(messageFromEncryptedString);
byte[] ivData = decodeBase64(ivFromEncryptedString);
paddedKey = padShortKeys(userKey);
byte[] keyBytes = paddedKey.getBytes(CHARSET);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivData);
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
byte [] encrypted = new byte[cipher.getOutputSize(data.length)];
int ctLength = cipher.update(data, 0, data.length, encrypted, 0);
ctLength += cipher.doFinal(encrypted, ctLength);
} catch (Exception e) {
System.out.println(e);
} finally {
return encrypted;
}
}
return null;
}
private static String encodeBase64(byte [] in){
return Base64.getEncoder().encodeToString(in);
}
private static byte[] decodeBase64(String str) throws UnsupportedEncodingException {
return DatatypeConverter.parseBase64Binary(str);
}
Can someone point me in the right direction what am I missing here? I am not a security expert or even intermediate individual. I have tried my best to grasp these concepts without diving into much detail. Is there any way to obtain same results in this Java code and decrypt the string?
I tried using SHA-256
for MessageDigest
which turns the 25 Bytes padded key to 32 Bytes but the exception clearly indicates that there is something wrong with the key.