Leveraging ASP.NET machineKey For Encrypting My Own Data

前端 未结 5 1750
天命终不由人
天命终不由人 2021-01-30 02:00

I have some data I want to encrypt in an ASP.NET MVC application to prevent users from tampering with it. I can use the Cryptography classes to do the actual encryption/decrypt

相关标签:
5条回答
  • 2021-01-30 02:02

    You might be able to reuse the MembershipProvider.EncryptPassword method, which in turn uses some (unfortunately internal) encryption methods of the MachineKeySection class.

    0 讨论(0)
  • 2021-01-30 02:06

    The new MachineKey class in ASP.NET 4.0 does exactly what you want.

    For example:

    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;
            }
        }
    }
    

    UPDATE: As mentioned here, be careful how you use this or you could allow someone to forge a forms authentication token.

    0 讨论(0)
  • 2021-01-30 02:14

    I guess not directly. I can't remember where I got this from, probably a combination of Reflector and some blogs.

    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;
        }
    }
    

    Caveat emptor!

    0 讨论(0)
  • 2021-01-30 02:22

    With .NET Framwork 4.5 you should use the new 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;
        }
    
    }
    

    Ideally the "Purpose" should be a known one time valid value to prevent forging.

    0 讨论(0)
  • 2021-01-30 02:22

    If you're working with 3.5 or earlier you can avoid a lot of code and just do this:

    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;
    }
    

    One of my colleagues talked me into it and I think it's fairly reasonable to do this for custom cookies, if not for general encryption needs.

    0 讨论(0)
提交回复
热议问题