2016-09-08 3 views
2

Я хочу зашифровать в C# и расшифровать в C++, но у меня есть некоторые Encoding проблемы:Шифрование в C# дешифрования AES CBC 256

пример переменных:

Ключ: г OtIPaL вер-vS5UAnJbPqsDZSf, yj1 IVString : г OtIPaL вер-VS5

мой C# код:

public static string EncryptString(string message, string KeyString, string IVString) 
    { 
     byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString.Substring(0,32)); 
     byte[] IV = UTF8Encoding.UTF8.GetBytes(IVString); 

     string encrypted = null; 
     RijndaelManaged rj = new RijndaelManaged(); 
     rj.Key = Key; 
     rj.IV = IV; 
     rj.Mode = CipherMode.CBC; 
     rj.Padding = PaddingMode.PKCS7; 
     try 
     { 
      MemoryStream ms = new MemoryStream(); 

      using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write)) 
      { 
       using (StreamWriter sw = new StreamWriter(cs)) 
       { 
        sw.Write(message); 
        sw.Close(); 
       } 
       cs.Close(); 
      } 
      byte[] encoded = ms.ToArray(); 
      encrypted = Convert.ToBase64String(encoded); 

      ms.Close(); 
     } 
     catch (CryptographicException e) 
     { 
      Console.WriteLine("A Cryptographic error occurred: {0}", e.Message); 
      return null; 
     } 
     catch (UnauthorizedAccessException e) 
     { 
      Console.WriteLine("A file error occurred: {0}", e.Message); 
      return null; 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("An error occurred: {0}", e.Message); 
     } 
     finally 
     { 
      rj.Clear(); 
     } 
     return encrypted; 
    } 

Когда я пытаюсь зашифровать, а у моего ключа есть некорректный символ ASCII, это больше, чем длина строки.

Как кодировать Я использую? В C++ я использую EVP (заполнение по умолчанию - PKCS7).

static string decryptEX(string KS, string ctext) 
{ 
EVP_CIPHER_CTX* ctx; 
ctx = EVP_CIPHER_CTX_new(); 
string IV = KS.substr(0, 16); 
int rc = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (byte*)&KS[0], (byte*)&IV[0]); 
std::string rtext; 
rtext.resize(ctext.size()); 

int out_len1 = (int)rtext.size(); 
rc = EVP_DecryptUpdate(ctx, (byte*)&rtext[0], &out_len1, (const byte*)&ctext[0], (int)ctext.size()); 


int out_len2 = (int)rtext.size() - out_len1; 
rc = EVP_DecryptFinal_ex(ctx, (byte*)&rtext[0] + out_len1, &out_len2); 
try 
{ 
    rtext.resize(out_len1 + out_len2); 
} 
catch (exception e) 
{ 

} 
return rtext; 

}

+1

Строки, как правило, не очень рад реализации внедренных нулевые значения, но 0x00 байт может отображаться как в ключах, так и в IV, поэтому, если вам нужно текстовое представление, вы обычно должны использовать Base64. У вас также не должно быть фиксированного IV для ключа, поскольку это заставляет одно и то же сообщение шифровать одинаково; и он действительно не должен делиться байтами (намеренно) с ключом, так как IV обычно передается с сообщением. – bartonjs

ответ

1

Ваш призыв к

byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString.Substring(0,32)); 

терпит неудачу, потому что нет 32 символов в этой строке. Да, будет 32 байта, если строка кодируется как UTF8. Но подстрока принимает количество символов.

Изменение этой строки в

byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString); 

дает длинный ключ 32 байт.

Поскольку вы не можете рассчитывать на получение правильного ввода для KeyString, вы можете подтвердить после этот момент, что длина ключа достаточно длинная.

byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString); 
if (Key.Length < 32) 
    throw new KeyLengthException("some useful info as to why this was thrown"); // or some other appropriate Exception type you create or resuse. 

Если я правильно предполагая, какой ключ, IV и размеры блоков вам требуется, это должно делать то, что вам нужно:

public static string EncryptString(string message, string KeyString, string IVString) 
    { 
     byte[] Key = UTF8Encoding.UTF8.GetBytes(KeyString).Take(32).ToArray(); 
     if (Key.Length < 32) 
      throw new Exception("KeyString not at least 32 bytes."); 
     byte[] IV = UTF8Encoding.UTF8.GetBytes(IVString).Take(16).ToArray(); 
     if (Key.Length < 32) 
      throw new Exception("IVString not at least 16 bytes."); 
     string encrypted = null; 
     RijndaelManaged rj = new RijndaelManaged(); 
     rj.KeySize = 128; 
     rj.BlockSize = 128; 
     rj.Key = Key; 
     rj.IV = IV; 
     rj.Mode = CipherMode.CBC; 
     rj.Padding = PaddingMode.PKCS7; 
     try 
     { 
      MemoryStream ms = new MemoryStream(); 

      using (CryptoStream cs = new CryptoStream(ms, rj.CreateEncryptor(Key, IV), CryptoStreamMode.Write)) 
      { 
       using (StreamWriter sw = new StreamWriter(cs)) 
       { 
        sw.Write(message); 
        sw.Close(); 
       } 
       cs.Close(); 
      } 
      byte[] encoded = ms.ToArray(); 
      encrypted = Convert.ToBase64String(encoded); 

      ms.Close(); 
     } 
     catch (CryptographicException e) 
     { 
      Console.WriteLine("A Cryptographic error occurred: {0}", e.Message); 
      return null; 
     } 
     catch (UnauthorizedAccessException e) 
     { 
      Console.WriteLine("A file error occurred: {0}", e.Message); 
      return null; 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("An error occurred: {0}", e.Message); 
     } 
     finally 
     { 
      rj.Clear(); 
     } 
     return encrypted; 
    } 
+0

За исключением a) Использовать Aes вместо Rijndael, b) Использовать Aes.Create() вместо того, чтобы выбирать вашу реализацию, c) избыточность установки KeySize и Key, d) после переключения на Aes 128 является единственным законным BlockSize, e) объект Aes (или Rijndael) является IDisposable, поэтому вместо try/finally {Clear()} он может просто быть в операторе using. – bartonjs

+0

@bartonjs: спасибо. все очень хорошие моменты. если бы не «как исправить эту ошибку», это было бы отличным кандидатом для codereview.stackexchange – hometoast

Смежные вопросы