Beispiel #1
0
        private void AddNoise(ElementNode node, PerturbSetting perturbSetting)
        {
            if (s_integerValueTypeNames.Contains(node.InstanceType, StringComparer.InvariantCultureIgnoreCase))
            {
                perturbSetting.RoundTo = 0;
            }

            var originValue = decimal.Parse(node.Value.ToString());
            var span        = perturbSetting.Span;

            if (perturbSetting.RangeType == PerturbRangeType.Proportional)
            {
                span = (double)originValue * perturbSetting.Span;
            }

            var noise          = (decimal)ContinuousUniform.Sample(-1 * span / 2, span / 2);
            var perturbedValue = decimal.Round(originValue + noise, perturbSetting.RoundTo);

            if (perturbedValue <= 0 && string.Equals(FHIRAllTypes.PositiveInt.ToString(), node.InstanceType, StringComparison.InvariantCultureIgnoreCase))
            {
                perturbedValue = 1;
            }
            if (perturbedValue < 0 && string.Equals(FHIRAllTypes.UnsignedInt.ToString(), node.InstanceType, StringComparison.InvariantCultureIgnoreCase))
            {
                perturbedValue = 0;
            }
            node.Value = perturbedValue;
            return;
        }
        public PerturbFunction(PerturbSetting perturbSetting)
        {
            EnsureArg.IsNotNull(perturbSetting, nameof(perturbSetting));

            _perturbSetting = perturbSetting ?? new PerturbSetting();
            _perturbSetting.Validate();
        }
Beispiel #3
0
        public ProcessResult Process(ElementNode node, ProcessContext context = null, Dictionary <string, object> settings = null)
        {
            EnsureArg.IsNotNull(node);
            EnsureArg.IsNotNull(context?.VisitedNodes);
            EnsureArg.IsNotNull(settings);

            var result = new ProcessResult();

            ElementNode valueNode = null;

            if (s_primitiveValueTypeNames.Contains(node.InstanceType, StringComparer.InvariantCultureIgnoreCase))
            {
                valueNode = node;
            }
            else if (s_quantityTypeNames.Contains(node.InstanceType, StringComparer.InvariantCultureIgnoreCase))
            {
                valueNode = node.Children(Constants.ValueNodeName).Cast <ElementNode>().FirstOrDefault();
            }

            // Perturb will not happen if value node is empty or visited.
            if (valueNode?.Value == null || context.VisitedNodes.Contains(valueNode))
            {
                return(result);
            }

            var perturbSetting = PerturbSetting.CreateFromRuleSettings(settings);

            AddNoise(valueNode, perturbSetting);
            context.VisitedNodes.UnionWith(node.Descendants().Cast <ElementNode>());
            result.AddProcessRecord(AnonymizationOperations.Perturb, node);
            return(result);
        }
