public void ResolvePolicy_CngCbcEncryption_WithExplicitSettings()
        {
            IServiceCollection serviceCollection = new ServiceCollection();

            RunTestWithRegValues(serviceCollection, new Dictionary <string, object>()
            {
                ["EncryptionType"]              = "cng-cbc",
                ["EncryptionAlgorithm"]         = "enc-alg",
                ["EncryptionAlgorithmKeySize"]  = 2048,
                ["EncryptionAlgorithmProvider"] = "my-enc-alg-provider",
                ["HashAlgorithm"]         = "hash-alg",
                ["HashAlgorithmProvider"] = "my-hash-alg-provider"
            });

            var services = serviceCollection.BuildServiceProvider();
            var expectedConfiguration = new CngCbcAuthenticatedEncryptorConfiguration(new CngCbcAuthenticatedEncryptionOptions()
            {
                EncryptionAlgorithm         = "enc-alg",
                EncryptionAlgorithmKeySize  = 2048,
                EncryptionAlgorithmProvider = "my-enc-alg-provider",
                HashAlgorithm         = "hash-alg",
                HashAlgorithmProvider = "my-hash-alg-provider"
            });
            var actualConfiguration = (CngCbcAuthenticatedEncryptorConfiguration)services.GetService <IAuthenticatedEncryptorConfiguration>();

            Assert.Equal(expectedConfiguration.Options.EncryptionAlgorithm, actualConfiguration.Options.EncryptionAlgorithm);
            Assert.Equal(expectedConfiguration.Options.EncryptionAlgorithmKeySize, actualConfiguration.Options.EncryptionAlgorithmKeySize);
            Assert.Equal(expectedConfiguration.Options.EncryptionAlgorithmProvider, actualConfiguration.Options.EncryptionAlgorithmProvider);
            Assert.Equal(expectedConfiguration.Options.HashAlgorithm, actualConfiguration.Options.HashAlgorithm);
            Assert.Equal(expectedConfiguration.Options.HashAlgorithmProvider, actualConfiguration.Options.HashAlgorithmProvider);
        }
    internal IAuthenticatedEncryptor?CreateAuthenticatedEncryptorInstance(
        ISecret secret,
        AuthenticatedEncryptorConfiguration?authenticatedConfiguration)
    {
        if (authenticatedConfiguration == null)
        {
            return(null);
        }

        if (IsGcmAlgorithm(authenticatedConfiguration.EncryptionAlgorithm))
        {
#if NETCOREAPP
            return(new AesGcmAuthenticatedEncryptor(secret, GetAlgorithmKeySizeInBits(authenticatedConfiguration.EncryptionAlgorithm) / 8));
#else
            // GCM requires CNG, and CNG is only supported on Windows.
            if (!OSVersionUtil.IsWindows())
            {
                throw new PlatformNotSupportedException(Resources.Platform_WindowsRequiredForGcm);
            }

            Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));

            var configuration = new CngGcmAuthenticatedEncryptorConfiguration()
            {
                EncryptionAlgorithm        = GetBCryptAlgorithmNameFromEncryptionAlgorithm(authenticatedConfiguration.EncryptionAlgorithm),
                EncryptionAlgorithmKeySize = GetAlgorithmKeySizeInBits(authenticatedConfiguration.EncryptionAlgorithm)
            };

            return(new CngGcmAuthenticatedEncryptorFactory(_loggerFactory).CreateAuthenticatedEncryptorInstance(secret, configuration));
