2016-09-08 34 views
2

私はC#で暗号化し、C++で復号化したいが、私はいくつかのエンコーディングの問題があります。暗号化C#復号化AES CBC 256

例変数:

キー:G 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です)。その文字列で32 文字がないため

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

文字列が埋め込まれたNULL値を運ぶ非常に満足していない傾向があり、 0x00バイトはキーとIVの両方に表示されることがあります。したがって、テキスト表現が必要な場合は、一般的にBase64を使用する必要があります。また、同じメッセージが同じ方法で暗号化されるため、キーの固定IVを持つべきではありません。 IVは通常メッセージとともに送信されるので、キーと意図的にバイトを共有すべきではありません。 – bartonjs

答えて

1

あなたのコール

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

には失敗します。はい、文字列がUTF8としてエンコードされている場合、32バイトになります。しかし、サブストリングは文字の数を取る。

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)Rijndaelの代わりにAesを使う、b)実装を選ぶのではなくAes.Create()を使う、c)KeySizeとKeyの両方を設定する、d)Aes 128に切り替えた後は、 Aes(またはRijndael)オブジェクトはIDisposableなので、try/finally {Clear()}の代わりにusingステートメントの中に入れることができます。 – bartonjs

+0

@bartonjs:ありがとう。すべての非常に良い点。 「このエラーをどう解決すればよいか」ではない場合、これはcodereview.stackexchangeの優れた候補になります – hometoast

関連する問題