Beispiel #4
0
        public void GivenAPerturbSetting_WhenCreate_SettingPropertiesShouldBeParsedCorrectly(Dictionary <string, object> config, double expectedSpan, double expectedRoundTo, PerturbRangeType expectedRangeType)
        {
            var perturbSetting = PerturbSetting.CreateFromRuleSettings(config);

            Assert.Equal(expectedSpan, perturbSetting.Span);
            Assert.Equal(expectedRoundTo, perturbSetting.RoundTo);
            Assert.Equal(expectedRangeType, perturbSetting.RangeType);
        }
        public void Validate(AnonymizerConfiguration config)
        {
            if (string.IsNullOrEmpty(config.FhirVersion))
            {
                _logger.LogWarning($"Version is not specified in configuration file.");
            }
            else if (!string.Equals(Constants.SupportedVersion, config.FhirVersion, StringComparison.InvariantCultureIgnoreCase))
            {
                throw new AnonymizerConfigurationErrorsException($"Configuration of fhirVersion {config.FhirVersion} is not supported. Expected fhirVersion: {Constants.SupportedVersion}");
            }

            if (config.FhirPathRules == null)
            {
                throw new AnonymizerConfigurationErrorsException("The configuration is invalid, please specify any fhirPathRules");
            }

            FhirPathCompiler compiler = new FhirPathCompiler();
            var supportedMethods      = Enum.GetNames(typeof(AnonymizerMethod)).ToHashSet(StringComparer.InvariantCultureIgnoreCase);

            foreach (var rule in config.FhirPathRules)
            {
                if (!rule.ContainsKey(Constants.PathKey) || !rule.ContainsKey(Constants.MethodKey))
                {
                    throw new AnonymizerConfigurationErrorsException("Missing path or method in Fhir path rule config.");
                }

                // Grammar check on FHIR path
                try
                {
                    compiler.Compile(rule[Constants.PathKey].ToString());
                }
                catch (Exception ex)
                {
                    throw new AnonymizerConfigurationErrorsException($"Invalid FHIR path {rule[Constants.PathKey]}", ex);
                }

                // Method validate
                string method = rule[Constants.MethodKey].ToString();
                if (!supportedMethods.Contains(method))
                {
                    throw new AnonymizerConfigurationErrorsException($"Anonymization method {method} not supported.");
                }

                // Should provide replacement value for substitute rule
                if (string.Equals(method, AnonymizerMethod.Substitute.ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    SubstituteSetting.ValidateRuleSettings(rule);
                }

                if (string.Equals(method, AnonymizerMethod.Perturb.ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    PerturbSetting.ValidateRuleSettings(rule);
                }
                if (string.Equals(method, AnonymizerMethod.Generalize.ToString(), StringComparison.InvariantCultureIgnoreCase))
                {
                    GeneralizeSetting.ValidateRuleSettings(rule);
                }
            }

            // Check AES key size is valid (16, 24 or 32 bytes).
            if (!string.IsNullOrEmpty(config.ParameterConfiguration?.EncryptKey))
            {
                using Aes aes = Aes.Create();
                var encryptKeySize = Encoding.UTF8.GetByteCount(config.ParameterConfiguration.EncryptKey) * 8;
                if (!IsValidKeySize(encryptKeySize, aes.LegalKeySizes))
                {
                    throw new AnonymizerConfigurationErrorsException($"Invalid encrypt key size : {encryptKeySize} bits! Please provide key sizes of 128, 192 or 256 bits.");
                }
            }
        }
Beispiel #6
0
 public void GivenAInvalidPerturbSetting_WhenValidate_ExceptionShouldBeThrown(Dictionary <string, object> config)
 {
     Assert.Throws <AnonymizerConfigurationException>(() => PerturbSetting.ValidateRuleSettings(config));
 }
        public void GivenAnUnsignedLongInteger_WhenPerturb_PerturbedValueShouldBeReturned(ulong value, PerturbSetting perturbSetting, ulong lowerBound, ulong upperBound)
        {
            var function = new PerturbFunction(perturbSetting);
            var result   = function.Perturb(value);

            Assert.InRange(result, lowerBound, upperBound);
            Assert.IsType <ulong>(result);
        }
        public void GivenALongInteger_WhenPerturb_PerturbedValueShouldBeReturned(long value, PerturbSetting perturbSetting, long lowerBound, long upperBound)
        {
            var function = new PerturbFunction(perturbSetting);
            var result   = function.Perturb(value);

            Assert.InRange(result, lowerBound, upperBound);
            Assert.True(GetDecimalPlaces(result) <= perturbSetting.RoundTo);
            Assert.IsType <long>(result);
        }
        public void GivenAnUnsignedShortInteger_WhenPerturb_PerturbedValueShouldBeReturned(ushort value, PerturbSetting perturbSetting, ushort lowerBound, ushort upperBound)
        {
            var function = new PerturbFunction(perturbSetting);
            var result   = function.Perturb(value);

            Assert.InRange(result, lowerBound, upperBound);
            Assert.True(GetDecimalPlaces(result) <= perturbSetting.RoundTo);
            Assert.IsType <ushort>(result);
        }
        public void GivenAFloat_WhenPerturb_PerturbedValueShouldBeReturned(float value, PerturbSetting perturbSetting, float lowerBound, float upperBound)
        {
            var function = new PerturbFunction(perturbSetting);
            var result   = function.Perturb(value);

            Assert.InRange(result, lowerBound, upperBound);
            Assert.True(GetDecimalPlaces((decimal)result) <= perturbSetting.RoundTo);
            Assert.IsType <float>(result);
        }
        public void GivenAgeValue_WhenPerturb_PerturbedValueShouldBeReturned(AgeObject value, PerturbSetting perturbSetting, uint lowerBound, uint upperBound)
        {
            var function = new PerturbFunction(perturbSetting);
            var result   = function.Perturb(value);

            Assert.InRange(result.Value, lowerBound, upperBound);
            Assert.Equal(value.AgeType, value.AgeType);
        }
        public void GivenAValueString_WhenPerturb_PerturbedValueShouldBeReturned(string value, PerturbSetting perturbSetting, decimal lowerBound, decimal upperBound)
        {
            var function = new PerturbFunction(perturbSetting);
            var result   = function.Perturb(value);

            Assert.IsType <string>(result);
            Assert.InRange(decimal.Parse(result), lowerBound, upperBound);
            Assert.True(GetDecimalPlaces(decimal.Parse(result)) <= perturbSetting.RoundTo);
        }