#endif
        }
        else
        {
            if (OSVersionUtil.IsWindows())
            {
                Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
                // CNG preferred over managed implementations if running on Windows
                var configuration = new CngCbcAuthenticatedEncryptorConfiguration()
                {
                    EncryptionAlgorithm        = GetBCryptAlgorithmNameFromEncryptionAlgorithm(authenticatedConfiguration.EncryptionAlgorithm),
                    EncryptionAlgorithmKeySize = GetAlgorithmKeySizeInBits(authenticatedConfiguration.EncryptionAlgorithm),
                    HashAlgorithm = GetBCryptAlgorithmNameFromValidationAlgorithm(authenticatedConfiguration.ValidationAlgorithm)
                };

                return(new CngCbcAuthenticatedEncryptorFactory(_loggerFactory).CreateAuthenticatedEncryptorInstance(secret, configuration));
            }
            else
            {
                // Use managed implementations as a fallback
                var configuration = new ManagedAuthenticatedEncryptorConfiguration()
                {
                    EncryptionAlgorithmType    = GetManagedTypeFromEncryptionAlgorithm(authenticatedConfiguration.EncryptionAlgorithm),
                    EncryptionAlgorithmKeySize = GetAlgorithmKeySizeInBits(authenticatedConfiguration.EncryptionAlgorithm),
                    ValidationAlgorithmType    = GetManagedTypeFromValidationAlgorithm(authenticatedConfiguration.ValidationAlgorithm)
                };

                return(new ManagedAuthenticatedEncryptorFactory(_loggerFactory).CreateAuthenticatedEncryptorInstance(secret, configuration));
            }
        }
    }
        public void ResolvePolicy_CngCbcEncryption_WithExplicitSettings()
        {
            // Arrange
            var registryEntries = new Dictionary <string, object>()
            {
                ["EncryptionType"]              = "cng-cbc",
                ["EncryptionAlgorithm"]         = "enc-alg",
                ["EncryptionAlgorithmKeySize"]  = 2048,
                ["EncryptionAlgorithmProvider"] = "my-enc-alg-provider",
                ["HashAlgorithm"]         = "hash-alg",
                ["HashAlgorithmProvider"] = "my-hash-alg-provider"
            };
            var expectedConfiguration = new CngCbcAuthenticatedEncryptorConfiguration()
            {
                EncryptionAlgorithm         = "enc-alg",
                EncryptionAlgorithmKeySize  = 2048,
                EncryptionAlgorithmProvider = "my-enc-alg-provider",
                HashAlgorithm         = "hash-alg",
                HashAlgorithmProvider = "my-hash-alg-provider"
            };

            // Act
            var context = RunTestWithRegValues(registryEntries);

            // Assert
            var actualConfiguration = (CngCbcAuthenticatedEncryptorConfiguration)context.EncryptorConfiguration;

            Assert.Equal(expectedConfiguration.EncryptionAlgorithm, actualConfiguration.EncryptionAlgorithm);
            Assert.Equal(expectedConfiguration.EncryptionAlgorithmKeySize, actualConfiguration.EncryptionAlgorithmKeySize);
            Assert.Equal(expectedConfiguration.EncryptionAlgorithmProvider, actualConfiguration.EncryptionAlgorithmProvider);
            Assert.Equal(expectedConfiguration.HashAlgorithm, actualConfiguration.HashAlgorithm);
            Assert.Equal(expectedConfiguration.HashAlgorithmProvider, actualConfiguration.HashAlgorithmProvider);
        }
예제 #4
0
    /// <summary>
    /// Imports the <see cref="CngCbcAuthenticatedEncryptorDescriptor"/> from serialized XML.
    /// </summary>
    public IAuthenticatedEncryptorDescriptor ImportFromXml(XElement element)
    {
        if (element == null)
        {
            throw new ArgumentNullException(nameof(element));
        }

        // <descriptor>
        //   <!-- Windows CNG-CBC -->
        //   <encryption algorithm="..." keyLength="..." [provider="..."] />
        //   <hash algorithm="..." [provider="..."] />
        //   <masterKey>...</masterKey>
        // </descriptor>

        var configuration = new CngCbcAuthenticatedEncryptorConfiguration();

        var encryptionElement = element.Element("encryption") !;

        configuration.EncryptionAlgorithm         = (string)encryptionElement.Attribute("algorithm") !;
        configuration.EncryptionAlgorithmKeySize  = (int)encryptionElement.Attribute("keyLength") !;
        configuration.EncryptionAlgorithmProvider = (string?)encryptionElement.Attribute("provider"); // could be null

        var hashElement = element.Element("hash") !;

        configuration.HashAlgorithm         = (string)hashElement.Attribute("algorithm") !;
        configuration.HashAlgorithmProvider = (string?)hashElement.Attribute("provider"); // could be null

        Secret masterKey = ((string)element.Element("masterKey")) !.ToSecret();

        return(new CngCbcAuthenticatedEncryptorDescriptor(configuration, masterKey));
    }
