2011-02-07 2 views
4

こんにちは私はRijaendal経由で文字列を暗号化/復号化しようとしています。 私は単純に解読が爆発する理由を理解できません。私はいつも間違ったパディングエラーで終わる。私を捨てることの1つは、私が16進数の配列として返す暗号化の結果です。長さは14バイトです。復号化機能では、同じバイト配列が16進数から16バイトに変換されてしまいます。Rijndaelパディングエラー

任意の助けいただければ幸いです。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace rjandal 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string DataForEncrypting = "this is a test"; 

      string key = string.Empty; 
      string iv = string.Empty; 

      using (System.Security.Cryptography.RijndaelManaged rmt = new System.Security.Cryptography.RijndaelManaged()) 
      { 
       rmt.KeySize = 256; 
       rmt.BlockSize = 128; 
       rmt.Mode = System.Security.Cryptography.CipherMode.CBC; 
       rmt.Padding = System.Security.Cryptography.PaddingMode.ISO10126; 
       rmt.GenerateKey(); 
       rmt.GenerateIV(); 
       key = Convert.ToBase64String(rmt.Key); 
       iv = Convert.ToBase64String(rmt.IV); 
      } 

      string encryptedData = _encrypt(DataForEncrypting, key, iv); 
      string unencryptedData = _decrypt(key, iv, HexString2Ascii(encryptedData)); 

      Console.WriteLine(unencryptedData); 
      Console.WriteLine(encryptedData); 
      Console.ReadKey(); 
     } 

     private static string _encrypt(string value, string key, string initVector) 
     { 
      byte[] buffer = ASCIIEncoding.ASCII.GetBytes(value); 
      byte[] encBuffer; 
      using (System.Security.Cryptography.RijndaelManaged rmt = new System.Security.Cryptography.RijndaelManaged()) 
      { 
       rmt.KeySize = 256; 
       rmt.BlockSize = 128; 
       rmt.Mode = System.Security.Cryptography.CipherMode.CBC; 
       rmt.Padding = System.Security.Cryptography.PaddingMode.ISO10126; 
       encBuffer = rmt.CreateEncryptor(Convert.FromBase64String(key), 
        Convert.FromBase64String(initVector)).TransformFinalBlock(buffer, 0, buffer.Length); 
      } 
      string encryptValue = ConvertToHex(ASCIIEncoding.ASCII.GetString(encBuffer)); 
      return encryptValue; 
     } 

     private static string _decrypt(string key, string initVector, string value) 
     { 
      byte[] hexBuffer = ASCIIEncoding.ASCII.GetBytes(value); 
      byte[] decBuffer; 
      using (System.Security.Cryptography.RijndaelManaged rmt = new System.Security.Cryptography.RijndaelManaged()) 
      { 
       rmt.KeySize = 256; 
       rmt.BlockSize = 128; 
       rmt.Mode = System.Security.Cryptography.CipherMode.CBC; 
       rmt.Padding = System.Security.Cryptography.PaddingMode.ISO10126; 
       decBuffer = rmt.CreateDecryptor(Convert.FromBase64String(key), 
        Convert.FromBase64String(initVector)).TransformFinalBlock(hexBuffer, 0, hexBuffer.Length); 
      } 

      return System.Text.ASCIIEncoding.ASCII.GetString(decBuffer); 
     } 

     private static string ConvertToHex(string asciiString) 
     { 
      string hex = ""; 
      foreach (char c in asciiString) 
      { 
       int tmp = c; 
       hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString())); 
      } 
      return hex; 
     } 

     private static string HexString2Ascii(string hexString) 
     { 
      StringBuilder sb = new StringBuilder(); 
      for (int i = 0; i <= hexString.Length - 2; i += 2) 
      { 
       sb.Append(Convert.ToString(Convert.ToChar(Int32.Parse(hexString.Substring(i, 2), System.Globalization.NumberStyles.HexNumber)))); 
      } 
      return sb.ToString(); 
     } 

    } 
} 

答えて

2

あなたは中間ステップとしてASCII文字エンコーディングを使用すべきではありません。代わりにbyte[]から16進数に戻って(そして元に戻って)16進数からASCIIに戻って関数を変更する必要があります。

private static string ConvertToHex(byte[] data) 
    { 
     string hex = ""; 
     foreach (byte b in data) 
     { 
      hex += b.ToString("X2"); 
     } 
     return hex; 
    } 

    private static byte[] HexString2ByteArray(string hexString) 
    { 
     byte[] output = new byte[hexString.Length/2]; 

     for (int i = 0; i <= hexString.Length - 2; i += 2) 
     { 
      output[i/2] = Convert.ToByte(hexString.Substring(i, 2), 16); 
     } 
     return output; 
    } 

