【问题标题】:Rijndael: C++ encryption, C# decryptionRijndael:C++ 加密、C# 解密
【发布时间】:2016-02-17 07:55:54
【问题描述】:

我的情况:我正在用 C# 重写一个服务器,它是用 C++ 编写的,用于学习目的。在某些时候,客户端会向服务器发送一个加密的密码。他们使用 Rijndael 加密密码。 你可以在这里找到原始的加密类:

Rijndael.h:https://github.com/astorks/FlyFF/blob/master/Source/_Common/Rijndael.h

Rijndael.cpp:https://github.com/astorks/FlyFF/blob/master/Source/_Common/Rijndael.cpp#L926

正如您在 .cpp 文件中所见,他们使用此密钥和 IV:

char const* CRijndael::sm_chain0 = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

char    szDefaultKey[32] = "dldhsvmflvm";

这是他们实际解密原始服务器中密码的部分 (https://github.com/astorks/FlyFF/blob/master/Source/CERTIFIER/DPCertifier.cpp#L256)

// MAX_PASSWORD is actually 42. So 16*42 = 672 byte
char szEnc[ 16 * MAX_PASSWORD ] = {0, };
char szDec[ 16 * MAX_PASSWORD ] = {0, };

ar.Read( szEnc, 16 * MAX_PASSWORD );

g_xRijndael->ResetChain();
g_xRijndael->Decrypt( szEnc, szDec, 16 * MAX_PASSWORD, CRijndael::CBC );

现在我正处于从客户端正确获取数据包以及需要解密密码的位置。我当前的 C# 代码没有正确解密数据,我不知道为什么。这是我的代码:

public static class Rijndael
    {
        private static ICryptoTransform decryptor { get; set; }
        private static RijndaelManaged rijndael { get; set; }

        public static void Init()
        {
            byte[] decryptKey = Encoding.ASCII.GetBytes("dldhsvmflvm").Concat(Enumerable.Repeat((byte)0, 21).ToArray()).ToArray();
            byte[] decryptIV = Enumerable.Repeat((byte)0, 16).ToArray();
            // I've tried BlockSize 128 and 256. It actually should be 128 since it's 16 on the original server (16 * 8 = 128)
            rijndael = new RijndaelManaged() { Padding = PaddingMode.Zeros, Mode = CipherMode.CBC, KeySize = 256, BlockSize = 128, Key = decryptKey, IV = decryptIV };
            decryptor = rijndael.CreateDecryptor(decryptKey, decryptIV);
        }


        public static string decrypt(byte[] data)
        {
            string password = null;
            using (MemoryStream ms = new MemoryStream(data))
                using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                    using (StreamReader sr = new StreamReader(cs))
                        password = sr.ReadToEnd();
            return password;
        }
    }

他们在服务器端选择了 32 个字节,但只用 11 个字符填充它们:dldhsvmflvm。这就是为什么我用 0 填充其他 21 个字节的原因。 32*8 = 256 位 = 密钥大小

当我使用 byte[32] 之类的 IV 并将其填充为 0 时出现错误。它说 smth 好像 IV 不适合块大小。这就是为什么它现在有 16 个字节并且填充为 0。这可能是问题所在吗?如果是,我该如何解决?

除此之外,我不知道可能出了什么问题。希望你能拯救我的一天,Stackoverflow。 :)

【问题讨论】:

  • 您能否验证IV和Key的值在C++和C#代码中是否确实相同?
  • CRijndael 的默认块大小是 128 位,所以是 16 字节,所以 IV 必须是 16 字节长。 (参见void MakeKey(char const* key, char const* chain, int keylength=DEFAULT_BLOCK_SIZE, int blockSize=DEFAULT_BLOCK_SIZE),其中enum { DEFAULT_BLOCK_SIZE=16 }MakeKeyCRijndael::CRijndael()MakeKey( szDefaultKey, CRijndael::sm_chain0 ); 调用,因此使用默认参数。)
  • 请注意,即使密钥长度也必须为 16。CRijndael 不使用 sizeof(char[32]) 或类似名称。它通过MakeKey的参数知道密钥长度,所以试试Enumerable.Repeat((byte)0, 5)
  • 请告诉我们密钥是如何在 C++ 中创建的。在这种情况下,我认为这将是 MakeKey 调用。

标签: c# c++ encryption cryptography rijndael


【解决方案1】:

正如 xanatos 所说,我添加了 5 个零而不是 21,因为它们的键应该只有 16 个字节而不是 32 个字节。 它现在工作没有问题。谢谢大家!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-20
    • 2012-11-27
    • 2013-04-19
    相关资源
    最近更新 更多