예제 #5
0
    public void CreateNewDescriptor_PropagatesOptions()
    {
        // Arrange
        var configuration = new CngCbcAuthenticatedEncryptorConfiguration();

        // Act
        var descriptor = (CngCbcAuthenticatedEncryptorDescriptor)configuration.CreateNewDescriptor();

        // Assert
        Assert.Equal(configuration, descriptor.Configuration);
    }
예제 #6
0
        internal IAuthenticatedEncryptor CreateAuthenticatedEncryptorInstance(
            ISecret secret,
            AuthenticatedEncryptorConfiguration authenticatedConfiguration)
        {
            if (authenticatedConfiguration == null)
            {
                return(null);
            }

            if (IsGcmAlgorithm(authenticatedConfiguration.EncryptionAlgorithm))
            {
                // GCM requires CNG, and CNG is only supported on Windows.
                if (!OSVersionUtil.IsWindows())
                {
                    throw new PlatformNotSupportedException("GCM algorithms require the Windows platform.");
                }

                var configuration = new CngGcmAuthenticatedEncryptorConfiguration()
                {
                    EncryptionAlgorithm        = GetBCryptAlgorithmNameFromEncryptionAlgorithm(authenticatedConfiguration.EncryptionAlgorithm),
                    EncryptionAlgorithmKeySize = GetAlgorithmKeySizeInBits(authenticatedConfiguration.EncryptionAlgorithm)
                };

                return(new CngGcmAuthenticatedEncryptorFactory(_loggerFactory).CreateAuthenticatedEncryptorInstance(secret, configuration));
            }
            else
            {
                if (OSVersionUtil.IsWindows())
                {
                    // CNG preferred over managed implementations if running on Windows
                    var configuration = new CngCbcAuthenticatedEncryptorConfiguration()
                    {
                        EncryptionAlgorithm        = GetBCryptAlgorithmNameFromEncryptionAlgorithm(authenticatedConfiguration.EncryptionAlgorithm),
                        EncryptionAlgorithmKeySize = GetAlgorithmKeySizeInBits(authenticatedConfiguration.EncryptionAlgorithm),
                        HashAlgorithm = GetBCryptAlgorithmNameFromValidationAlgorithm(authenticatedConfiguration.ValidationAlgorithm)
                    };

                    return(new CngCbcAuthenticatedEncryptorFactory(_loggerFactory).CreateAuthenticatedEncryptorInstance(secret, configuration));
                }
                else
                {
                    // Use managed implementations as a fallback
                    var configuration = new ManagedAuthenticatedEncryptorConfiguration()
                    {
                        EncryptionAlgorithmType    = GetManagedTypeFromEncryptionAlgorithm(authenticatedConfiguration.EncryptionAlgorithm),
                        EncryptionAlgorithmKeySize = GetAlgorithmKeySizeInBits(authenticatedConfiguration.EncryptionAlgorithm),
                        ValidationAlgorithmType    = GetManagedTypeFromValidationAlgorithm(authenticatedConfiguration.ValidationAlgorithm)
                    };

                    return(new ManagedAuthenticatedEncryptorFactory(_loggerFactory).CreateAuthenticatedEncryptorInstance(secret, configuration));
                }
            }
        }
