【发布时间】: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 },MakeKey由CRijndael::CRijndael()和MakeKey( szDefaultKey, CRijndael::sm_chain0 );调用,因此使用默认参数。) -
请注意,即使密钥长度也必须为 16。
CRijndael不使用sizeof(char[32])或类似名称。它通过MakeKey的参数知道密钥长度,所以试试Enumerable.Repeat((byte)0, 5) -
请告诉我们密钥是如何在 C++ 中创建的。在这种情况下,我认为这将是
MakeKey调用。
标签: c# c++ encryption cryptography rijndael