RC2 实现差异 C# 和 Python?

RC2 Implementation differences C# and Python?

出于 compatibility/legacy 原因,我需要在 CBC 模式下使用 RC2 加密 。 我正在编写一个测试 - 但我在 C# 中得到完全不同的结果,Python 和在线工具,具有(看似)相同的输入值。

对于所有实现,我使用了以下数据:

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# 和 an online tool called CyberChef 对此进行测试。 都给了我完全不同的结果。

Python 结果: d123f2ac56146f3cebd19b285eb1e1744b828a177778be07

C# 结果f278304ee422a8bbccd54c9157afa818ac4e5b21858ff267

Cyber​​Chef 结果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;
}

所以 - 为什么我到处都得到不同的结果?我尝试使用一些 CBC 测试向量,我唯一能找到的是这些:http://cryptomanager.com/tv.html

如何确保哪个结果是正确的? 为什么所有的实现都会产生不同的结果?

RC2 在RFC2268. It's a block cipher with variable key length and has an additional parameter called effective key length in bits, see RFC2268, Section 2 中有描述。在这两个代码和网站上,使用了不同的有效密钥位长度,导致不同的结果。

在 Python 代码中,当使用 PyCryptodome 时,在创建 ARC2-cipher instance, which may have values between 40 and 1024, where 1024 is the default value. Since the parameter isn't explicitly specified in the posted Python code, the default value is used. Note that this parameter is described in the PyCrypto 文档时使用参数 effective_keylen 指定有效密钥长度(以位为单位),但在 PyCryptodome 中没有文档。

effective_keylen = 128website 结果的密文。在网站上似乎无法更改以位为单位的有效密钥长度。

无法重现C#代码的密文,可能是因为GetRc2Provider中没有设置IV(所以使用了随机生成的IV)。如果这是固定的,结果表明以位为单位的有效密钥长度 (RC2CryptoServiceProvider#EffectiveKeySize) 被隐式设置为实际密钥长度。如果参数显式切换为另一个值,则会抛出 System.Security.Cryptography.CryptographicUnexpectedOperationException: EffectiveKeySize must be the same as KeySize in this implementation.