예제 #7
0
    public void CreateNewDescriptor_CreatesUniqueCorrectlySizedMasterKey()
    {
        // Arrange
        var configuration = new CngCbcAuthenticatedEncryptorConfiguration();

        // Act
        var masterKey1 = ((CngCbcAuthenticatedEncryptorDescriptor)configuration.CreateNewDescriptor()).MasterKey;
        var masterKey2 = ((CngCbcAuthenticatedEncryptorDescriptor)configuration.CreateNewDescriptor()).MasterKey;

        // Assert
        SecretAssert.NotEqual(masterKey1, masterKey2);
        SecretAssert.LengthIs(512 /* bits */, masterKey1);
        SecretAssert.LengthIs(512 /* bits */, masterKey2);
    }
예제 #8
0
        internal CbcAuthenticatedEncryptor CreateAuthenticatedEncryptorInstance(
            ISecret secret,
            CngCbcAuthenticatedEncryptorConfiguration configuration)
        {
            if (configuration == null)
            {
                return(null);
            }

            return(new CbcAuthenticatedEncryptor(
                       keyDerivationKey: new Secret(secret),
                       symmetricAlgorithmHandle: GetSymmetricBlockCipherAlgorithmHandle(configuration),
                       symmetricAlgorithmKeySizeInBytes: (uint)(configuration.EncryptionAlgorithmKeySize / 8),
                       hmacAlgorithmHandle: GetHmacAlgorithmHandle(configuration)));
        }
    /// <summary>
    /// Initializes a new instance of <see cref="CngCbcAuthenticatedEncryptorDescriptor"/>.
    /// </summary>
    /// <param name="configuration">The <see cref="CngCbcAuthenticatedEncryptorConfiguration"/>.</param>
    /// <param name="masterKey">The master key.</param>
    public CngCbcAuthenticatedEncryptorDescriptor(CngCbcAuthenticatedEncryptorConfiguration configuration, ISecret masterKey)
    {
        if (configuration == null)
        {
            throw new ArgumentNullException(nameof(configuration));
        }

        if (masterKey == null)
        {
            throw new ArgumentNullException(nameof(masterKey));
        }

        Configuration = configuration;
        MasterKey     = masterKey;
    }
    public void CreateEncrptorInstance_ExpectedDescriptorType_ReturnsEncryptor()
    {
        // Arrange
        var descriptor = new CngCbcAuthenticatedEncryptorConfiguration().CreateNewDescriptor();
        var key        = new Mock <IKey>();

        key.Setup(k => k.Descriptor).Returns(descriptor);

        var factory = new CngCbcAuthenticatedEncryptorFactory(NullLoggerFactory.Instance);

        // Act
        var encryptor = factory.CreateEncryptorInstance(key.Object);

        // Assert
        Assert.NotNull(encryptor);
        Assert.IsType <CbcAuthenticatedEncryptor>(encryptor);
    }
