iOS中的AES填充问题,但在Android

时间:2015-10-08 12:50:55

标签: c# android ios encryption aes

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

请在下面找到C#,Java和Objective C代码。

C#代码:

namespace InternetMobileService
{
    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    using System.Xml;


    public class EncryptDecrypt
    {
        //// Replace me with a 16-byte key, share between Java and C#

        /// <summary>
        /// rawSecretKey values
        /// </summary>
        private static byte[] rawSecretKey = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

        /// <summary>
        /// variable field
        /// </summary>
        private ICryptoTransform rijndaelDecryptor;

        /// <summary>
        /// Initializes a new instance of the <see cref="EncryptDecrypt"/> class.
        /// </summary>
        /// <param name="passphrase">pass phrase</param>
        public EncryptDecrypt(string passphrase)
        {
            byte[] passwordKey = EncodeDigest(passphrase);
            RijndaelManaged rijndael = new RijndaelManaged();
            this.rijndaelDecryptor = rijndael.CreateDecryptor(passwordKey, rawSecretKey);
        }


        public static byte[] EncodeDigest(string text)
        {
            SHA256CryptoServiceProvider x = new System.Security.Cryptography.SHA256CryptoServiceProvider();
            byte[] data = Encoding.ASCII.GetBytes(text);
            return x.ComputeHash(data);
        }


        public static string Encrypt(string plainText)
        {
            using (RijndaelManaged myRijndael = new RijndaelManaged())
            {
                byte[] passwordKey = EncodeDigest(System.Configuration.ConfigurationManager.AppSettings["ConstructorKey"].ToString());
                byte[] encrypted = EncryptStringToBytes(plainText, passwordKey, rawSecretKey);
                return Convert.ToBase64String(encrypted);
            }
        }


        public static byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iV)
        {
            if (plainText == null || plainText.Length <= 0)
            {
                throw new ArgumentNullException("plainText");
            }

            if (key == null || key.Length <= 0)
            {
                throw new ArgumentNullException("key");
            }

            if (iV == null || iV.Length <= 0)
            {
                throw new ArgumentNullException("key");
            }

            byte[] encrypted;
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = key;
                rijAlg.IV = iV;
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
                using (MemoryStream memorystreamEncrypt = new MemoryStream())
                {
                    using (CryptoStream cryptostreamEncrypt = new CryptoStream(memorystreamEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter streamwriterEncrypt = new StreamWriter(cryptostreamEncrypt))
                        {
                            streamwriterEncrypt.Write(plainText);
                        }

                        encrypted = memorystreamEncrypt.ToArray();
                    }
                }
            }

            return encrypted;
        }


        public string Decrypt(byte[] encryptedData)
        {            
            byte[] newClearData = this.rijndaelDecryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
            return Encoding.ASCII.GetString(newClearData);
        }


        public string DecryptFromBase64(string encryptedBase64)
        {
            return this.Decrypt(Convert.FromBase64String(encryptedBase64));
        }
    }
}

Java代码:

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;
    }
}

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;
}

1 个答案:

答案 0 :(得分:0)

Common Crypto使用显式密钥大小,许多其他库使用基于提供的密钥的密钥大小,因此您需要确保为Common Crypto指定正确的密钥大小,kCCKeySizeAES128之一,{{1 },kCCKeySizeAES192,而不是kCCKeySizeAES256。在这种情况下,因为密钥是使用SHA-256 kCCBlockSizeAES128派生的,所以应该指定密钥大小。

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

简单地说,如果输入相同,输出将匹配。它们是选项(模式和填充),密钥,密钥大小,数据和iv。用十六进制检查它们。

为所有三个提供测试向量:十六进制的键,输入数据和输出数据,以便我们可以测试代码。