C# RijndaelManaged в 10 раз мощнее, чем эквивалент Java (AES/CFB8/NoPadding)

Отлаживая производительность моего приложения на C#, я заметил, что он намного медленнее, чем его эквивалентность Java. После рассмотрения проблемы проблема, кажется, вызвана методами шифрования / дешифрования.

Я вынужден использовать шифрование AES с режимом CFB8 и без заполнения. Для Java это довольно просто, так как я могу использовать Cipher.getInstance("AES/CFB8/NoPadding");, В C# я узнал, что мне нужно использовать new RijndaelManaged(), После запуска тестов с теми же ключами и теми же данными, вот результаты:

Джава:

  • Шифровать: 0,402 с
  • Расшифровать: 0,480 с

C#:

  • Зашифровать: 4.201
  • Расшифровать: 3.671 с

C# код шифра:

    public ICryptoTransform enc;
    public ICryptoTransform dec;

    public AesCrypto(byte[] key)
    {
        enc = Generate(key).CreateEncryptor();
        dec = Generate(key).CreateDecryptor();
    }

    private SymmetricAlgorithm Generate(byte[] key) {
        RijndaelManaged cipher = new RijndaelManaged(); 
        cipher.Mode = CipherMode.CFB;
        cipher.Padding = PaddingMode.None;
        cipher.KeySize = 128;
        cipher.FeedbackSize = 8;
        cipher.Key = key;
        cipher.IV = key;
        return cipher;
    }

    public byte[] Crypt(byte[] buffer, int offset, int count) {
        return enc.TransformFinalBlock(buffer, offset, count); 
    }

C# Тестовый код:

 static void Test() {
        // Init
        var AesCrypto = new AesCrypto(Encoding.UTF8.GetBytes("aaabbbccaaabbbcc"));
        var testData = Encoding.UTF8.GetBytes(createDataSize(9000000)); // 9mb test.

        // Timer
        var stopWatch = new Stopwatch();
        stopWatch.Start();
        AesCrypto.Crypt(testData, 0, testData.Length);
        stopWatch.Stop();
        Console.WriteLine("AesCrypto.Crypt took: " + stopWatch.ElapsedMilliseconds);
 }
 static string createDataSize(int msgSize)
    {
        StringBuilder sb = new StringBuilder(msgSize);
        for (int i = 0; i < msgSize; i++)
        {
            sb.Append('a');
        }
        return sb.ToString();
    }

Результат: "AesCrypto.Crypt взял: 3626"

Код JAVA шифра:

public Cryptor(boolean reader) throws CryptingException {

    keySpec = new SecretKeySpec(secretKey.getBytes(CHARSET), "AES");
    ivSpec = new IvParameterSpec(iv.getBytes(CHARSET));
    try {
        cipher = Cipher.getInstance("AES/CFB8/NoPadding");
        if (reader) cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        else cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
    } catch (NoSuchAlgorithmException e) {
        throw new SecurityException(e);
    } catch (NoSuchPaddingException e) {
        throw new SecurityException(e);
    }catch (InvalidKeyException e) {
        throw new SecurityException(e);
    } catch (InvalidAlgorithmParameterException e) {
        throw new SecurityException(e);
    }
}

public byte[] decrypt(byte[] input) throws CryptingException {
        return cipher.update(input);
}

public byte[] encrypt(String input) throws CryptingException {
    return cipher.update(input.getBytes());
}

Тестовый код Java:

private static void Test() {
    // Init
    String data = createDataSize(9392963);
    Cryptor writer = new Cryptor(false);

    // Timer
    Instant starts = Instant.now();
    byte[] encrypted = writer.encrypt(data);
    Instant ends = Instant.now();
    System.out.println("Java Encryption took: " + Duration.between(starts, ends));
}
private static String createDataSize(int msgSize) {
      StringBuilder sb = new StringBuilder(msgSize);
      for (int i=0; i<msgSize; i++) {
        sb.append('a');
      }
      return sb.toString();
}

Результат: "Шифрование Java заняло: PT0.469S"

Возможное решение:

Изучив это совсем немного, кажется, что AesCryptoServiceProvider() имеет примерно ту же производительность, что и эквивалентность Java, и имеет в основном идентичные результаты. Однако проблема в том, что он требует заполнения, тогда как эквивалентность Java не требует заполнения. Например, это означает, что если я захочу зашифровать "abcdab", он зашифрует только "abcd" и вернет для этого результат, а оставшуюся часть ("ab") сохранит внутри. Если я использую заполнение, я могу заставить его возвращать полный зашифрованный abcdab, однако тогда к нему добавляются дополнительные данные, и симметричный алгоритм не синхронизируется, потому что в java я мог шифровать "abcdab" без каких-либо дополнений.

Вопрос

Итак, наконец, мой вопрос: как бы я мог сделать процесс шифрования / дешифрования в C# таким же быстрым, как и в Java? Я делаю что-то не так с AesCryptoServiceProviderМожет быть, это возможно, чтобы не требовать дополнения?

0 ответов

Другие вопросы по тегам