예제 #11
0
        public void ResolvePolicy_CngCbcEncryption_WithoutExplicitSettings()
        {
            IServiceCollection serviceCollection = new ServiceCollection();

            RunTestWithRegValues(serviceCollection, new Dictionary <string, object>()
            {
                ["EncryptionType"] = "cng-cbc"
            });

            var services = serviceCollection.BuildServiceProvider();
            var expectedConfiguration = new CngCbcAuthenticatedEncryptorConfiguration(new CngCbcAuthenticatedEncryptionSettings());
            var actualConfiguration   = (CngCbcAuthenticatedEncryptorConfiguration)services.GetService <IAuthenticatedEncryptorConfiguration>();

            Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithm, actualConfiguration.Settings.EncryptionAlgorithm);
            Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmKeySize, actualConfiguration.Settings.EncryptionAlgorithmKeySize);
            Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmProvider, actualConfiguration.Settings.EncryptionAlgorithmProvider);
            Assert.Equal(expectedConfiguration.Settings.HashAlgorithm, actualConfiguration.Settings.HashAlgorithm);
            Assert.Equal(expectedConfiguration.Settings.HashAlgorithmProvider, actualConfiguration.Settings.HashAlgorithmProvider);
        }
        private BCryptAlgorithmHandle GetHmacAlgorithmHandle(CngCbcAuthenticatedEncryptorConfiguration configuration)
        {
            // basic argument checking
            if (String.IsNullOrEmpty(configuration.HashAlgorithm))
            {
                throw Error.Common_PropertyCannotBeNullOrEmpty(nameof(configuration.HashAlgorithm));
            }

            _logger.OpeningCNGAlgorithmFromProviderWithHMAC(configuration.HashAlgorithm, configuration.HashAlgorithmProvider);
            BCryptAlgorithmHandle?algorithmHandle = null;

            // Special-case cached providers
            if (configuration.HashAlgorithmProvider == null)
            {
                if (configuration.HashAlgorithm == Constants.BCRYPT_SHA1_ALGORITHM)
                {
                    algorithmHandle = CachedAlgorithmHandles.HMAC_SHA1;
                }
                else if (configuration.HashAlgorithm == Constants.BCRYPT_SHA256_ALGORITHM)
                {
                    algorithmHandle = CachedAlgorithmHandles.HMAC_SHA256;
                }
                else if (configuration.HashAlgorithm == Constants.BCRYPT_SHA512_ALGORITHM)
                {
                    algorithmHandle = CachedAlgorithmHandles.HMAC_SHA512;
                }
            }

            // Look up the provider dynamically if we couldn't fetch a cached instance
            if (algorithmHandle == null)
            {
                algorithmHandle = BCryptAlgorithmHandle.OpenAlgorithmHandle(configuration.HashAlgorithm, configuration.HashAlgorithmProvider, hmac: true);
            }

            // Make sure we're using a hash algorithm. We require a minimum 128-bit digest.
            uint digestSize = algorithmHandle.GetHashDigestLength();

            AlgorithmAssert.IsAllowableValidationAlgorithmDigestSize(checked (digestSize * 8));

            // all good!
            return(algorithmHandle);
        }
        private BCryptAlgorithmHandle GetSymmetricBlockCipherAlgorithmHandle(CngCbcAuthenticatedEncryptorConfiguration configuration)
        {
            // basic argument checking
            if (String.IsNullOrEmpty(configuration.EncryptionAlgorithm))
            {
                throw Error.Common_PropertyCannotBeNullOrEmpty(nameof(EncryptionAlgorithm));
            }
            if (configuration.EncryptionAlgorithmKeySize < 0)
            {
                throw Error.Common_PropertyMustBeNonNegative(nameof(configuration.EncryptionAlgorithmKeySize));
            }

            _logger.OpeningCNGAlgorithmFromProviderWithChainingModeCBC(configuration.EncryptionAlgorithm, configuration.EncryptionAlgorithmProvider);

            BCryptAlgorithmHandle?algorithmHandle = null;

            // Special-case cached providers
            if (configuration.EncryptionAlgorithmProvider == null)
            {
                if (configuration.EncryptionAlgorithm == Constants.BCRYPT_AES_ALGORITHM)
                {
                    algorithmHandle = CachedAlgorithmHandles.AES_CBC;
                }
            }

            // Look up the provider dynamically if we couldn't fetch a cached instance
            if (algorithmHandle == null)
            {
                algorithmHandle = BCryptAlgorithmHandle.OpenAlgorithmHandle(configuration.EncryptionAlgorithm, configuration.EncryptionAlgorithmProvider);
                algorithmHandle.SetChainingMode(Constants.BCRYPT_CHAIN_MODE_CBC);
            }

            // make sure we're using a block cipher with an appropriate key size & block size
            AlgorithmAssert.IsAllowableSymmetricAlgorithmBlockSize(checked (algorithmHandle.GetCipherBlockLength() * 8));
            AlgorithmAssert.IsAllowableSymmetricAlgorithmKeySize(checked ((uint)configuration.EncryptionAlgorithmKeySize));

            // make sure the provided key length is valid
            algorithmHandle.GetSupportedKeyLengths().EnsureValidKeyLength((uint)configuration.EncryptionAlgorithmKeySize);

            // all good!
            return(algorithmHandle);
        }
