Подтвердить что ты не робот

Использование машинного ключа ASP.NET для шифрования моих собственных данных

У меня есть некоторые данные, которые я хочу зашифровать в приложении ASP.NET MVC, чтобы помешать им подделывать его. Я могу использовать классы криптографии для фактического шифрования/дешифрования, без проблем. Основная проблема заключается в том, чтобы выяснить, где хранить ключ шифрования и управлять его изменениями.

Так как ASP.NET уже поддерживает machineKey для разных вещей (шифрование ViewData и т.д.), мне было интересно, есть ли какие-либо функции ASP.NET, которые позволяют мне шифровать/расшифровывать мои собственные данные с помощью machineKey? Таким образом, мне не пришлось бы разрабатывать собственную систему управления ключами.

4b9b3361

Ответ 1

С .NET Frameworkwork 4.5 вы должны использовать новый API:

public class StringProtector
{

    private const string Purpose = "Authentication Token";

    public string Protect(string unprotectedText)
    {
        var unprotectedBytes = Encoding.UTF8.GetBytes(unprotectedText);
        var protectedBytes = MachineKey.Protect(unprotectedBytes, Purpose);
        var protectedText = Convert.ToBase64String(protectedBytes);
        return protectedText;
    }

    public string Unprotect(string protectedText)
    {
        var protectedBytes = Convert.FromBase64String(protectedText);
        var unprotectedBytes = MachineKey.Unprotect(protectedBytes, Purpose);
        var unprotectedText = Encoding.UTF8.GetString(unprotectedBytes);
        return unprotectedText;
    }

}

В идеале "Цель" должна быть известным одноразовым действительным значением для предотвращения подделки.

Ответ 2

Новый класс MachineKey в ASP.NET 4.0 делает именно то, что вы хотите.

Например:

public static class StringEncryptor {
    public static string Encrypt(string plaintextValue) {
        var plaintextBytes = Encoding.UTF8.GetBytes(plaintextValue);
        return MachineKey.Encode(plaintextBytes, MachineKeyProtection.All);
    }

    public static string Decrypt(string encryptedValue) {
        try {
            var decryptedBytes = MachineKey.Decode(encryptedValue, MachineKeyProtection.All);
            return Encoding.UTF8.GetString(decryptedBytes);
        }
        catch {
            return null;
        }
    }
}

ОБНОВЛЕНИЕ. Как упоминалось здесь, будьте осторожны, как вы это используете, или вы можете позволить кому-то подделать токен аутентификации форм.

Ответ 3

Я думаю, не напрямую. Я не могу вспомнить, откуда я это получил, возможно, сочетание Reflector и некоторых блогов.

public abstract class MyAwesomeClass
{
    private static byte[] cryptKey;

    private static MachineKeySection machineKeyConfig =
        (MachineKeySection)ConfigurationManager
            .GetSection("system.web/machineKey");

    // ... snip ...

    static MyAwesomeClass()
    {
        string configKey;
        byte[] key;

        configKey = machineKeyConfig.DecryptionKey;
        if (configKey.Contains("AutoGenerate"))
        {
            throw new ConfigurationErrorsException(
                Resources.MyAwesomeClass_ExplicitAlgorithmRequired);
        }

        key = HexStringToByteArray(configKey);

        cryptKey = key;
    }

    // ... snip ...

    protected static byte[] Encrypt(byte[] inputBuffer)
    {
        SymmetricAlgorithm algorithm;
        byte[] outputBuffer;

        if (inputBuffer == null)
        {
            throw new ArgumentNullException("inputBuffer");
        }

        algorithm = GetCryptAlgorithm();

        using (var ms = new MemoryStream())
        {
            algorithm.GenerateIV();
            ms.Write(algorithm.IV, 0, algorithm.IV.Length);

            using (var cs = new CryptoStream(
                 ms, 
                 algorithm.CreateEncryptor(), 
                 CryptoStreamMode.Write))
            {
                cs.Write(inputBuffer, 0, inputBuffer.Length);
                cs.FlushFinalBlock();
            }

            outputBuffer = ms.ToArray();
        }

        return outputBuffer;
    }

    protected static byte[] Decrypt(string input)
    {
        SymmetricAlgorithm algorithm;
        byte[] inputBuffer, inputVectorBuffer, outputBuffer;

        if (input == null)
        {
            throw new ArgumentNullException("input");
        }

        algorithm = GetCryptAlgorithm();
        outputBuffer = null;

        try
        {
            inputBuffer = Convert.FromBase64String(input);

            inputVectorBuffer = new byte[algorithm.IV.Length];
            Array.Copy(
                 inputBuffer, 
                 inputVectorBuffer,
                 inputVectorBuffer.Length);
            algorithm.IV = inputVectorBuffer;

            using (var ms = new MemoryStream())
            {
                using (var cs = new CryptoStream(
                    ms, 
                    algorithm.CreateDecryptor(), 
                    CryptoStreamMode.Write))
                {
                    cs.Write(
                        inputBuffer,
                        inputVectorBuffer.Length, 
                        inputBuffer.Length - inputVectorBuffer.Length);
                    cs.FlushFinalBlock();
                }

                outputBuffer = ms.ToArray();
            }
        }
        catch (FormatException e)
        {
            throw new CryptographicException(
                "The string could not be decoded.", e);
        }

        return outputBuffer;
    }

    // ... snip ...

    private static SymmetricAlgorithm GetCryptAlgorithm()
    {
        SymmetricAlgorithm algorithm;
        string algorithmName;

        algorithmName = machineKeyConfig.Decryption;
        if (algorithmName == "Auto")
        {
            throw new ConfigurationErrorsException(
                Resources.MyAwesomeClass_ExplicitAlgorithmRequired);
        }

        switch (algorithmName)
        {
            case "AES":
                algorithm = new RijndaelManaged();
                break;
            case "3DES":
                algorithm = new TripleDESCryptoServiceProvider();
                break;
            case "DES":
                algorithm = new DESCryptoServiceProvider();
                break;
            default:
                throw new ConfigurationErrorsException(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        Resources.MyAwesomeClass_UnrecognizedAlgorithmName,
                        algorithmName));
        }

        algorithm.Key = cryptKey;

        return algorithm;
    }

    private static byte[] HexStringToByteArray(string str)
    {
        byte[] buffer;

        if (str == null)
        {
            throw new ArgumentNullException("str");
        }

        if (str.Length % 2 == 1)
        {
            str = '0' + str;
        }

        buffer = new byte[str.Length / 2];

        for (int i = 0; i < buffer.Length; ++i)
        {
            buffer[i] = byte.Parse(
                str.Substring(i * 2, 2),
                NumberStyles.HexNumber,
                CultureInfo.InvariantCulture);
        }

        return buffer;
    }
}

Предостережение emptor!

Ответ 4

Если вы работаете с 3.5 или более ранними версиями, вы можете избежать большого количества кода и просто сделать это:

public static string Encrypt(string cookieValue)
{
    return FormsAuthentication.Encrypt(new FormsAuthenticationTicket(1,
                                                                     string.Empty,
                                                                     DateTime.Now,
                                                                     DateTime.Now.AddMinutes(20160),
                                                                     true,
                                                                     cookieValue));
}

public static string Decrypt(string encryptedTicket)
{
    return FormsAuthentication.Decrypt(encryptedTicket).UserData;
}

Один из моих коллег рассказал мне об этом, и я думаю, что это разумно сделать это для пользовательских файлов cookie, если не для общего шифрования.

Ответ 5

Возможно, вы сможете повторно использовать метод MemberhipProvider.EncryptPassword, который, в свою очередь, использует некоторые (к сожалению, внутренние) методы шифрования MachineKeySection.