Unity C#で Rfc2898 / PBKDF2 ＋ SHA256 による暗号化 


■詳しい仕組みについては下記サイト
　https://www.sophos.com/ja-jp/press-office/press-releases/2013/11/ns-serious-security-how-to-store-your-users-passwords-safely.aspx

■参考サイト（めっちゃ助かった）
　https://gist.github.com/peteroupc/6986999#file-pbkdf2-cs



dklenは戻した後のバイト数っぽい
自分のプロジェクトは暗号化後のbyte配列の長さが２５６ビット（３２バイト）なので３２

自分のプロジェクトは暗号化後のbyte配列を文字列に変換する時に
base64する必要があるので入力側で**Convert.ToBase64String**する。

自分のプロジェクトはストレッチ回数が1000なのでiterationCountの引数は1000

■呼び出し元ソース

```
using System;

public void OnClickTest()
{
    System.DateTime times = System.DateTime.Now;

    string salt = "1234567890";
    string pwd = "testtesttest";

    byte[] returnvalue = PBKDF2Sha256GetBytes
        (
            System.Text.Encoding.UTF8.GetBytes(pwd + salt),
            System.Text.Encoding.UTF8.GetBytes(salt),
            1000
        );

    string result = Convert.ToBase64String(returnvalue);
    Debug.Log("result = " + result);
}

```

■ちょっと元ソース改造


```
// .NET: PBKDF2-SHA256
// http://upokecenter.dreamhosters.com/articles/2012/02/net-pbkdf2-sha256/
//As a followup to the Secure Password Storage article, 
// here is a .NET implementation of PBKDF2 using SHA256 
//(Rfc2898DerivedBytes uses PBKDF2-SHA1, where the 
// underlying hash algorithm unfortunately is not configurable. 
// It’s in the public domain under CC0 
// http://creativecommons.org/publicdomain/zero/1.0/.

    // NOTE: The iteration count should
    // be as high as possible without causing
    // unreasonable delay.  Note also that the password
    // and salt are byte arrays, not strings.  After use,
    // the password and salt should be cleared (with Array.Clear)
        public static byte[] PBKDF2Sha256GetBytes(byte[] password, byte[] salt, int iterationCount)
        {
            int dklen = 32; 
            using (var hmac = new System.Security.Cryptography.HMACSHA256(password))
            {
                int hashLength = hmac.HashSize / 8;
                if ((hmac.HashSize & 7) != 0)
                    hashLength++;
                int keyLength = dklen / hashLength;
                if ((long)dklen > (0xFFFFFFFFL * hashLength) || dklen < 0)
                    throw new ArgumentOutOfRangeException("dklen");
                if (dklen % hashLength != 0)
                    keyLength++;
                byte[] extendedkey = new byte[salt.Length + 4];
                Buffer.BlockCopy(salt, 0, extendedkey, 0, salt.Length);
                using (var ms = new System.IO.MemoryStream())
                {
                    for (int i = 0; i < keyLength; i++)
                    {
                        extendedkey[salt.Length] = (byte)(((i + 1) >> 24) & 0xFF);
                        extendedkey[salt.Length + 1] = (byte)(((i + 1) >> 16) & 0xFF);
                        extendedkey[salt.Length + 2] = (byte)(((i + 1) >> 8) & 0xFF);
                        extendedkey[salt.Length + 3] = (byte)(((i + 1)) & 0xFF);
                        byte[] u = hmac.ComputeHash(extendedkey);
                        Array.Clear(extendedkey, salt.Length, 4);
                        byte[] f = u;
                        for (int j = 1; j < iterationCount; j++)
                        {
                            u = hmac.ComputeHash(u);
                            for (int k = 0; k < f.Length; k++)
                            {
                                f[k] ^= u[k];
                            }
                        }
                        ms.Write(f, 0, f.Length);
                        Array.Clear(u, 0, u.Length);
                        Array.Clear(f, 0, f.Length);
                    }
                    byte[] dk = new byte[dklen];
                    ms.Position = 0;
                    ms.Read(dk, 0, dklen);
                    ms.Position = 0;
                    for (long i = 0; i < ms.Length; i++)
                    {
                        ms.WriteByte(0);
                    }
                    Array.Clear(extendedkey, 0, extendedkey.Length);
                    return dk;
                }
            }
        }
```