File: MachineKeyCryptoAlgorithmFactory.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (135 lines) | stat: -rw-r--r-- 6,204 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//------------------------------------------------------------------------------
// <copyright file="MachineKeyCryptoAlgorithmFactory.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------

namespace System.Web.Security.Cryptography {
    using System;
    using System.Security.Cryptography;
    using System.Web.Configuration;

    // Can create cryptographic algorithms from a given <machineKey> element

    internal sealed class MachineKeyCryptoAlgorithmFactory : ICryptoAlgorithmFactory {

        private Func<SymmetricAlgorithm> _encryptionAlgorithmFactory;
        private readonly MachineKeySection _machineKeySection;
        private Func<KeyedHashAlgorithm> _validationAlgorithmFactory;

        public MachineKeyCryptoAlgorithmFactory(MachineKeySection machineKeySection) {
            _machineKeySection = machineKeySection;
        }

        public SymmetricAlgorithm GetEncryptionAlgorithm() {
            if (_encryptionAlgorithmFactory == null) {
                _encryptionAlgorithmFactory = GetEncryptionAlgorithmFactory();
            }
            return _encryptionAlgorithmFactory();
        }

        private Func<SymmetricAlgorithm> GetEncryptionAlgorithmFactory() {
            return GetGenericAlgorithmFactory<SymmetricAlgorithm>(
                configAttributeName: "decryption",
                configAttributeValue: _machineKeySection.GetDecryptionAttributeSkipValidation(),
                switchStatement: algorithmName => {
                    // We suppress CS0618 since some of the algorithms we support are marked with [Obsolete].
                    // These deprecated algorithms are *not* enabled by default. Developers must opt-in to
                    // them, so we're secure by default.
#pragma warning disable 618
                    switch (algorithmName) {
                        case "AES":
                        case "Auto": // currently "Auto" defaults to AES
                            return CryptoAlgorithms.CreateAes;

                        case "DES":
                            return CryptoAlgorithms.CreateDES;

                        case "3DES":
                            return CryptoAlgorithms.CreateTripleDES;

                        default:
                            return null; // unknown
#pragma warning restore 618
                    }
                },
                errorResourceString: SR.Wrong_decryption_enum);
        }

        public KeyedHashAlgorithm GetValidationAlgorithm() {
            if (_validationAlgorithmFactory == null) {
                _validationAlgorithmFactory = GetValidationAlgorithmFactory();
            }
            return _validationAlgorithmFactory();
        }

        private Func<KeyedHashAlgorithm> GetValidationAlgorithmFactory() {
            return GetGenericAlgorithmFactory<KeyedHashAlgorithm>(
                configAttributeName: "validation",
                configAttributeValue: _machineKeySection.GetValidationAttributeSkipValidation(),
                switchStatement: algorithmName => {
                    switch (algorithmName) {
                        case "SHA1":
                            return CryptoAlgorithms.CreateHMACSHA1;

                        case "HMACSHA256":
                            return CryptoAlgorithms.CreateHMACSHA256;

                        case "HMACSHA384":
                            return CryptoAlgorithms.CreateHMACSHA384;

                        case "HMACSHA512":
                            return CryptoAlgorithms.CreateHMACSHA512;

                        default:
                            return null; // unknown
                    }
                },
                errorResourceString: SR.Wrong_validation_enum_FX45);
        }

        // Contains common logic for creating encryption / validation factories, including
        // custom algorithm lookup and exception handling.
        private Func<TResult> GetGenericAlgorithmFactory<TResult>(string configAttributeName, string configAttributeValue, Func<string, Func<TResult>> switchStatement, string errorResourceString) where TResult : class, IDisposable {
            Func<TResult> factory;

            if (configAttributeValue != null && configAttributeValue.StartsWith("alg:", StringComparison.Ordinal)) {
                string algorithmName = configAttributeValue.Substring("alg:".Length);
                factory = () => {
                    // Since the custom algorithm might depend on the impersonated
                    // identity, we must instantiate it under app-level impersonation.
                    using (new ApplicationImpersonationContext()) {
                        return (TResult)CryptoConfig.CreateFromName(algorithmName);
                    }
                };
            }
            else {
                // If using a built-in algorithm, consult the switch statement to get the factory.
                factory = switchStatement(configAttributeValue);
            }

            // Invoke the factory once to make sure there aren't any configuration errors.
            Exception factoryCreationException = null;
            try {
                if (factory != null) {
                    TResult algorithm = factory();
                    if (algorithm != null) {
                        algorithm.Dispose();
                        return factory; // we know at this point the factory is good
                    }
                }
            }
            catch (Exception ex) {
                factoryCreationException = ex;
            }

            // If we reached this point, there was a failure:
            // the factory returned null, threw, or did something else unexpected.
            throw ConfigUtil.MakeConfigurationErrorsException(
                message: SR.GetString(errorResourceString),
                innerException: factoryCreationException, // can be null
                configProperty: _machineKeySection.ElementInformation.Properties[configAttributeName]);
        }

    }
}