RC2 Отличия реализации C# и Python? - PullRequest
2 голосов
/ 19 февраля 2020

Из соображений совместимости / унаследования мне необходимо использовать шифрование RC2 в режиме CB C . Я пишу тест - но я получаю совершенно разные результаты в C#, Python и с Online Tools, с (на вид) одинаковыми входными значениями.

Для всех реализаций я использовал следующие данные:

Data: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 
Key: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00    
IV: 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08   
Mode: CBC    
Padding: PKCS7

Я пытался протестировать это с Python, C# и с помощью онлайн-инструмента под названием CyberChef . Все дали мне совершенно разные результаты.

Python Результат : d123f2ac56146f3cebd19b285eb1e1744b828a177778be07

C# Результат : f278304ee422a8bbccd54c9157afa818ac4e5b21858ff267

Результат CyberChef : c91e276fc97e71acb72426f29c3a6c6f5181d8e83dcf1a98

Сценарии python:

from Crypto.Cipher import ARC2
from Crypto.Util.Padding import pad
input = bytes([0]*16)
key = bytes([0]*8)
iv = b"\x01\x02\x03\x04\x05\x06\x07\x08"

cipher = ARC2.new(key, ARC2.MODE_CBC, iv=iv)

msg = cipher.encrypt(pad(input,8,style='pkcs7'))
print("{} {}".format(len(msg), msg.hex()))

C# Сценарий (части):

public byte[] Encrypt(Rc2CryptoParameters cryptoParameters)
{
    using var outputStream = new MemoryStream();
    using var provider = GetRc2Provider(cryptoParameters);
    using var encryptor = provider.CreateEncryptor();
    using var cryptoStream = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write);

    cryptoStream.Write(cryptoParameters.Data);
    cryptoStream.Close();
    return outputStream.ToArray();
}

private RC2CryptoServiceProvider GetRc2Provider(Rc2CryptoParameters cryptoParameters)
{
    return new RC2CryptoServiceProvider
    {
        Key = cryptoParameters.Key,
        BlockSize = cryptoParameters.BlockSize,
        KeySize = cryptoParameters.KeySize,
        Padding = cryptoParameters.PaddingMode,
        Mode = cryptoParameters.CipherMode
    };
}

public Rc2CryptoParameters(byte[] data, byte[] key, byte[] iv)
{
    Data = data;
    Iv = iv;
    Key = key;
    CipherMode = CipherMode.CBC;
    PaddingMode = PaddingMode.PKCS7;
}

Итак - почему я везде получаю разные результаты? Я попытался использовать несколько тестовых векторов CB C, я смог найти только следующие: http://cryptomanager.com/tv.html

Как я могу убедиться, какой из результатов правильный? Почему все реализации дают разные результаты?

1 Ответ

4 голосов
/ 19 февраля 2020

RC2 описано в RFC2268 . Это блочный шифр с переменной длиной ключа и имеет дополнительный параметр, называемый эффективная длина ключа в битах , см. RFC2268, раздел 2 . В двух кодах и на веб-сайте используется разная эффективная длина ключа в битах, что приводит к разным результатам.

В коде Python при использовании PyCryptodome эффективная длина ключа в битах указывается параметром effective_keylen при создании экземпляра шифра ARC2 , который может иметь значения между 40 и 1024, где 1024 является значением по умолчанию. Поскольку параметр явно не указан в опубликованном коде Python, используется значение по умолчанию. Обратите внимание, что этот параметр описан в документации PyCrypto , но не в документации PyCryptodome.

Зашифрованный текст веб-сайта приводит к effective_keylen = 128. На веб-сайте, кажется, нет возможности изменить эффективную длину ключа в битах.

Зашифрованный текст кода C# не может быть воспроизведен, возможно, потому что IV не установлен в GetRc2Provider (так что используется случайно сгенерированный IV). Если это исправлено, оказывается, что эффективная длина ключа в битах (RC2CryptoServiceProvider#EffectiveKeySize) неявно установлена ​​на фактическую длину ключа. Если параметр явно переключен на другое значение, выдается System.Security.Cryptography.CryptographicUnexpectedOperationException: EffectiveKeySize must be the same as KeySize in this implementation..

...