C# 在iOS中存在AES填充问题,但在Android中效果良好

C# 在iOS中存在AES填充问题,但在Android中效果良好,c#,android,ios,encryption,aes,C#,Android,Ios,Encryption,Aes,我正在尝试在iOS中使用AES/CBC加密。解密由C#完成。由Java在Android中完成的加密工作正常。尝试使用iOS代码时,我收到错误“填充无效且无法删除”。请帮忙 请查找下面的C#、Java和Objective C代码 C#代码: Obj C代码: + (NSString*)encryptBase64String:(NSString*)string keyString:(NSString*)keyString separateLines:(BOOL)separateLines {

我正在尝试在iOS中使用AES/CBC加密。解密由C#完成。由Java在Android中完成的加密工作正常。尝试使用iOS代码时,我收到错误“填充无效且无法删除”。请帮忙

请查找下面的C#、Java和Objective C代码

C#代码:

Obj C代码:

+ (NSString*)encryptBase64String:(NSString*)string keyString:(NSString*)keyString separateLines:(BOOL)separateLines
{

    const unsigned char rawSectret[] = {
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00};
    NSData* rawScretdata = [NSData dataWithBytes:rawSectret length:kCCBlockSizeAES128];

    NSString *shaKeyString = [self sha256HashFor:keyString];

    NSData *sourceData = [string dataUsingEncoding:NSUTF8StringEncoding];
    NSString *ivString = [[NSString alloc] initWithData:rawScretdata
                                               encoding:NSUTF8StringEncoding];

    NSData* Outdata = [sourceData AES128EncryptedDataWithKey:shaKeyString  iv:ivString];


    NSString *encodedString = [Outdata base64EncodedStringWithSeparateLines:separateLines];

    return encodedString;
}

