Question

I'm trying to send an encrypted string via a tcp connection from a C# program to a C++ program. The c++ program crashes in crypto++ when it tries to decrypt the string. I can see in the debugger the string is mostly decoded but does not terminate properly. For example if I send "Hello world" it gets decrypted as "Hello world%%@#$@#" (garbage at the end)

Here's how I encrypt

           //Create byte arrays to hold original, encrypted, and decrypted data.
                byte[] dataToEncrypt = ByteConverter.GetBytes(data);

                byte[] key = new byte[16];
                for (int i = 0; i < 16; ++i)
                {
                    key[i] = 1;
                }

                byte[] iv = new byte[16];
                for (int i = 0; i < 16; ++i)
                {
                    iv[i] = 1;
                }


                RijndaelManaged myRijndael = new RijndaelManaged();

                myRijndael.Key = key;
                myRijndael.IV = iv;
                byte[] encrypted = encryptStringToBytes_AES(data, myRijndael.Key, myRijndael.IV);

         // sends the byte array via active tcp connection
        _transport.SendEncryptedData(encrypted);


 static byte[] encryptStringToBytes_AES(string plainText, byte[] Key, byte[] IV)
 {
   // Check arguments.
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");

            // Declare the stream used to encrypt to an in memory
            // array of bytes.
            MemoryStream msEncrypt = null;

            // Declare the RijndaelManaged object
            // used to encrypt the data.
            RijndaelManaged aesAlg = null;

            try
            {
                // Create a RijndaelManaged object
                // with the specified key and IV.
                aesAlg = new RijndaelManaged();
                aesAlg.Key = Key;
                aesAlg.IV = IV;

                // Create an encrypto to perform the stream transform.
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                // Create the streams used for encryption.
                msEncrypt = new MemoryStream();
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                }
            }
            finally
            {
                // Clear the RijndaelManaged object.
                if (aesAlg != null)
                    aesAlg.Clear();
            }

            // Return the encrypted bytes from the memory stream.
            return msEncrypt.ToArray();
        }

Here's the C++ side decrypting with Crypto++

     byte key[ CryptoPP::AES::DEFAULT_KEYLENGTH ];
        byte iv[ CryptoPP::AES::BLOCKSIZE ];
        ::memset( key, 0x01, CryptoPP::AES::DEFAULT_KEYLENGTH );
        ::memset( iv, 0x01, CryptoPP::AES::BLOCKSIZE );

        std::string decryptedtext;


        CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
        CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );


        CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedtext ) );

            // CRASHES IN .PUT(...)
        stfDecryptor.Put( reinterpret_cast<const unsigned char*>(data ), len + 1);
        stfDecryptor.MessageEnd();
Was it helpful?

Solution

Your problem is because of 1 of 2 things, perhaps both.

  1. The C# stream writer isn't writing out a null byte. When the C++ code reads in the data, the string is not null terminated. I haven't tested out the code you've given, but this would seem to be expected behavior.

  2. The assumed methods of padding (or lack thereof) may be different between the C# implementation and the Crypto++ implementation. AES in CBC mode can only encrypt or decrypt blocks that are multiples of the block size. In AES, the block size is 128-bits or 16 bytes.

Wikipedia has a great explanation of the various block cipher modes here. The typical padding for CBC is PKCS7, which is described here.

I don't know the internals of either implementation well enough to know what the default methods of padding are, or if they leave that up to the user.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top