예제 #14
0
        private RegistryPolicy?ResolvePolicyCore(RegistryKey?policyRegKey)
        {
            if (policyRegKey == null)
            {
                return(null);
            }

            // Read the encryption options type: CNG-CBC, CNG-GCM, Managed
            AlgorithmConfiguration?configuration = null;

            var encryptionType = (string?)policyRegKey.GetValue("EncryptionType");

            if (String.Equals(encryptionType, "CNG-CBC", StringComparison.OrdinalIgnoreCase))
            {
                configuration = new CngCbcAuthenticatedEncryptorConfiguration();
            }
            else if (String.Equals(encryptionType, "CNG-GCM", StringComparison.OrdinalIgnoreCase))
            {
                configuration = new CngGcmAuthenticatedEncryptorConfiguration();
            }
            else if (String.Equals(encryptionType, "Managed", StringComparison.OrdinalIgnoreCase))
            {
                configuration = new ManagedAuthenticatedEncryptorConfiguration();
            }
            else if (!String.IsNullOrEmpty(encryptionType))
            {
                throw CryptoUtil.Fail("Unrecognized EncryptionType: " + encryptionType);
            }
            if (configuration != null)
            {
                PopulateOptions(configuration, policyRegKey);
            }

            // Read ancillary data

            var defaultKeyLifetime = (int?)policyRegKey.GetValue("DefaultKeyLifetime");

            var keyEscrowSinks = ReadKeyEscrowSinks(policyRegKey).Select(item => _activator.CreateInstance <IKeyEscrowSink>(item));

            return(new RegistryPolicy(configuration, keyEscrowSinks, defaultKeyLifetime));
        }
예제 #15
0
    private static CngCbcAuthenticatedEncryptorConfiguration GetCngCbcAuthenticatedEncryptorConfiguration(RegistryKey key)
    {
        var options           = new CngCbcAuthenticatedEncryptorConfiguration();
        var valueFromRegistry = key.GetValue(nameof(CngCbcAuthenticatedEncryptorConfiguration.EncryptionAlgorithm));

        if (valueFromRegistry != null)
        {
            options.EncryptionAlgorithm = Convert.ToString(valueFromRegistry, CultureInfo.InvariantCulture) !;
        }

        valueFromRegistry = key.GetValue(nameof(CngCbcAuthenticatedEncryptorConfiguration.EncryptionAlgorithmProvider));
        if (valueFromRegistry != null)
        {
            options.EncryptionAlgorithmProvider = Convert.ToString(valueFromRegistry, CultureInfo.InvariantCulture) !;
        }

        valueFromRegistry = key.GetValue(nameof(CngCbcAuthenticatedEncryptorConfiguration.EncryptionAlgorithmKeySize));
        if (valueFromRegistry != null)
        {
            options.EncryptionAlgorithmKeySize = Convert.ToInt32(valueFromRegistry, CultureInfo.InvariantCulture);
        }

        valueFromRegistry = key.GetValue(nameof(CngCbcAuthenticatedEncryptorConfiguration.HashAlgorithm));
        if (valueFromRegistry != null)
        {
            options.HashAlgorithm = Convert.ToString(valueFromRegistry, CultureInfo.InvariantCulture) !;
        }

        valueFromRegistry = key.GetValue(nameof(CngCbcAuthenticatedEncryptorConfiguration.HashAlgorithmProvider));
        if (valueFromRegistry != null)
        {
            options.HashAlgorithmProvider = Convert.ToString(valueFromRegistry, CultureInfo.InvariantCulture);
        }

        return(options);
    }
예제 #16
0
    public static IDataProtectionBuilder UseCustomCryptographicAlgorithms(this IDataProtectionBuilder builder, CngCbcAuthenticatedEncryptorConfiguration configuration)
    {
        if (builder == null)
        {
            throw new ArgumentNullException(nameof(builder));
        }

        if (configuration == null)
        {
            throw new ArgumentNullException(nameof(configuration));
        }

        return(UseCryptographicAlgorithmsCore(builder, configuration));
    }