NOVINKA! E-learningové kurzy umělé inteligence. Nyní AI za nejlepší ceny. Zjisti více:
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!
Avatar
Petr Čech
Tvůrce
Avatar
Petr Čech:12.12.2015 17:35

Čau, udělal jsem si třídu, která šifruje a dešifruje stringy. Funguje to dobře, ale nejsem si jistý, jestli je to bezpečné, tak se chci zeptat tady. Nebudu chodit okolo horké kaše, tady je kód:

/// <summary>
/// Class used to encrypt/decrypt strings using password and salt
/// </summary>
class AesEncrypt : IDisposable
{
    /// <summary>
    /// Lenght of <see cref="RijndaelManaged.IV"/>. Bytes of this lenght are
    /// prepended to every encryped string and contain IV itself
    /// </summary>
    private int IVSize => _rijndael.BlockSize / 8;

    /// <summary>
    /// Instantialzes new <see cref="AesEncrypt"/> class
    /// </summary>
    /// <param name="key">password protecting the string</param>
    /// <param name="salt">salt which is used to hash password</param>
    public AesEncrypt(string key, byte[] salt)
    {
        if (key == null) throw new ArgumentNullException(nameof(key));
        if (salt == null) throw new ArgumentNullException(nameof(salt));
        if (salt.Length == 0) throw new ArgumentException("Argument is empty collection", nameof(salt));

        Salt = salt;
        _rijndael = new RijndaelManaged { Key = GetKey(key) };
    }

    /// <summary>
    /// Salt used to hash password to generate <see cref="RijndaelManaged.Key"/> to be used
    /// </summary>
    public byte[] Salt { get; }

    private readonly RijndaelManaged _rijndael;

    /// <summary>
    /// Generates key from password of any lenght and hash. Key is 256bit long.
    /// </summary>
    /// <param name="password">Any password</param>
    /// <returns>Key of fixed size 256bit</returns>
    protected byte[] GetKey(string password)
    {
        int keyLength = 32;//

        using (var pbkdf = new Rfc2898DeriveBytes(password, Salt))
        {
            return pbkdf.GetBytes(keyLength);
        }
    }
    protected ICryptoTransform GetEncryptor()
    {
        return _rijndael.CreateEncryptor();
    }
    protected ICryptoTransform GetDecryptor()
    {
        return _rijndael.CreateDecryptor(_rijndael.Key, _rijndael.IV);
    }

    /// <summary>
    /// Encrypts string to bytes using 256bit Rijndael. IV of size <see cref="IVSize"/> occupies first bytes.
    /// </summary>
    /// <param name="plainText">Text to be encoded</param>
    /// <returns>Cipher in bytes</returns>
    public byte[] Encrypt(string plainText)
    {
        if (plainText == null) throw new ArgumentNullException(nameof(plainText));

        _rijndael.GenerateIV();
        var encryptor = GetEncryptor();

        // Create the streams used for encryption.
        using (MemoryStream msEncrypt = new MemoryStream())
        {
            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                {
                    //Write all data to the stream.
                    swEncrypt.Write(plainText);
                }
                //result without prepended IV
                byte[] encBytes = msEncrypt.ToArray();

                #region prepend IV to the beginning of bytes
                byte[] result = new byte[encBytes.Length + IVSize];
                for (int i = 0; i < IVSize; i++)
                {
                    //write IV to the beginning
                    result[i] = _rijndael.IV[i];
                }
                #endregion

                for (int i = 0; i < encBytes.Length; i++)
                {
                    //index to be written to
                    int index = i + IVSize;
                    result[index] = encBytes[i];
                }

                return result;
            }
        }
    }
    /// <summary>
    /// Decrypt a cipher made by <see cref="Encrypt"/> with known <see cref="Salt"/> and password.
    /// </summary>
    /// <param name="cipher">Cipher to be decrypted.</param>
    /// <returns>Decrypted string</returns>
    public string Decrypt(byte[] cipher)
    {
        if (cipher == null) throw new ArgumentNullException(nameof(cipher));
        if (cipher.Length < IVSize + 1) throw new ArgumentException($"Argument must be {IVSize + 1} bytes long at least!", nameof(cipher));

        #region read first IVSize bytes which are IV
        byte[] IV = new byte[IVSize];
        for (int i = 0; i < IVSize; i++)
        {
            IV[i] = cipher[i];
        }
        _rijndael.IV = IV;
        #endregion

        //actual bytes to be decrypted
        byte[] encBytes = new byte[cipher.Length - IVSize];
        for (int i = 0; i < encBytes.Length; i++)
        {
            //index to be read from
            int index = i + IVSize;
            encBytes[i] = cipher[index];
        }

        // Create a decrytor to perform the stream transform.
        var decryptor = GetDecryptor();

        // Create the streams used for decryption.
        using (MemoryStream msDecrypt = new MemoryStream(encBytes))
        {
            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
                using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                {
                    // Read the decrypted bytes from the decrypting stream
                    // and place them in a string.
                    return srDecrypt.ReadToEnd();
                }
            }
        }
    }

    public void Dispose()
    {
        _rijndael?.Dispose();
    }
}

PS: nemám žádný specifický důvod dělat cokoliv jakkoliv, plánuji to používat na šifrování JSONu.

Odpovědět
12.12.2015 17:35
the cake is a lie
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 1 zpráv z 1.