- (NSData *)AES128Operation:(CCOperation)operation key:(NSString *)key iv:(NSString *)iv
{
    char keyPtr[kCCKeySizeAES128 + 1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    char ivPtr[kCCBlockSizeAES128 + 1];
    bzero(ivPtr, sizeof(ivPtr));
    if (iv) {
        [iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    }

    NSUInteger dataLength = [self length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(operation,
                                          kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kCCBlockSizeAES128,
                                          ivPtr,
                                          [self bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    free(buffer);
    return nil;
}

Common Crypto使用显式密钥大小,许多其他库基于提供的密钥使用密钥大小,因此您需要确保为Common Crypto指定正确的密钥大小,
KCCKYSIZEAES128
KCCKYSIZEAES192
KCCKYSIZEAES256
,而不是
kCCBlockSizeAES128
。在这种情况下,由于密钥是通过SHA-256
kCCKeySizeAES256
派生的,因此应指定密钥大小

C#正在使用Rijndael,因此必须确保指定的块大小为128,这是AES支持的唯一块大小

只要你得到相同的输入,输出就会匹配。它们是选项(模式和填充)、键、键大小、数据和iv。用十六进制检查它们


提供测试向量:密钥、输入数据和输出数据均为十六进制,因此我们可以测试代码。

通用加密使用显式密钥大小,许多其他库使用基于所提供密钥的密钥大小,因此您需要确保为通用加密指定正确的密钥大小,
kCCKeySizeAES128
KCCKYSIZEAES192
KCCKYSIZEAES256
,而不是
kCCBlockSizeAES128
。在这种情况下,由于密钥是通过SHA-256
kCCKeySizeAES256
派生的,因此应指定密钥大小

C#正在使用Rijndael,因此必须确保指定的块大小为128,这是AES支持的唯一块大小

只要你得到相同的输入,输出就会匹配。它们是选项(模式和填充)、键、键大小、数据和iv。用十六进制检查它们


提供测试向量:所有三个的密钥、输入数据和输出数据均为十六进制,因此我们可以测试代码。

显然您使用的不是AES-128(obj-c),而是AES-256,因为密钥是从SH-A256的密码派生的
rawSecretKey
是IV的字节数组,因此名称有误导性。密码的密钥派生需要像PBKDF2那样具有一百万次迭代和一个随机salt。此外,您没有使用HMAC验证密文。如果是填充问题,则只有最后一个块不正确。从本质上讲,PKCS5Padding和PKCS7Padding是相同的,只是PKCS7Padding的文档允许更大的块大小。显然,您使用的不是AES-128(obj-c),而是AES-256,因为密钥来自SH-A256的密码
rawSecretKey
是IV的字节数组,因此名称有误导性。密码的密钥派生需要像PBKDF2那样具有一百万次迭代和一个随机salt。此外,您没有使用HMAC验证密文。如果是填充问题,则只有最后一个块不正确。PKCS5Padding和PKCS7Padding本质上是相同的,只是PKCS7Padding的文档允许更大的块大小。我应该在哪里更改?我可以看到kCCBlockSizeAES128的多次出现,您在需要块大小的情况下使用它,
kCCBlockSizeAES128
,在需要密钥的情况下使用它。请参阅CCCrypt文档(头文件)。我应该在哪里更改?我可以看到kCCBlockSizeAES128的多次出现,您在需要块大小的情况下使用它,
kCCBlockSizeAES128
,在需要密钥的情况下使用它。请参阅CCCrypt文档(头文件)。
public class Crypto {
    public static final String TAG = Crypto.class.getSimpleName();
    // Replace me with a 16-byte key, share between Java and C#
    private static Cipher aesCipher;
    private static SecretKey secretKey;
    private static IvParameterSpec ivParameterSpec;
    private static String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";
    private static String CIPHER_ALGORITHM = "AES";
    private static byte[] rawSecretKey = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    private static String MESSAGEDIGEST_ALGORITHM = "SHA-256";

    public Crypto(String passphrase) {
        byte[] passwordKey = encodeDigest(passphrase);

        try {
            aesCipher = Cipher.getInstance(CIPHER_TRANSFORMATION);
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "No such algorithm " + CIPHER_ALGORITHM, e);
        } catch (NoSuchPaddingException e) {
            Log.e(TAG, "No such padding PKCS5", e);
        }

        secretKey = new SecretKeySpec(passwordKey, CIPHER_ALGORITHM);
        ivParameterSpec = new IvParameterSpec(rawSecretKey);
    }

    public byte[] decrypt(byte[] clearData) {
        try {
            aesCipher.init(Cipher.DECRYPT_MODE, secretKey);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }

        byte[] decryptedData;

        try {
            decryptedData = aesCipher.doFinal(clearData);
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
            return null;
        } catch (BadPaddingException e) {
            e.printStackTrace();
            return null;
        }
        return decryptedData;

    }

    public String decryptAsBase64(byte[] clearData) throws IOException {
        byte[] decryptedData = decrypt(clearData);
        return new String(Base64New.decode(decryptedData));
    }

    public String encryptAsBase64(byte[] clearData) {
        byte[] encryptedData = encrypt(clearData);
        return Base64New.encodeBytes(encryptedData);
    }

    public byte[] encrypt(byte[] clearData) {
        try {
            aesCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
        } catch (InvalidKeyException e) {
            Log.e(TAG, "Invalid key", e);
            return null;
        } catch (InvalidAlgorithmParameterException e) {
            Log.e(TAG, "Invalid algorithm " + CIPHER_ALGORITHM, e);
            return null;
        }

        byte[] encryptedData;
        try {
            encryptedData = aesCipher.doFinal(clearData);
        } catch (IllegalBlockSizeException e) {
            Log.e(TAG, "Illegal block size", e);
            return null;
        } catch (BadPaddingException e) {
            Log.e(TAG, "Bad padding", e);
            return null;
        }
        return encryptedData;
    }

    private byte[] encodeDigest(String text) {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance(MESSAGEDIGEST_ALGORITHM);
            return digest.digest(text.getBytes());
        } catch (NoSuchAlgorithmException e) {
            Log.e(TAG, "No such algorithm " + MESSAGEDIGEST_ALGORITHM, e);
        }

        return null;
    }
}
+ (NSString*)encryptBase64String:(NSString*)string keyString:(NSString*)keyString separateLines:(BOOL)separateLines
{

    const unsigned char rawSectret[] = {
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00};
    NSData* rawScretdata = [NSData dataWithBytes:rawSectret length:kCCBlockSizeAES128];

    NSString *shaKeyString = [self sha256HashFor:keyString];

    NSData *sourceData = [string dataUsingEncoding:NSUTF8StringEncoding];
    NSString *ivString = [[NSString alloc] initWithData:rawScretdata
                                               encoding:NSUTF8StringEncoding];

    NSData* Outdata = [sourceData AES128EncryptedDataWithKey:shaKeyString  iv:ivString];


    NSString *encodedString = [Outdata base64EncodedStringWithSeparateLines:separateLines];

    return encodedString;
}

- (NSData *)AES128Operation:(CCOperation)operation key:(NSString *)key iv:(NSString *)iv
{
    char keyPtr[kCCKeySizeAES128 + 1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    char ivPtr[kCCBlockSizeAES128 + 1];
    bzero(ivPtr, sizeof(ivPtr));
    if (iv) {
        [iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    }

    NSUInteger dataLength = [self length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(operation,
                                          kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kCCBlockSizeAES128,
                                          ivPtr,
                                          [self bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    free(buffer);
    return nil;
}