繁体   English   中英

iOS中的AES填充问题,但在Android中工作正常

[英]AES Padding issue in iOS but works fine in Android

我正在尝试在iOS中使用AES / CBC加密。 解密由C#完成。 Java在Android中完成的加密工作正常。 我收到错误消息:“填充无效,无法删除。” 尝试使用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;
    }
}

对象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( kCCKeySizeAES128kCCKeySizeAES192kCCKeySizeAES256而非kCCBlockSizeAES128指定正确的密钥大小。 在这种情况下,由于密钥是使用SHA-256派生的,因此kCCKeySizeAES256是应指定的密钥大小。

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

简单来说,如果您获得相同的输入,则输出将匹配。 它们是选项(模式和填充),键,键大小,数据和iv。 十六进制检查它们。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM