2016-05-10 6 views
1

私は、各ユーザーごとにランダムなHMACキーを生成し、そのキーをデータベースに格納します。ユーザーはキーを要求する場合にのみキーを取得し、ほとんどの場合、BASE64でエンコードされた不透明キーとしてAPIトークン(SWT)を使用し、その完全性について心配する必要はありません。データベースストレージのHMAC鍵を暗号化/復号化できないのはなぜですか?

キーが侵害されないように、キーをSQL Serverデータベースに格納する前に、そのキーを暗号化します。暗号化されたキーはvarbinary(MAX)列に格納されます。すべてが暗号化なしで素晴らしい作品です。

暗号化された値の先頭にランダムに生成されたIVを使用した暗号化にAESを使用しています。

単純な文字列での私の単体テストでは、HMACキーですべてがうまくいきますが、復号化された値は元のものと決して一致しません。 HMACキーを生成し、暗号化してデータベースに格納します。私はそれを取得し、解読し、キーを使用してHMACハッシュを生成しますが、元のHMACハッシュ値と一致しません。

下記の暗号化/復号化方法を参照してください。

public static byte[] Encrypt(byte[] value) 
    { 
     using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider()) 
     { 
      Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(_password, Encoding.ASCII.GetBytes(_salt)); 

      aes.Key = key.GetBytes(aes.KeySize/8); 
      aes.GenerateIV(); 
      aes.Padding = PaddingMode.PKCS7; 
      aes.Mode = CipherMode.CBC; 

      using (var crypt = aes.CreateEncryptor(aes.Key, aes.IV)) 
      using (MemoryStream ms = new MemoryStream()) 
      { 
       using (CryptoStream cs = new CryptoStream(ms, crypt, CryptoStreamMode.Write)) 
       { 
        cs.Write(aes.IV, 0, aes.IV.Length); 

        using (BinaryWriter bw = new BinaryWriter(cs)) 
        {        
         bw.Write(value); 
         cs.FlushFinalBlock(); 
        } 

        return ms.ToArray(); 
       } 
      } 
     } 
    } 

public static byte[] Decrypt(byte[] value) 
    { 
     using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider()) 
     { 
      Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(_password, Encoding.ASCII.GetBytes(_salt)); 

      aes.Key = key.GetBytes(aes.KeySize/8); 
      aes.Padding = PaddingMode.PKCS7; 
      aes.Mode = CipherMode.CBC; 

      using (MemoryStream ms = new MemoryStream(value)) 
      { 
       byte[] iv = new byte[aes.IV.Length]; 

       ms.Read(iv, 0, aes.IV.Length); 
       aes.IV = iv; 

       using (var crypt = aes.CreateDecryptor(aes.Key, aes.IV)) 
       using (CryptoStream cs = new CryptoStream(ms, crypt, CryptoStreamMode.Read)) 
       { 
        using (StreamReader sr = new StreamReader(cs)) 
         return Encoding.ASCII.GetBytes(sr.ReadToEnd()); 
       } 
      } 
     } 
    } 

パスワードと塩は、コードにコンパイルされたconst文字列リテラルに格納されます。私はこれが理想的ではないことを認識していますが、それは今のためのものです。

+0

あなたはいくつかのコードを書いていますが、どのように動作しないのかはわかりません... –

+0

HMAC鍵を生成して暗号化してデータベースに格納します。私はそれを取得し、解読し、キーを使用してHMACハッシュを生成しますが、元のHMACハッシュ値と一致しません。 –

+0

問題を診断するために何をしましたか?すべての段階でバイトを記録しましたか? (暗号化の前、暗号化の後、データベースに保存する前、データベースから取り出した後、復号化前、復号化後...)基本的には、問題の原因となっているステージを正確に分離する必要があります。 –

答えて

0

私は問題が二重であったと信じています。最初はJon Skeetと議論されていたように、IVが暗号化されていたため、その値を復号化するためにIVが使用されていました。次のコードでCryptoStreamの代わりにMemoryStreamに直接書き込むことでこれを修正しました。

public static byte[] Encrypt(byte[] value) 
    { 
     using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider()) 
     { 
      Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(_password, Encoding.ASCII.GetBytes(_salt)); 

      aes.Key = key.GetBytes(aes.KeySize/8); 
      aes.GenerateIV(); 
      aes.Padding = PaddingMode.PKCS7; 
      aes.Mode = CipherMode.CBC; 

      using (var crypt = aes.CreateEncryptor(aes.Key, aes.IV)) 
      using (MemoryStream ms = new MemoryStream()) 
      using (CryptoStream cs = new CryptoStream(ms, crypt, CryptoStreamMode.Write)) 
      using (BinaryWriter bw = new BinaryWriter(cs)) 
      { 
       ms.Write(aes.IV, 0, aes.IV.Length); 
       bw.Write(value); 
       cs.FlushFinalBlock(); 

       return ms.ToArray(); 
      } 
     } 
    } 

次の部分私は約完全にわからないんだけど、私はジョンはまた、いくつかの問題が戻ってバイト配列に文字列に読み込むとしてそこにあることについて正しかったと思います。ストリームをバイト配列に直接読み込むには、jonskeet.uk/csharp/readbinary.htmlのようなコードを使用してこれを修正しました。 ReadStream()が私がJonに基づいて書いたメソッドである次のコードを見てください。

public static byte[] Decrypt(byte[] value) 
    { 
     using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider()) 
     { 
      Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(_password, Encoding.ASCII.GetBytes(_salt)); 

      aes.Key = key.GetBytes(aes.KeySize/8); 
      aes.Padding = PaddingMode.PKCS7; 
      aes.Mode = CipherMode.CBC; 

      using (MemoryStream ms = new MemoryStream(value)) 
      { 
       byte[] iv = new byte[aes.IV.Length]; 

       ms.Read(iv, 0, aes.IV.Length); 
       aes.IV = iv; 

       using (var crypt = aes.CreateDecryptor(aes.Key, aes.IV)) 
       using (CryptoStream cs = new CryptoStream(ms, crypt, CryptoStreamMode.Read)) 
        return ReadStream(cs, 0, ms.Length); 
      } 
     } 
    } 

Jonさん、ありがとうございます。私はあなたに感謝します。私が何かを学ぶつもりなら、私はそれのために働いても構いません。それは私が何をするために支払われるものです。

-1

シンプルでカスタムにはいかがですか?

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

namespace GrimoireTactics.Framework.Security 
{ 
    public enum ObfuscatorType 
    { 
     Encrypt, 
     Decrypt 
    } 
    public class Obfuscator 
    { 
     private string _seed; 
     private byte[] _hashedSeedBytes; 
     private readonly SHA256Managed _hashingAlgorithm; 
     public string Seed 
     { 
      get 
      { 
       return _seed; 
      } 
      set 
      { 
       this._seed = value; 
       SeedHash = GenerateHash(value); 
       this._hashedSeedBytes = GetBytes(SeedHash); 
      } 
     } 

     public byte[] SeedBytes 
     { 
      get 
      { 
       return _hashedSeedBytes; 
      } 
     } 

     public string SeedHash { get; private set; } 

     public Obfuscator(string seed) 
     { 
      this._hashingAlgorithm = new SHA256Managed(); 
      this.Seed = seed; 
     } 


     public byte[] Encrypt(byte[] data) 
     { 
      return Transform(data, ObfuscatorType.Encrypt); 
     } 

     public byte[] Encrypt(string data) 
     { 
      return Transform(GetBytes(data), ObfuscatorType.Encrypt); 
     } 

     public byte[] Decrypt(byte[] data) 
     { 
      return Transform(data, ObfuscatorType.Decrypt); 
     } 

     public byte[] Transform(byte[] bytes, ObfuscatorType type) 
     { 
      int passwordShiftIndex = 0; 
      byte[] data = bytes; 
      byte offset = 0; 
      switch (type) 
      { 
       case ObfuscatorType.Encrypt: 
        for (int i = 0; i < data.Length; i++) 
        { 
         byte currentByte = _hashedSeedBytes[passwordShiftIndex]; 
         offset += (byte)(1 + currentByte); // Incrementing Offset 
         data[i] = (byte)(data[i] + currentByte + offset); 
         passwordShiftIndex = (passwordShiftIndex + 1) % _hashedSeedBytes.Length; 
        } 
        break; 
       case ObfuscatorType.Decrypt: 
        for (int i = 0; i < data.Length; i++) 
        { 
         byte currentByte = _hashedSeedBytes[passwordShiftIndex]; 
         offset += (byte)(1 + currentByte); // Incrementing Offset 
         data[i] = (byte)(data[i] - currentByte - offset); 
         passwordShiftIndex = (passwordShiftIndex + 1) % _hashedSeedBytes.Length; 
        } 
        break; 
      } 
      return data; 
     } 

     public byte[] GetBytes(string data) 
     { 
      return Encoding.UTF8.GetBytes(data); 
     } 

     public byte[] GetBytes(string data, Encoding encoding) 
     { 
      return encoding.GetBytes(data); 
     } 

     public string GetString(byte[] data) 
     { 
      return Encoding.UTF8.GetString(data); 
     } 

     public string GetString(byte[] data, Encoding encoding) 
     { 
      return encoding.GetString(data); 
     } 

     public string GenerateHash(string text) 
     { 
      byte[] bytes = Encoding.UTF8.GetBytes(text); 
      byte[] hash = _hashingAlgorithm.ComputeHash(bytes); 
      string hashString = string.Empty; 
      for (int index = 0; index < hash.Length; index++) 
      { 
       byte x = hash[index]; 
       hashString += $"{x:x2}"; 
      } 
      return hashString; 
     } 
    } 
} 

使用例:

using System.Diagnostics; 
using System.IO; 
using System.Windows.Forms; 
using GrimoireDevelopmentKit.DevelopmentKit.UserInterface; 
using GrimoireTactics.Framework.OpenGL.Modeling; 
using GrimoireTactics.Framework.OpenGL.Texturing; 
using GrimoireTactics.Framework.Security; 

namespace GrimoireDevelopmentKit.DevelopmentKit 
{ 
    static class Program 
    { 
     /// <summary> 
     /// The main entry point for the application. 
     /// </summary> 
     [STAThread] 
     static void Main() 
     { 
      //Application.EnableVisualStyles(); 
      //Application.SetCompatibleTextRenderingDefault(false); 
      //Application.Run(new DevelopmentKitEditor()); 

      Obfuscator obs = new Obfuscator("My Arbitary Seed"); 
      byte[] obufsicatedData = obs.Encrypt("Some Top Secret Data"); 
      byte[] unobufsicatedData = obs.Decrypt(obufsicatedData); 
      Console.WriteLine(obs.GetString(unobufsicatedData)); 
      Console.Read(); 
     } 
    } 
} 

我々が行うすべては、カスタムアルゴリズムを使用してバイトを難読化です。コードは誰にでも自由に使用できます。私はそれをセキュリティ対策として追加しました。

+0

ありがとうございます。しかし、私はAESよりも弱いものを探しているわけではありません。私は今のところAESを設計していますが、とにかく感謝しています。 –

+0

@ EvilAugust "Secure"の対策はさまざまです。セキュリティキーを隠すことは不可能なので、AESは私のカスタムアルゴリズムと同じくらい安全です。結局のところ、obufsucationはすべて重要です。私のコードは速く暗号化と解読を行い、1:1のサイズ比を提供します。さらに、アルゴリズムの複雑さにより、時間がかかりすぎてクラックすることもありません。 – Krythic

関連する問題