簡體   English   中英

使用C#加密和使用Crypto ++解密不起作用

[英]Encrypting in C# and Decrypting with Crypto++ does not work

加密方式:

    public static byte[] EncryptAES(Message msg)
    {

        byte[] encText; // This will keep the encrypted text
        byte[] encLength; // This will keep the length of the encrypted text
        byte[] finalEncText = null; // This keeps the encLength + encText (#####[encText] / [encLength][encText])

        // Building the plaintext message : 
        string plainText = msg.MessageCode.ToString();

        if (msg.Parameters != null)
            foreach (string parameter in msg.Parameters)
                plainText += parameter;

        // Encrypting the plaintext :
        encText = EncryptAES(plainText);

        string encLen = encText.Length.ToString();
        string fittedEncLen = MessageSender.FitStringIntoSize(encLen, Globals.MESSAGE_LENGTH_LEN); // Fit the length of the encrypted text into a certain size
        encLength = Encoding.ASCII.GetBytes(fittedEncLen); // convert the length into byte[]

        finalEncText = new byte[encLength.Length + encText.Length];
        System.Buffer.BlockCopy(encLength, 0, finalEncText, 0, encLength.Length);
        System.Buffer.BlockCopy(encText, 0, finalEncText, encLength.Length, encText.Length); // Copy the byte arrays into the new byte array


        return finalEncText;
    }

    private static byte[] EncryptAES(string text)
    {
        // This function encrypts a plaintext message using the aes key we have from the server

        if (AesKey == null || IV == null) // If we dont have an aes key / iv, dont encrypt
            return Encoding.ASCII.GetBytes(text);


        byte[] encryptedText;

        try
        {
            Aes aes = Aes.Create();
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.Zeros;
            aes.Key = Encoding.ASCII.GetBytes(AesKey);
            aes.IV = Encoding.ASCII.GetBytes(IV);

            ICryptoTransform cryptor = aes.CreateEncryptor(aes.Key, aes.IV);



            using (MemoryStream memStream = new MemoryStream())
            {
                using (CryptoStream crypotStream = new CryptoStream(memStream, cryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter writerStream = new StreamWriter(crypotStream))
                    {
                        writerStream.Write(text);
                    }
                    encryptedText = memStream.ToArray();
                }
            }

            aes.Dispose();
        }
        catch
        {
            // In case of an error while encrypting, dont encrypt
            encryptedText = Encoding.ASCII.GetBytes(text);
        }
        return encryptedText;
    }

