匹配iOS和& Android AES - 糟糕的填充

时间:2014-11-25 22:05:56

标签: android ios encryption aes

我有一个奇怪的问题,试图匹配现有的iOS应用程序,.net服务器和我正在处理的Android应用程序之间的解密。我已经检查过我的程序输出字节的字节与iOS的加密方式相同,并且完全解密了它自己的数据包。似乎服务器能够解密从Android应用程序发送的数据包,但是当我尝试解码来自服务器的数据包时,我在Android上获得BadPaddingException,而iOS版本正确解码。我还检查过Key和IV是字节相同的。

编辑:我已经从我的客户端添加了服务器端代码(UDP套接字侦听器的一部分),乍一看它似乎没有正确定义填充,但我的研究表明默认是PKCS7,所以我仍然对导致问题的原因感到困惑。

我在解密之前和之后测试了消息长度(来自服务器),我看到了2条不同的消息。一个是解密前16字节的空保持消息,解密后的0字节。在iOS中,第二条消息在解密前为128字节,在解密后为112字节。两者都无法在Android中解密。

的iOS:

+ (NSData*)decryptData:(NSData*)data key:(NSData*)key iv:(NSData*)iv; 
{
    int FBENCRYPT_BLOCK_SIZE = kCCBlockSizeAES128; 
    int FBENCRYPT_KEY_SIZE = kCCKeySizeAES256;

    // setup key
    unsigned char cKey[FBENCRYPT_KEY_SIZE];
    bzero(cKey, sizeof(cKey));
    [key getBytes:cKey length:FBENCRYPT_KEY_SIZE];

    // setup iv
    char cIv[FBENCRYPT_BLOCK_SIZE];
    bzero(cIv, FBENCRYPT_BLOCK_SIZE);
    if (iv) {
        [iv getBytes:cIv length:FBENCRYPT_BLOCK_SIZE];
    }

    NSData* Result = nil;

    // setup output buffer
    size_t bufferSize = [data length] + FBENCRYPT_BLOCK_SIZE;
    void *buffer = malloc(bufferSize);

    // do decrypt
    size_t decryptedSize = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding,
                                          cKey,
                                          kCCKeySizeAES256,
                                          cIv,
                                          [data bytes],
                                          [data length],
                                          buffer,
                                          bufferSize,
                                          &decryptedSize);
    if (cryptStatus == kCCSuccess) {
        result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
    } else {
        free(buffer);
        NSLog(@"[ERROR] failed to decrypt| CCCryptoStatus: %d", cryptStatus);
    }

    return result;  
}

机器人:

byte[] decryptData(byte[] data, byte[] key, byte[] iv)
{
    static int FBENCRYPT_BLOCK_SIZE = 16; //(kCCBlockSizeAES128) 
    static int FBENCRYPT_KEY_SIZE = 32; //(kCCKeySizeAES256)        
    // setup key
    byte[] cKey = new byte[FBENCRYPT_KEY_SIZE];
    Arrays.fill(cKey, (byte) 0x00);

    int num = FBENCRYPT_KEY_SIZE;
    if (key.length<num)
        num = key.length;
    System.arraycopy(key, 0, cKey, 0, num);

    // setup iv
    byte[] cIv = new byte[FBENCRYPT_BLOCK_SIZE];
    Arrays.fill(cIv, (byte) 0x00);
    if (iv!=null) {
        System.arraycopy(iv, 0, cIv, 0, iv.length);
    } 

    Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
    SecretKeySpec skeySpec = new SecretKeySpec(cKey, "AES");
    IvParameterSpec ivParameterSpec = new IvParameterSpec(cIv);
    aesCipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
    byte[] byteCipherText = aesCipher.doFinal(data);
    return byteCipherText;
}

服务器C#:

        public enum AESBitCounts
    {
        AES64Bit = 8,
        AES128Bit = 16,
        AES256Bit = 32
    }
    public static byte[] Encrypt(byte[] RawPayload, byte[] key, AESBitCounts AESBitCount)
    {
        Symmetric sym = new Symmetric(Symmetric.Provider.Rijndael, false);
        //sym.mcrypto.Padding = System.Security.Cryptography.PaddingMode.None;
        sym.IntializationVector = new Data(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
        Data deckey = new Data();
        deckey.MinBytes = (Int32)AESBitCount;
        deckey.MaxBytes = (Int32)AESBitCount;
        deckey.Bytes = key;
        Byte fred = deckey.Bytes[0];
        Data encrypted = sym.Encrypt(new Data(RawPayload), deckey);
        return encrypted.Bytes;
    }

1 个答案:

答案 0 :(得分:1)

事实证明,CCCrypt和Cipher之间存在一个重要区别,CCCrypt将返回它能够解密的任何数据,而Cipher一旦得到填充错误,就不会返回任何数据。似乎我的客户端的服务器端脚本正在破坏填充块,以便任何短于16字节的消息在iOS上被解密为null,并且在主消息的情况下只是丢弃填充块。我能够通过在解码之前切断最后16个字节来复制iOS代码的结果,如果没有剩余字节则返回null,并且从使用Cipher.doFinal切换到Cipher.update,这不会期望最终填充阻止出席。

编辑:我实际上并不需要消除最后16个字节。只需从doFinal切换到更新即可。