さらに、Base64のようにコンパクトなものと比べて、配列の16進表現を探している理由はありますか?あなたの例ではBase64を使ってキーとIVを転送していますので、ここでは暗号化されたデータを16進数で返すことに興味があります。いずれの場合においても

は、ここにあなたのために働くべきものです:

private static string _encrypt(string value, string key, string initVector) 
    { 
     byte[] buffer = Encoding.Unicode.GetBytes(value); 
     byte[] encBuffer; 
     using (System.Security.Cryptography.RijndaelManaged rmt = new System.Security.Cryptography.RijndaelManaged()) 
     { 
      rmt.KeySize = 256; 
      rmt.BlockSize = 128; 
      rmt.Mode = System.Security.Cryptography.CipherMode.CBC; 
      rmt.Padding = System.Security.Cryptography.PaddingMode.ISO10126; 
      encBuffer = rmt.CreateEncryptor(Convert.FromBase64String(key), 
       Convert.FromBase64String(initVector)).TransformFinalBlock(buffer, 0, buffer.Length); 
     } 
     string encryptValue = ConvertToHex(encBuffer); 
     return encryptValue; 
    } 

    private static string _decrypt(string key, string initVector, string value) 
    { 
     byte[] hexBuffer = HexString2ByteArray(value); 
     byte[] decBuffer; 
     using (System.Security.Cryptography.RijndaelManaged rmt = new System.Security.Cryptography.RijndaelManaged()) 
     { 
      rmt.KeySize = 256; 
      rmt.BlockSize = 128; 
      rmt.Mode = System.Security.Cryptography.CipherMode.CBC; 
      rmt.Padding = System.Security.Cryptography.PaddingMode.ISO10126; 
      decBuffer = rmt.CreateDecryptor(Convert.FromBase64String(key), 
       Convert.FromBase64String(initVector)).TransformFinalBlock(hexBuffer, 0, hexBuffer.Length); 
     } 

     return Encoding.Unicode.GetString(decBuffer); 
    } 
+0

でどのように使用されるかその理由は、私はBASE64と六角で暗号化された結果にIVとキーを提供するように頼まれたということです。 – jcs

+0

@jcs:十分に公正です。これはあなたのためのトリックを行う必要があります。 Jonの答えは機能している間は、暗号化された値を16進ではなく、base64文字列として返します。 –

+0

お返事ありがとうございました。これは助けになりました。 – jcs

5

あなたは基本的には、テキストとデータの間にあまりにも多くの変換をやっています。例えば、これを見て:

string encryptValue = ConvertToHex(ASCIIEncoding.ASCII.GetString(encBuffer)); 

あなたがヘクスにことを変換する必要があるだろう、なぜASCII文字列を、持ってたら?すでにテキストです!しかしそれまでにはすでにデータを失ってしまいます。

string encryptValue = Convert.ToBase64String(encBuffer); 

利用Convert.FromBase64Stringで:あなたは本当にあなただけConvert.ToBase64Stringを使用する必要があります(アダムの提案に従い、バイト[]文字列の代わりを取るためにあなたのHexToAscii方法を変更された場合に)ヘクスそれを必要としない限り、解読するときもう一方の端。その後、16進法を完全に取り除くことができます。

ああ、一般的に私はで始まりません...私はほとんど常にEncoding.UTF8を使用します。現在、アクセントなどのASCII以外の文字を含む文字列を(正しく)暗号化できません。

ここには、テストプログラムの変更されたバージョンがありますが、いくつかの変更が加えられています。 「暗号テキスト」と「プレーンテキスト」という名前は暗号化の点であり、テキストではなくバイナリデータであることに注意してください。

using System; 
using System.Security.Cryptography; 
using System.Text; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     string DataForEncrypting = "this is a test"; 

     string key = string.Empty; 
     string iv = string.Empty; 

     using (RijndaelManaged rmt = new RijndaelManaged()) 
     { 
      rmt.KeySize = 256; 
      rmt.BlockSize = 128; 
      rmt.Mode = CipherMode.CBC; 
      rmt.Padding = PaddingMode.ISO10126; 
      rmt.GenerateKey(); 
      rmt.GenerateIV(); 
      key = Convert.ToBase64String(rmt.Key); 
      iv = Convert.ToBase64String(rmt.IV); 
     } 

     string encryptedData = _encrypt(DataForEncrypting, key, iv); 
     string unencryptedData = _decrypt(key, iv, encryptedData); 

     Console.WriteLine(unencryptedData); 
     Console.WriteLine(encryptedData); 
     Console.ReadKey(); 
    } 

    private static string _encrypt(string value, string key, string initVector) 
    { 
     using (RijndaelManaged rmt = new RijndaelManaged()) 
     { 
      rmt.KeySize = 256; 
      rmt.BlockSize = 128; 
      rmt.Mode = CipherMode.CBC; 
      rmt.Padding = PaddingMode.ISO10126; 
      byte[] plainText = Encoding.UTF8.GetBytes(value); 
      byte[] cipherText = rmt.CreateEncryptor(Convert.FromBase64String(key), 
                Convert.FromBase64String(initVector)) 
            .TransformFinalBlock(plainText, 0, plainText.Length); 
      return Convert.ToBase64String(cipherText); 
     } 
    } 

    private static string _decrypt(string key, string initVector, string value) 
    { 
     using (RijndaelManaged rmt = new RijndaelManaged()) 
     { 
      rmt.KeySize = 256; 
      rmt.BlockSize = 128; 
      rmt.Mode = CipherMode.CBC; 
      rmt.Padding = PaddingMode.ISO10126; 
      byte[] cipherText = Convert.FromBase64String(value); 
      byte[] plainText = rmt.CreateDecryptor(Convert.FromBase64String(key), 
                Convert.FromBase64String(initVector)) 
            .TransformFinalBlock(cipherText, 0, cipherText.Length); 
      return Encoding.UTF8.GetString(plainText); 
     } 
    } 
} 
+0

これは私が16進数の値を必要としなかった場合に使用するソリューションですが、OPは16進数の値を必要としていますが、これはbase64で返します。 –

+0

@アダム:私は今まであなたの答えに彼のコメントを読んでいなかった...(これは問題ではない) –

2

あなたはDecypting /暗号化とusign System.Text.Encodingの問題を回避し、完全にSystem.Text.EncodingにMicrosoftの不一致の変換を回避いくつかのメソッドを追加することで、周りの仕事をBase64エンコードを使用して回避することができます、あなたは翻訳せずにメモリ内の実バイトを暗号化することができます。

これらを使用しているので、System.Text.Encodingメソッドによって発生したパディングエラーを回避しているため、Base64変換も使用しません。

private static Byte[] GetBytes(String SomeString) 
    { 
     Char[] SomeChars = SomeString.ToCharArray(); 
     Int32 Size = SomeChars.Length * 2; 
     List<Byte> TempList = new List<Byte>(Size); 
     foreach (Char Character in SomeChars) 
     { 
      TempList.AddRange(BitConverter.GetBytes(Character)); 
     } 
     return TempList.ToArray(); 
    } 
    private static String GetString(Byte[] ByteArray) 
    { 
     Int32 Size = ByteArray.Length/2; 
     List<Char> TempList = new List<Char>(Size); 
     for (Int32 i = 0; i < ByteArray.Length; i += 2) 
     { 
      TempList.Add(BitConverter.ToChar(ByteArray, i)); 
     } 
     return new String(TempList.ToArray()); 
    } 

そして、彼らは暗号化

private static String Encrypt(String Test1, Byte[] Key, Byte[] IV) 
    { 
     Byte[] Encrypted; 
     using (AesCryptoServiceProvider AesMan = new AesCryptoServiceProvider()) 
     { 
      AesMan.Mode    = CipherMode.CBC; 
      AesMan.Padding   = PaddingMode.ISO10126; 
      ICryptoTransform EncThis = AesMan.CreateEncryptor(Key, IV); 

      using (MemoryStream msEncrypt = new MemoryStream()) 
      { 
       using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, EncThis, CryptoStreamMode.Write)) 
       { 

        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) 
        { 
         //Write all data to the stream. 
         swEncrypt.Write(Test1); 
        } 
        Encrypted = msEncrypt.ToArray(); 
       } 
      } 
     }; 
     return GetString(Encrypted); 
    } 

    private static String Decrypt(String Data, Byte[] Key, Byte[] IV) 
    { 
     String Decrypted; 
     using (AesCryptoServiceProvider AesMan = new AesCryptoServiceProvider()) 
     { 
      AesMan.Mode    = CipherMode.CBC; 
      AesMan.Padding   = PaddingMode.ISO10126; 
      ICryptoTransform EncThis = AesMan.CreateDecryptor(Key, IV); 

      using (MemoryStream msDecrypt = new MemoryStream(GetBytes(Data))) 
      { 
       using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, EncThis, CryptoStreamMode.Read)) 
       { 
        using (StreamReader srDecrypt = new StreamReader(csDecrypt)) 
        { 

         // Read the decrypted bytes from the decrypting stream 
         // and place them in a string. 
         Decrypted = srDecrypt.ReadToEnd(); 
        } 
       } 
      } 
     } 
     return Decrypted; 
    } 
関連する問題