0

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,

  1. 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.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • 2
    Since the key is a "user provided password", it must be subject to an entropy-stretching function, aka password(-based) hash, in charge of turning it into an AES key in a way giving some level of protection against password searching. The contrary would be quite insecure and utterly unprofessional (but not uncommon). It looks like you are missing that step. According to [this](https://en.wikipedia.org/wiki/PBKDF2#Purpose_and_operation), Apple has sometime used some parametrization of PBKDF2 for entropy stretching. This group is not for such implementation details, perhaps try security.SE – fgrieu Jul 06 '18 at 08:48
  • @fgrieu "Entropy-stretching" is a bad word choice. It will be interpreted to mean "something that adds or multiplies entropy". Entropy cannot be increased by deterministic process. "Password stretching" and "key stretching" don't have that danger. Maybe "Input stretching" if you want a shorthand generic term. – Future Security Jul 06 '18 at 22:33

0 Answers0