2011-12-05 38 views
1

我試圖通過tcp連接從C#程序向C++程序發送加密字符串。當它試圖解密字符串時,C++程序在crypto ++中崩潰。我可以在調試器中看到該字符串大部分已解碼,但未正確終止。例如,如果我送的 「Hello world」,它就會被解密爲 「世界,你好%% @#$ @#」(末尾垃圾)將C#AES加密字符串發送到CyptoPP C++程序進行解密

下面是如何加密

  //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(); 
     } 

這裏是C++側解密與加密++

 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(); 

回答

1

您的問題是因爲1件事情,也許兩個。

  1. C#流寫入器不寫出空字節。當C++代碼讀入數據時,該字符串不是空終止的。我沒有測試過你提供的代碼,但這似乎是預期的行爲。

  2. 在C#實現和Crypto ++實現之間,假定的填充方法(或缺少方法)可能不同。 CBC模式下的AES只能加密或解密爲塊大小倍數的塊。在AES中,塊大小爲128位或16個字節。

維基百科對各種分組密碼模式here有很好的解釋。 CBC的典型填充是PKCS7,其描述爲here

我不知道任何一個實現的內部結構是否足以知道缺省的填充方法是什麼,或者如果它們留給用戶。

+0

RijndaelManaged的默認值是PaddingMode.PKCS7。 CryptoPP的默認值是DEFAULT_PADDING ...找不到更多。沿着這個答案的線,我會建議改變StreamTransformationFilter有可選的填充第三個參數,並把PKCS選項。 –

+0

「DEFAULT_PADDING表示如果c.MandatoryBlockSize()> 1 && c.MinLastBlockSize()== 0(例如ECB或CBC模式),否則NO_PADDING(OFB,CFB,CTR,CBC-CTS模式),則表示PKCS_PADDING。 [鏈接](http://www.cryptopp.com/docs/ref/class_stream_transformation_filter.html)所以它應該使用PKCS。我敢打賭,這是空終結者,我越想越想。 – Luke