[添加的fitEncLen基本上是固定長度的5個字符的前綴,它包含緊隨其后的加密消息的長度,然后在解密服務器讀取這5個字符之前,然后解密加密部分。

將消息發送到服務器[TCPClient] [C#]:

public int Send(Message message)
        {
            /*
             * Encrpyts the message and then sends it to the network stream.
             * 
             * Return code:
             *      0 on success.
             *      -1 on failure.
             */

            byte[] msg = Cryptography.EncryptAES(message); // Encrypt the message
            // Sending message

            try
            {
                this._networkStream.Write(msg, 0, msg.Length);
                this._networkStream.Flush();
            }
            catch
            {
                return -1;
            }
            return 0;
        }

接收[C ++]:

wstring Helper::getWideStringPartFromSocket(SOCKET sc, int bytesNum)
{
    // This function reads the message from the socket, using wide string
    std::wstringstream cls;
    cls << getPartFromSocket(sc, bytesNum, 0);
    return cls.str();
}

char* Helper::getPartFromSocket(SOCKET sc, int bytesNum, int flags)
{
    if (bytesNum == 0)
        return "";

    char* data = new char[bytesNum + 1];
    int res = recv(sc, data, bytesNum, flags);

    if (res == INVALID_SOCKET)
    {
        string s = "Error while recieving from socket: ";
        s += to_string(sc);
        throw exception(s.c_str());
    }

    data[bytesNum] = 0;

    return data;
}



BufferedString* Helper::makeBufferedString(SOCKET sc)
    {
        /*
            The socket contains <length of encrypted message (unencrypted)> <encrypted message>.

            This function will read the length of the unencrypted message, read 
            the encrypted message, decrypt it, store it in a BufferedString
            object and return the object.

            Length of length number: MESSAGE_LENGTH_LEN.
        */

        int sizeOfMessage = Helper::getIntPartFromSocket(sc, MESSAGE_LENGTH_LEN);
        if (sizeOfMessage == 0)
            return NULL;

        wstring wideString = getWideStringPartFromSocket(sc, sizeOfMessage);
        string decrypted = "";

        if (wideString.length() < sizeOfMessage)
        {
            std::wstringstream cls;
            cls << wideString;
            cls << getWideStringPartFromSocket(sc, sizeOfMessage - wideString.length());
            wideString = cls.str();
        }

        SocketEncryptionKeychain* keyChain = SocketEncryptionKeychain::getKeychain(sc);

        if (keyChain != nullptr) // If the socket has a keychain, decrypt the message
            decrypted = Cryptography::decryptAES(wideString, keyChain->getKey(), keyChain->getIV()); // Try to decrypt the message
        else // If the keychain is null, just convert the widestring to a string
            decrypted = wideStringToString(wideString);

        return new BufferedString(decrypted);
    }

SocketEncryptionKeychain基本上包含每個套接字的AES密鑰和IV BufferedString是一個包含字符串的類,您可以像從套接字中讀取一樣讀取它[它是一個緩沖區,一旦讀取它,就會刪除所讀取的內容] [基本上是一個字符串緩沖區,沒什么特別的]

解密[C ++]:

string Cryptography::decryptAES(wstring cipherText, byte aesKey[], byte iv[])
{
    if (aesKey == nullptr || iv == nullptr) // If the key or iv are null, dont decrypt
        return Helper::wideStringToString(cipherText);

    string plaintext;
    try
    {
        // Decrypt :
        byte* cipher = wideStringToByteArray(cipherText); // Convert the wide string to byte*

        CryptoPP::AES::Decryption aesDecryption(aesKey, 32);
        CryptoPP::CBC_Mode_ExternalCipher::Decryption ecbDecryption(aesDecryption, iv);


        CryptoPP::StreamTransformationFilter stfDecryptor(ecbDecryption, new CryptoPP::StringSink(plaintext), StreamTransformationFilter::ZEROS_PADDING);
        stfDecryptor.Put(cipher, cipherText.length());
        stfDecryptor.MessageEnd();

        Helper::safeDelete(cipher);
    }
    catch (CryptoPP::InvalidCiphertext& ex)
    {
        // In case of an error don't decrypt
        plaintext = Helper::wideStringToString(cipherText);
    }

    return plaintext;
}


byte* Cryptography::wideStringToByteArray(wstring text)
{
    // This function translates the wstring into a byte*
    byte* bytes = new byte[text.length()]; // Convert the wstring to byte*
    for (int i = 0; i < text.length(); i++)
    {
        bytes[i] = text[i];
    }
    return bytes;
}

[Helper :: safeDelete是一個僅刪除指針並將其設置為null的函數]

解密只會偶爾失敗一次

您可能還有其他問題,但這是一個:

using (CryptoStream crypotStream = new CryptoStream(memStream, cryptor, CryptoStreamMode.Write))
{
    using (StreamWriter writerStream = new StreamWriter(crypotStream))
    {
        writerStream.Write(text);
    }
    encryptedText = memStream.ToArray();
}

在告訴CryptoStream完成之前,您先耗盡了CryptoStream的輸出。 因此,您可能丟失了多達16個字節。

您需要:

  • crypotStream (sic)上調用FlushFinalBlock()。
  • 在退出對CryptoStream的使用之前,請勿調用memStream.ToArray()

因此,問題在於在函數中將char *解析為wstring時

這個函數的問題是我解析它的方式:

wstring Helper::getWideStringPartFromSocket(SOCKET sc, int bytesNum)
{
    // This function reads the message from the socket, using wide string
    std::wstringstream cls;
    cls << getPartFromSocket(sc, bytesNum, 0);
    return cls.str();
}

我使用了wstringstream,並且加密的文本有時可以包含以零結尾的字符。

因此,我沒有使用wstringstream,而是這樣:

wstring Helper::getWideStringPartFromSocket(SOCKET sc, int bytesNum)
{
    // This function reads the message from the socket, using wide string
    char* readBuffer = getPartFromSocket(sc, bytesNum, 0);

    return wstring(&readBuffer[0], &readBuffer[bytesNum]);
}

然后它不會在空字符處剪切消息

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM