public void ShouldReturnResultFromKeyManagementServiceOnGenerateDataKey()
        {
            var keyId = Guid.NewGuid().ToString();

            var expected = new GenerateDataKeyResult()
            {
                KeyCiphertext = new byte[] { 1, 2, 3 },
                KeyPlaintext  = new byte[] { 4, 5, 6 }
            };

            _dataKeyCache.Setup(x => x.Get(It.Is <DataKeyIdentifier>(identifier =>
                                                                     identifier.KeyId == keyId && identifier.EncryptionContext == _encryptionContext)))
            .Returns <GenerateDataKeyResult>(null);

            var keySpec = Guid.NewGuid().ToString();

            _keyManagementService.Setup(x => x.GenerateDataKey(keyId, _encryptionContext, keySpec))
            .Returns(expected);

            var result = _keyManagementServiceCache.GenerateDataKey(keyId, _encryptionContext, keySpec);

            _dataKeyCache.Verify(x => x.Set(It.Is <DataKeyIdentifier>(identifier =>
                                                                      identifier.KeyId == keyId && identifier.EncryptionContext == _encryptionContext), expected), Times.Once);

            result.KeyPlaintext.ShouldBe(expected.KeyPlaintext);
            result.KeyCiphertext.ShouldBe(expected.KeyCiphertext);
        }
        /// <summary>
        /// Attempt to generate a KMS datakey using the first successful response using a sorted dictionary of available KMS clients.
        /// </summary>
        /// <param name="sortedRegionToArnAndClientDictionary"> A sorted dictionary mapping regions and their arns and kms clients</param>
        /// <param name="dateKeyKeyId">The KMS arn used to generate the data key</param>
        /// <returns>A GenerateDataKeyResult object that contains the plain text key and the ciphertext for that key</returns>
        /// <exception cref="KeyManagementException">Throw an exception if we're unable to generate a datakey in any AWS region</exception>
        internal virtual GenerateDataKeyResult GenerateDataKey(OrderedDictionary sortedRegionToArnAndClientDictionary, out string dateKeyKeyId)
        {
            foreach (DictionaryEntry regionToArnAndClient in sortedRegionToArnAndClientDictionary)
            {
                try
                {
                    TimerOptions generateDataKeyTimerOptions = new TimerOptions
                    {
                        Name = MetricsUtil.AelMetricsPrefix + ".kms.aws.generatedatakey." + regionToArnAndClient.Key
                    };
                    using (MetricsUtil.MetricsInstance.Measure.Timer.Time(generateDataKeyTimerOptions))
                    {
                        IAmazonKeyManagementService client          = ((AwsKmsArnClient)regionToArnAndClient.Value).AwsKmsClient;
                        string keyIdForDataKeyGeneration            = ((AwsKmsArnClient)regionToArnAndClient.Value).Arn;
                        GenerateDataKeyResult generateDataKeyResult = client.GenerateDataKey(
                            keyIdForDataKeyGeneration,
                            null,
                            DataKeySpec.AES_256);
                        dateKeyKeyId = keyIdForDataKeyGeneration;
                        return(generateDataKeyResult);
                    }
                }
                catch (AmazonServiceException e)
                {
                    Logger.LogWarning(e, "Failed to generate data key via region {region}, trying next region", regionToArnAndClient.Key);

                    // TODO Consider adding notification/CW alert
                }
            }

            throw new KeyManagementException("could not successfully generate data key using any regions");
        }
        public void ShouldReturnResultFromCacheOnGenerateDataKey()
        {
            var keyId    = Guid.NewGuid().ToString();
            var cacheKey = Guid.NewGuid().ToString();

            _cacheKeyGenerator.Setup(x =>
                                     x.Generate(keyId, _encryptionContext))
            .Returns(cacheKey);

            var cacheValue = new byte[] { 10, 11, 12 };

            _cache.Setup(x => x.Get(cacheKey))
            .Returns(cacheValue);
            var dataKeyResult = new GenerateDataKeyResult()
            {
                KeyCiphertext = new byte[] { 1, 2, 3 },
                KeyPlaintext  = new byte[] { 4, 5, 6 }
            };

            _cacheValueConverter.Setup(x => x.Convert(cacheValue))
            .Returns(dataKeyResult);

            var result =
                _keyManagementServiceCache.GenerateDataKey(keyId, _encryptionContext, Guid.NewGuid().ToString());

            _keyManagementService.Verify(
                x => x.GenerateDataKey(
                    It.IsAny <string>(),
                    It.IsAny <Dictionary <string, string> >(),
                    It.IsAny <string>()), Times.Never);

            result.KeyPlaintext.ShouldBe(dataKeyResult.KeyPlaintext);
            result.KeyCiphertext.ShouldBe(dataKeyResult.KeyCiphertext);
        }
        public void ShouldReturnResultFromKeyManagementServiceOnGenerateDataKey()
        {
            var keyId    = Guid.NewGuid().ToString();
            var cacheKey = Guid.NewGuid().ToString();

            _cacheKeyGenerator.Setup(x =>
                                     x.Generate(keyId, _encryptionContext))
            .Returns(cacheKey);

            var cacheValue = new byte[] { 1, 2, 3 };

            var expected = new GenerateDataKeyResult()
            {
                KeyCiphertext = new byte[] { 1, 2, 3 },
                KeyPlaintext  = new byte[] { 4, 5, 6 }
            };

            _cacheValueConverter.Setup(x => x.Convert(expected))
            .Returns(cacheValue);

            _cache.Setup(x => x.Get(cacheKey))
            .Returns <byte[]>(null);

            var keySpec = Guid.NewGuid().ToString();

            _keyManagementService.Setup(x => x.GenerateDataKey(keyId, _encryptionContext, keySpec))
            .Returns(expected);

            var result = _keyManagementServiceCache.GenerateDataKey(keyId, _encryptionContext, keySpec);

            _cache.Verify(x => x.Set(cacheKey, cacheValue, It.IsAny <DistributedCacheEntryOptions>()), Times.Once);

            result.KeyPlaintext.ShouldBe(expected.KeyPlaintext);
            result.KeyCiphertext.ShouldBe(expected.KeyCiphertext);
        }
Ejemplo n.º 5
0
        private void TestEncryptKeyShouldThrowExceptionAndWipeBytes()
        {
            byte[] dataKeyPlainText = { 1, 2 };
            byte[] encryptedKey     = { 3, 4 };

            GenerateDataKeyResult generateDataKeyResult = new GenerateDataKeyResult
            {
                KeyPlaintext = dataKeyPlainText,
            };
            Mock <CryptoKey> generatedDataKeyCryptoKey = new Mock <CryptoKey>();
            string           someKey = "some_key";

            awsKeyManagementServiceImplSpy
            .Setup(x =>
                   x.GenerateDataKey(
                       awsKeyManagementServiceImplSpy.Object.RegionToArnAndClientDictionary, out someKey))
            .Returns(generateDataKeyResult);
            cryptoMock.Setup(x => x.GenerateKeyFromBytes(generateDataKeyResult.KeyPlaintext))
            .Returns(generatedDataKeyCryptoKey.Object);

            // Inject unexpected exception so the Task.WaitAll throws an  exception
            awsKeyManagementServiceImplSpy
            .Setup(x => x.EncryptKeyAndBuildResult(
                       It.IsAny <IAmazonKeyManagementService>(),
                       It.IsAny <string>(),
                       It.IsAny <string>(),
                       It.IsAny <byte[]>()))
            .Throws <SystemException>();
            cryptoMock.Setup(x => x.EncryptKey(cryptoKeyMock.Object, generatedDataKeyCryptoKey.Object))
            .Returns(encryptedKey);

            Assert.Throws <AppEncryptionException>(() =>
                                                   awsKeyManagementServiceImplSpy.Object.EncryptKey(cryptoKeyMock.Object));
            Assert.Equal(new byte[] { 0, 0 }, dataKeyPlainText);
        }
        public void ShouldSetValue()
        {
            var identifier = new DataKeyIdentifier(Guid.NewGuid().ToString(), new Dictionary <string, string>());

            var cacheKey = Guid.NewGuid().ToString();

            _cacheKeyGenerator.Setup(x =>
                                     x.Generate(identifier))
            .Returns(cacheKey);

            var cacheValue = new byte[] { 1, 2, 3 };

            var item = new GenerateDataKeyResult();

            _cacheValueConverter.Setup(x => x.Convert(item))
            .Returns(cacheValue);

            var entryOptions = new DistributedCacheEntryOptions();

            _distributedCacheEntryOptionsFactory.Setup(x => x.Create(CacheItemType.DataKey))
            .Returns(entryOptions);

            var dataKeyCache = new DataKeyCache(_cacheKeyGenerator.Object, _distributedCache.Object, _cacheValueConverter.Object, _distributedCacheEntryOptionsFactory.Object);

            dataKeyCache.Set(identifier, item);

            _distributedCache.Verify(x => x.Set(cacheKey, cacheValue, entryOptions));
        }
        public void ShouldReturnResultFromCacheOnGenerateDataKey()
        {
            var keyId = Guid.NewGuid().ToString();

            var dataKeyResult = new GenerateDataKeyResult()
            {
                KeyCiphertext = new byte[] { 1, 2, 3 },
                KeyPlaintext  = new byte[] { 4, 5, 6 }
            };

            _dataKeyCache.Setup(x => x.Get(It.Is <DataKeyIdentifier>(identifier =>
                                                                     identifier.KeyId == keyId && identifier.EncryptionContext == _encryptionContext)))
            .Returns(dataKeyResult);

            var result =
                _keyManagementServiceCache.GenerateDataKey(keyId, _encryptionContext, Guid.NewGuid().ToString());

            _keyManagementService.Verify(
                x => x.GenerateDataKey(
                    It.IsAny <string>(),
                    It.IsAny <Dictionary <string, string> >(),
                    It.IsAny <string>()), Times.Never);

            result.KeyPlaintext.ShouldBe(dataKeyResult.KeyPlaintext);
            result.KeyCiphertext.ShouldBe(dataKeyResult.KeyCiphertext);
        }
        public void ShouldGetValue()
        {
            var identifier = new DataKeyIdentifier(Guid.NewGuid().ToString(), new Dictionary <string, string>());

            var cacheKey = Guid.NewGuid().ToString();

            _cacheKeyGenerator.Setup(x =>
                                     x.Generate(identifier))
            .Returns(cacheKey);

            var cacheValue = new byte[] { 1, 2, 3 };

            _distributedCache.Setup(x => x.Get(cacheKey))
            .Returns(cacheValue);

            var expected = new GenerateDataKeyResult();

            _cacheValueConverter.Setup(x => x.Convert(cacheValue))
            .Returns(expected);

            var dataKeyCache = new DataKeyCache(_cacheKeyGenerator.Object, _distributedCache.Object, _cacheValueConverter.Object, _distributedCacheEntryOptionsFactory.Object);

            var result = dataKeyCache.Get(identifier);

            result.ShouldBe(expected);
        }
        public GenerateDataKeyResult Convert(byte[] cacheValue)
        {
            using (var ms = new MemoryStream(cacheValue))
            {
                using (var sr = new BinaryReader(ms))
                {
                    var keyCiphertextLengthBytes = sr.ReadBytes(sizeof(int));
                    Array.Reverse(keyCiphertextLengthBytes);
                    var keyCiphertextLength = BitConverter.ToInt32(keyCiphertextLengthBytes, 0);

                    var obj = new GenerateDataKeyResult();
                    obj.KeyCiphertext = sr.ReadBytes(keyCiphertextLength);

                    var keyPlaintextLengthBytes = sr.ReadBytes(sizeof(int));
                    Array.Reverse(keyPlaintextLengthBytes);
                    var keyPlaintextLength = BitConverter.ToInt32(keyPlaintextLengthBytes, 0);

                    obj.KeyPlaintext = sr.ReadBytes(keyPlaintextLength);

                    return(new GenerateDataKeyResult
                    {
                        KeyCiphertext = obj.KeyCiphertext,
                        KeyPlaintext = obj.KeyPlaintext
                    });
                }
            }
        }
Ejemplo n.º 10
0
        public override byte[] EncryptKey(CryptoKey key)
        {
            using (MetricsUtil.MetricsInstance.Measure.Timer.Time(EncryptkeyTimerOptions))
            {
                Json kmsKeyEnvelope = new Json();

                // We generate a KMS datakey (plaintext and encrypted) and encrypt its plaintext key against remaining regions.
                // This allows us to be able to decrypt from any of the regions locally later.
                GenerateDataKeyResult dataKey = GenerateDataKey(RegionToArnAndClientDictionary, out string dateKeyKeyId);
                byte[] dataKeyPlainText       = dataKey.KeyPlaintext;
                try
                {
                    byte[] encryptedKey = crypto.EncryptKey(key, crypto.GenerateKeyFromBytes(dataKeyPlainText));
                    kmsKeyEnvelope.Put(EncryptedKey, encryptedKey);

                    ConcurrentBag <JObject> kmsRegionKeyJsonBag = new ConcurrentBag <JObject>();
                    Parallel.ForEach(RegionToArnAndClientDictionary.Cast <object>(), regionToArnClientObject =>
                    {
                        DictionaryEntry regionToArnAndClient = (DictionaryEntry)regionToArnClientObject;
                        AwsKmsArnClient arnClient            = (AwsKmsArnClient)regionToArnAndClient.Value;
                        string region = (string)regionToArnAndClient.Key;
                        if (!arnClient.Arn.Equals(dateKeyKeyId))
                        {
                            // If the ARN is different than the datakey's, call encrypt since it's another region
                            EncryptKeyAndBuildResult(
                                arnClient.AwsKmsClient,
                                region,
                                arnClient.Arn,
                                dataKeyPlainText).IfSome(encryptedKeyResult => kmsRegionKeyJsonBag.Add(encryptedKeyResult));
                        }
                        else
                        {
                            // This is the datakey, so build kmsKey json for it
                            kmsRegionKeyJsonBag.Add((JObject)Option <JObject> .Some(BuildKmsRegionKeyJson(
                                                                                        region,
                                                                                        dateKeyKeyId,
                                                                                        dataKey.KeyCiphertext)));
                        }
                    });

                    // TODO Consider adding minimum or quorum check on number of entries
                    kmsKeyEnvelope.Put(KmsKeksKey, kmsRegionKeyJsonBag.ToList());
                }
                catch (Exception e)
                {
                    Logger.LogError(e, "Unexpected execution exception while encrypting KMS data key");
                    throw new AppEncryptionException("unexpected execution error during encrypt", e);
                }
                finally
                {
                    ManagedBufferUtils.WipeByteArray(dataKeyPlainText);
                }

                return(kmsKeyEnvelope.ToUtf8());
            }
        }
        public void Set(DataKeyIdentifier key, GenerateDataKeyResult item)
        {
            var cacheKey = _cacheKeyGenerator.Generate(key);

            var cacheValue = _cacheValueConverter.Convert(item);

            var options = _distributedCacheEntryOptionsFactory.Create(CacheItemType.DataKey);

            _distributedCache.Set(cacheKey, cacheValue, options);
        }
        private void TestGenerateDataKeySuccessful()
        {
            OrderedDictionary sortedRegionToArnAndClient =
                awsKeyManagementServiceImplSpy.Object.RegionToArnAndClientDictionary;
            Mock <GenerateDataKeyResult> dataKeyResultMock = new Mock <GenerateDataKeyResult>();

            amazonKeyManagementServiceClientMock
            .Setup(x => x.GenerateDataKey(ArnUsWest1, null, DataKeySpec.AES_256))     // preferred region's ARN, verify it's the first and hence returned
            .Returns(dataKeyResultMock.Object);
            GenerateDataKeyResult dataKeyResponseActual =
                awsKeyManagementServiceImplSpy.Object.GenerateDataKey(sortedRegionToArnAndClient, out _);

            Assert.Equal(dataKeyResultMock.Object, dataKeyResponseActual);
        }
        public void ShouldConvertFromCacheValue()
        {
            var cacheValueConverter = new CacheValueConverter();
            var cacheValue          = new byte[] { 0, 0, 0, 2, 1, 2, 0, 0, 0, 3, 3, 4, 5 };
            var result = cacheValueConverter.Convert(cacheValue);

            var expected = new GenerateDataKeyResult()
            {
                KeyCiphertext = new byte[] { 1, 2 },
                KeyPlaintext  = new byte[] { 3, 4, 5 }
            };

            Assert.True(result.KeyCiphertext.SequenceEqual(expected.KeyCiphertext));
            Assert.True(result.KeyPlaintext.SequenceEqual(expected.KeyPlaintext));
        }
        public byte[] Convert(GenerateDataKeyResult result)
        {
            using (var ms = new MemoryStream())
            {
                using (var sw = new BinaryWriter(ms))
                {
                    var keyCiphertextLengthBytes = BitConverter.GetBytes(result.KeyCiphertext.Length);
                    Array.Reverse(keyCiphertextLengthBytes);
                    var keyPlaintextLengthBytes = BitConverter.GetBytes(result.KeyPlaintext.Length);
                    Array.Reverse(keyPlaintextLengthBytes);

                    sw.Write(keyCiphertextLengthBytes);
                    sw.Write(result.KeyCiphertext);
                    sw.Write(keyPlaintextLengthBytes);
                    sw.Write(result.KeyPlaintext);

                    sw.Flush();
                }

                return(ms.ToArray());
            }
        }
 public void GenerateDataKeyCalled()
 {
     _result = Manager.GenerateDataKey(_keyId);
 }
Ejemplo n.º 16
0
        private void TestEncryptKeySuccessful()
        {
            byte[] encryptedKey         = { 3, 4 };
            byte[] dataKeyPlainText     = { 1, 2 };
            byte[] dataKeyCipherText    = { 5, 6 };
            byte[] encryptKeyCipherText = { 7, 8 };

            JObject encryptKeyAndBuildResultJson = JObject.FromObject(new Dictionary <string, object>
            {
                { RegionKey, UsEast1 },
                { ArnKey, ArnUsEast1 },
                { EncryptedKek, Convert.ToBase64String(encryptKeyCipherText) },
            });

            JObject kmsKeyEnvelope = JObject.FromObject(new Dictionary <string, object>
            {
                { EncryptedKey, Convert.ToBase64String(encryptedKey) },
                {
                    KmsKeksKey, new List <object>
                    {
                        new Dictionary <string, object>
                        {
                            { RegionKey, UsWest1 },
                            { ArnKey, ArnUsWest1 },
                            { EncryptedKek, Convert.ToBase64String(dataKeyCipherText) },
                        },
                        encryptKeyAndBuildResultJson,
                    }
                },
            });
            GenerateDataKeyResult generateDataKeyResult = new GenerateDataKeyResult
            {
                KeyPlaintext  = dataKeyPlainText,
                KeyCiphertext = dataKeyCipherText,
            };

            Mock <CryptoKey> generatedDataKeyCryptoKey = new Mock <CryptoKey>();
            string           keyId = ArnUsWest1;

            awsKeyManagementServiceImplSpy
            .Setup(x =>
                   x.GenerateDataKey(awsKeyManagementServiceImplSpy.Object.RegionToArnAndClientDictionary, out keyId))
            .Returns(generateDataKeyResult);
            cryptoMock.Setup(x => x.GenerateKeyFromBytes(generateDataKeyResult.KeyPlaintext))
            .Returns(generatedDataKeyCryptoKey.Object);
            cryptoMock.Setup(x => x.EncryptKey(cryptoKeyMock.Object, generatedDataKeyCryptoKey.Object))
            .Returns(encryptedKey);
            awsKeyManagementServiceImplSpy.Setup(x =>
                                                 x.EncryptKeyAndBuildResult(
                                                     It.IsAny <IAmazonKeyManagementService>(),
                                                     UsEast1,
                                                     ArnUsEast1,
                                                     dataKeyPlainText))
            .Returns(Option <JObject> .Some(encryptKeyAndBuildResultJson));

            byte[]  encryptedResult      = awsKeyManagementServiceImplSpy.Object.EncryptKey(cryptoKeyMock.Object);
            JObject kmsKeyEnvelopeResult = new Asherah.AppEncryption.Util.Json(encryptedResult).ToJObject();

            Assert.Equal(new byte[] { 0, 0 }, dataKeyPlainText);

            // This is a workaround for https://github.com/JamesNK/Newtonsoft.Json/issues/1437
            // If DeepEquals fails due to mismatching array order, compare the elements individually
            if (!JToken.DeepEquals(kmsKeyEnvelope, kmsKeyEnvelopeResult))
            {
                JArray kmsKeyEnvelopeKmsKeks = JArray.FromObject(kmsKeyEnvelope[KmsKeksKey]
                                                                 .OrderBy(k => k[RegionKey]));
                JArray kmsKeyEnvelopeResultKmsKeks = JArray.FromObject(kmsKeyEnvelopeResult[KmsKeksKey]
                                                                       .OrderBy(k => k[RegionKey]));

                Assert.True(JToken.DeepEquals(kmsKeyEnvelope[EncryptedKey], kmsKeyEnvelopeResult[EncryptedKey]));
                Assert.True(JToken.DeepEquals(kmsKeyEnvelopeKmsKeks, kmsKeyEnvelopeResultKmsKeks));
            }
        }
 public void DataKeyIsGeneratedAndRoundTripped()
 {
     _result = Manager.GenerateDataKey(_keyId);
     _decryptedCipherText = Manager.DecryptData(_result.CipherTextKey);
 }
