Подтвердить что ты не робот

AES в iOS и Android и расшифровка в С#.NET

Прежде всего. Некоторое время назад мне понадобилось простое шифрование AES в Android для шифрования пароля и отправки его в качестве параметра для веб-службы .net, где пароль был расшифрован.

Следующее - это мое 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;
        }

И затем я расшифровал его в С# с помощью:

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

Это работало как прелесть, но проблемы возникли, когда я попытался сделать то же самое в iOS. Я довольно новые разработки приложений для iphone/ipad, поэтому из-за того, что я искал его, и почти каждый предоставленный образец кода был следующим:

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

}

Возможно, я был немного оптимистичен, когда я надеялся на плавный переход сюда, потому что, когда Android бросает мне что-то вроде:

"EgQVKvCLS4VKLoR0xEGexA=="

то iOS дает мне:

"yP42c9gajUra7n0zSEuVJQ=="

Надеюсь, это просто что-то, что я забыл, или некоторые из настроек неверны?

[UPDATE] Результаты теперь отображаются после кодировки base64.

4b9b3361

Ответ 1

Прежде всего, у вас есть серьезные проблемы с безопасностью в этом коде. Вы берете строковый пароль и просто бросаете это в ключ. Если бы эта строка была типичной для человека, тогда вы резко сократили свое пространство ключей (превращение AES-128 в более похожее на AES-40 или AES-50, может быть, даже хуже). Вам нужно солить и растянуть ключ, используя PBKDF2. См. Правильное шифрование с помощью AES с помощью CommonCrypto для более полного обсуждения.

У вас также есть существенная проблема с безопасностью, потому что вы используете свой ключ как ваш IV (см. ниже, это на самом деле причина вашего симптома). Это не правильный способ выбрать IV и сделать ваш зашифрованный текст предсказуемым. Идентичный открытый текст, зашифрованный одним и тем же ключом, даст тот же результат. Это похоже на отсутствие IV вообще. IV должен быть случайным. См. Выше ссылку для дальнейшего обсуждения.

Теперь к вашему фактическому симптому. Проблема в том, что вы используете ключ как IV в Java и С#, но используете 0 (NULL) как IV на iOS (IV не является необязательным, вы просто проходите 0). Вы должны использовать тот же IV во всех случаях.