iOS和Android中的AES加密,以及C#.NET中的解密

时间:2022-06-19 18:32:51

First thing first. Some time ago I needed a simple AES encryption in Android to encrypt a password and send it as a parameter for a .net web service where the password was decrypted.

首先是第一件事。前段时间我在Android中需要一个简单的AES加密来加密密码,并将其作为密码被解密的.net Web服务的参数发送。

The following is my Android encryption:

以下是我的Android加密:

    private static String Encrypt(String text, String key)
        throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] keyBytes= new byte[16];
        byte[] b= key.getBytes("UTF-8");
        int len= b.length;
        if (len > keyBytes.length) len = keyBytes.length;
        System.arraycopy(b, 0, keyBytes, 0, len);
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
        cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec);

        byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
        String result = Base64.encodeBytes(results);
        return result;
        }

And then I decrypted it in C# with:

然后我用C#解密它:

        public static string Decrypt(string textToDecrypt, string key)
    {
        System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

        RijndaelManaged rijndaelCipher = new RijndaelManaged();
        rijndaelCipher.Mode = CipherMode.CBC;
        rijndaelCipher.Padding = PaddingMode.PKCS7;

        rijndaelCipher.KeySize = 0x80;
        rijndaelCipher.BlockSize = 0x80;

        string decodedUrl = HttpUtility.UrlDecode(textToDecrypt);
        byte[] encryptedData = Convert.FromBase64String(decodedUrl);
        byte[] pwdBytes = Encoding.UTF8.GetBytes(key);
        byte[] keyBytes = new byte[0x10];
        int len = pwdBytes.Length;
        if (len > keyBytes.Length)
        {
            len = keyBytes.Length;
        }
        Array.Copy(pwdBytes, keyBytes, len);
        rijndaelCipher.Key = keyBytes;
        rijndaelCipher.IV = keyBytes;
        byte[] plainText = rijndaelCipher.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length);
        return encoding.GetString(plainText);
    }

This worked like a charm, but the problems came when I tried to do the same in iOS. I am pretty new developing applications for the iphone/ipad, so ofcause I googled it, and almost every code sample provided was the following:

这就像一个魅力,但问题来自我试图在iOS中做同样的事情。我是非常新开发的iphone / ipad应用程序,所以因为我用Google搜索它,几乎每个提供的代码示例如下:

- (NSData *)AESEncryptionWithKey:(NSString *)key {
char keyPtr[kCCKeySizeAES128]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

NSUInteger dataLength = [self length];

size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);

size_t numBytesEncrypted = 0;

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                      keyPtr, kCCKeySizeAES128,
                                      NULL /* initialization vector (optional) */,
                                      [self bytes], [self length], /* input */
                                      buffer, bufferSize, /* output */
                                      &numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
    //the returned NSData takes ownership of the buffer and will free it on deallocation
    return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}

free(buffer); //free the buffer;
return nil;

}

Maybe I was a little bit too optimistic, when I was hoping for a smooth transition here, because when the Android is throwing me something like:

也许我有点过于乐观,当我希望在这里顺利过渡时,因为当Android给我一些东西时:

"EgQVKvCLS4VKLoR0xEGexA=="

then the iOS gives me:

然后iOS给了我:

"yP42c9gajUra7n0zSEuVJQ=="

Hopefully it is just something I forgot, or some of the settings are wrong?

希望这只是我忘记的东西,或者某些设置是错误的?

[UPDATE] The results are now showed after the base64 encoding.

[更新]结果现在显示在base64编码之后。

1 个解决方案

#1


5  

First note is that you have significant security issues in this code. You're taking a string password and just dropping that into a key. If that string human-typable, then you've dramatically constricted your keyspace (turning AES-128 into more like AES-40 or AES-50, maybe even worse). You need to salt and stretch the key using PBKDF2. See Properly encrypting with AES with CommonCrypto for a fuller discussion.

首先要注意的是,此代码中存在重大安全问题。您正在使用字符串密码并将其放入密钥中。如果那个字符串是人类可用的,那么你就会极大地限制你的密钥空间(将AES-128变成更像AES-40或AES-50,甚至可能更糟)。您需要使用PBKDF2对密钥进行加盐和拉伸。有关更充分的讨论,请参阅使用CommonCrypto对AES进行正确加密。

You also have a significant security problem because you're using your key as your IV (see more below; this is actually the cause of your symptom). This is not the correct way to pick an IV and makes your ciphertext predictable. Identical plaintext encrypted with the same key will give the same result. This is similar to having no IV at all. The IV needs to be random. See the above link for more discussion.

您还有一个严重的安全问题,因为您正在使用您的密钥作为您的IV(请参阅下面的内容;​​这实际上是您症状的原因)。这不是选择IV的正确方法,并使您的密文可预测。使用相同密钥加密的相同明文将给出相同的结果。这类似于完全没有IV。 IV必须是随机的。有关更多讨论,请参阅上面的链接。

Now to your actual symptom. The problem is that you are using the key as the IV in Java and C#, but you're using 0 (NULL) as the IV on iOS (the IV is not optional; you're just passing 0). You need to use the same IV in all cases.

现在你的实际症状。问题是你在Java和C#中使用密钥作为IV,但你在iOS上使用0(NULL)作为IV(IV不是可选的;你只是传递0)。在所有情况下,您都需要使用相同的IV。

#1


5  

First note is that you have significant security issues in this code. You're taking a string password and just dropping that into a key. If that string human-typable, then you've dramatically constricted your keyspace (turning AES-128 into more like AES-40 or AES-50, maybe even worse). You need to salt and stretch the key using PBKDF2. See Properly encrypting with AES with CommonCrypto for a fuller discussion.

首先要注意的是,此代码中存在重大安全问题。您正在使用字符串密码并将其放入密钥中。如果那个字符串是人类可用的,那么你就会极大地限制你的密钥空间(将AES-128变成更像AES-40或AES-50,甚至可能更糟)。您需要使用PBKDF2对密钥进行加盐和拉伸。有关更充分的讨论,请参阅使用CommonCrypto对AES进行正确加密。

You also have a significant security problem because you're using your key as your IV (see more below; this is actually the cause of your symptom). This is not the correct way to pick an IV and makes your ciphertext predictable. Identical plaintext encrypted with the same key will give the same result. This is similar to having no IV at all. The IV needs to be random. See the above link for more discussion.

您还有一个严重的安全问题,因为您正在使用您的密钥作为您的IV(请参阅下面的内容;​​这实际上是您症状的原因)。这不是选择IV的正确方法,并使您的密文可预测。使用相同密钥加密的相同明文将给出相同的结果。这类似于完全没有IV。 IV必须是随机的。有关更多讨论,请参阅上面的链接。

Now to your actual symptom. The problem is that you are using the key as the IV in Java and C#, but you're using 0 (NULL) as the IV on iOS (the IV is not optional; you're just passing 0). You need to use the same IV in all cases.

现在你的实际症状。问题是你在Java和C#中使用密钥作为IV,但你在iOS上使用0(NULL)作为IV(IV不是可选的;你只是传递0)。在所有情况下,您都需要使用相同的IV。