Ejemplo n.º 18
0
        private void TestEncryptKeySuccessful()
        {
            byte[] encryptedKey         = { 3, 4 };
            byte[] dataKeyPlainText     = { 1, 2 };
            byte[] dataKeyCipherText    = { 5, 6 };
            byte[] encryptKeyCipherText = { 7, 8 };

            JObject encryptKeyAndBuildResultJson = JObject.FromObject(new Dictionary <string, object>
            {
                { RegionKey, UsEast1 },
                { ArnKey, ArnUsEast1 },
                { EncryptedKek, Convert.ToBase64String(encryptKeyCipherText) }
            });

            JObject kmsKeyEnvelope = JObject.FromObject(new Dictionary <string, object>
            {
                { EncryptedKey, Convert.ToBase64String(encryptedKey) },
                {
                    // For some reason we have to use ConcurrentBag here. Likely due to internal ConcurrentBag list
                    // structure failing to compare against regular List?
                    KmsKeksKey, new ConcurrentBag <object>
                    {
                        new Dictionary <string, object>
                        {
                            { RegionKey, UsWest1 },
                            { ArnKey, ArnUsWest1 },
                            { EncryptedKek, Convert.ToBase64String(dataKeyCipherText) }
                        },
                        encryptKeyAndBuildResultJson
                    }
                }
            });
            GenerateDataKeyResult generateDataKeyResult = new GenerateDataKeyResult
            {
                KeyPlaintext  = dataKeyPlainText,
                KeyCiphertext = dataKeyCipherText
            };

            Mock <CryptoKey> generatedDataKeyCryptoKey = new Mock <CryptoKey>();
            string           keyId = ArnUsWest1;

            awsKeyManagementServiceImplSpy
            .Setup(x =>
                   x.GenerateDataKey(awsKeyManagementServiceImplSpy.Object.RegionToArnAndClientDictionary, out keyId))
            .Returns(generateDataKeyResult);
            cryptoMock.Setup(x => x.GenerateKeyFromBytes(generateDataKeyResult.KeyPlaintext))
            .Returns(generatedDataKeyCryptoKey.Object);
            cryptoMock.Setup(x => x.EncryptKey(cryptoKeyMock.Object, generatedDataKeyCryptoKey.Object))
            .Returns(encryptedKey);
            awsKeyManagementServiceImplSpy.Setup(x =>
                                                 x.EncryptKeyAndBuildResult(
                                                     It.IsAny <IAmazonKeyManagementService>(),
                                                     UsEast1,
                                                     ArnUsEast1,
                                                     dataKeyPlainText))
            .Returns(Option <JObject> .Some(encryptKeyAndBuildResultJson));

            byte[] encryptedResult = awsKeyManagementServiceImplSpy.Object.EncryptKey(cryptoKeyMock.Object);
            Asherah.AppEncryption.Util.Json kmsKeyEnvelopeResult = new Asherah.AppEncryption.Util.Json(encryptedResult);

            Assert.True(JToken.DeepEquals(kmsKeyEnvelope, kmsKeyEnvelopeResult.ToJObject()));
            Assert.Equal(new byte[] { 0, 0 }, dataKeyPlainText);
        }