2

出于兼容性/遗留原因,我需要在 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# 和名为 Cyber​​Chef 的在线工具对此进行测试。都给了我完全不同的结果。

蟒蛇结果d123f2ac56146f3cebd19b285eb1e1744b828a177778be07

C# 结果f278304ee422a8bbccd54c9157afa818ac4e5b21858ff267

网络厨师结果c91e276fc97e71acb72426f29c3a6c6f5181d8e83dcf1a98

蟒蛇脚本:

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

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

4

1 回答 1

4

RC2 在RFC2268中进行了描述。它是一种具有可变密钥长度的分组密码,并且有一个称为有效密钥长度(以位为单位)的附加参数,请参阅RFC2268,第 2 节。在这两个代码和网站上,使用了不同的有效密钥长度(以位为单位),导致结果不同。

在 Python 代码中,使用 PyCryptodome 时,effective_keylen在创建ARC2 -cipher 实例时使用参数指定有效密钥长度(以位为单位),其值可能介于 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.则抛出 a。

于 2020-02-19T02:22:19.840 回答