public void ThrowWhenDecryptingLessThanSixtyFiveBytes(byte[] ciphertext)
        {
            DataEncryptionKey encryptionKey = new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey);
            AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Deterministic);

            Assert.Throws <ArgumentException>(() => encryptionAlgorithm.Decrypt(ciphertext));
        }
Example #2
0
        private async Task DecryptObjectAsync(
            JObject document,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            Debug.Assert(diagnosticsContext != null);

            foreach (ClientEncryptionIncludedPath path in this.ClientEncryptionPolicy.IncludedPaths)
            {
                if (document.TryGetValue(path.Path.Substring(1), out JToken propertyValue))
                {
                    string propertyName = path.Path.Substring(1);
                    EncryptionSettingForProperty settingsForProperty = await this.EncryptionSettings.GetEncryptionSettingForPropertyAsync(propertyName, cancellationToken);

                    if (settingsForProperty == null)
                    {
                        throw new ArgumentException($"Invalid Encryption Setting for Property:{propertyName}. ");
                    }

                    AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingsForProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken);

                    this.DecryptProperty(
                        document,
                        aeadAes256CbcHmac256EncryptionAlgorithm,
                        propertyName,
                        propertyValue);
                }
            }

            return;
        }
Example #3
0
        private JToken DecryptAndDeserializeValue(
            JToken jToken,
            AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm)
        {
            byte[] cipherTextWithTypeMarker = jToken.ToObject <byte[]>();

            if (cipherTextWithTypeMarker == null)
            {
                return(null);
            }

            byte[] cipherText = new byte[cipherTextWithTypeMarker.Length - 1];
            Buffer.BlockCopy(cipherTextWithTypeMarker, 1, cipherText, 0, cipherTextWithTypeMarker.Length - 1);

            byte[] plainText = aeadAes256CbcHmac256EncryptionAlgorithm.Decrypt(cipherText);

            if (plainText == null)
            {
                throw new InvalidOperationException($"{nameof(this.DecryptAndDeserializeValue)} returned null plainText from {nameof(aeadAes256CbcHmac256EncryptionAlgorithm.Decrypt)}. ");
            }

            return(DeserializeAndAddProperty(
                       plainText,
                       (TypeMarker)cipherTextWithTypeMarker[0]));
        }
Example #4
0
        private JToken SerializeAndEncryptValue(
            JToken jToken,
            AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm)
        {
            JToken propertyValueToEncrypt = jToken;

            if (propertyValueToEncrypt.Type == JTokenType.Null)
            {
                return(propertyValueToEncrypt);
            }

            (TypeMarker typeMarker, byte[] plainText) = Serialize(propertyValueToEncrypt);

            byte[] cipherText = aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt(plainText);

            if (cipherText == null)
            {
                throw new InvalidOperationException($"{nameof(this.SerializeAndEncryptValue)} returned null cipherText from {nameof(aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt)}. ");
            }

            byte[] cipherTextWithTypeMarker = new byte[cipherText.Length + 1];
            cipherTextWithTypeMarker[0] = (byte)typeMarker;
            Buffer.BlockCopy(cipherText, 0, cipherTextWithTypeMarker, 1, cipherText.Length);
            return(cipherTextWithTypeMarker);
        }
Example #5
0
        internal static async Task <Stream> EncryptValueStreamAsync(
            Stream valueStream,
            EncryptionSettingForProperty settingsForProperty,
            CancellationToken cancellationToken)
        {
            if (valueStream == null)
            {
                throw new ArgumentNullException(nameof(valueStream));
            }

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

            AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingsForProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken);

            JToken propertyValueToEncrypt = EncryptionProcessor.BaseSerializer.FromStream <JToken>(valueStream);

            (EncryptionProcessor.TypeMarker typeMarker, byte[] serializedData) = EncryptionProcessor.Serialize(propertyValueToEncrypt);

            byte[] cipherText = aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt(serializedData);

            if (cipherText == null)
            {
                throw new InvalidOperationException($"{nameof(EncryptValueStreamAsync)} returned null cipherText from {nameof(aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt)}. Please refer to https://aka.ms/CosmosClientEncryption for more details. ");
            }

            byte[] cipherTextWithTypeMarker = new byte[cipherText.Length + 1];
            cipherTextWithTypeMarker[0] = (byte)typeMarker;
            Buffer.BlockCopy(cipherText, 0, cipherTextWithTypeMarker, 1, cipherText.Length);

            return(EncryptionProcessor.BaseSerializer.ToStream(cipherTextWithTypeMarker));
        }
        public async Task <AeadAes256CbcHmac256EncryptionAlgorithm> BuildEncryptionAlgorithmForSettingAsync(CancellationToken cancellationToken)
        {
            ClientEncryptionKeyProperties clientEncryptionKeyProperties = await this.encryptionContainer.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync(
                clientEncryptionKeyId : this.ClientEncryptionKeyId,
                encryptionContainer : this.encryptionContainer,
                databaseRid : this.databaseRid,
                ifNoneMatchEtag : null,
                shouldForceRefresh : false,
                cancellationToken : cancellationToken);

            ProtectedDataEncryptionKey protectedDataEncryptionKey;

            try
            {
                // we pull out the Encrypted Data Encryption Key and build the Protected Data Encryption key
                // Here a request is sent out to unwrap using the Master Key configured via the Key Encryption Key.
                protectedDataEncryptionKey = await this.BuildProtectedDataEncryptionKeyAsync(
                    clientEncryptionKeyProperties,
                    this.ClientEncryptionKeyId,
                    cancellationToken);
            }
            catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.Forbidden)
            {
                // The access to master key was probably revoked. Try to fetch the latest ClientEncryptionKeyProperties from the backend.
                // This will succeed provided the user has rewraped the Client Encryption Key with right set of meta data.
                // This is based on the AKV provider implementaion so we expect a RequestFailedException in case other providers are used in unwrap implementation.
                // first try to force refresh the local cache, we might have a stale cache.
                clientEncryptionKeyProperties = await this.encryptionContainer.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync(
                    clientEncryptionKeyId : this.ClientEncryptionKeyId,
                    encryptionContainer : this.encryptionContainer,
                    databaseRid : this.databaseRid,
                    ifNoneMatchEtag : null,
                    shouldForceRefresh : true,
                    cancellationToken : cancellationToken);

                try
                {
                    // try to build the ProtectedDataEncryptionKey. If it fails, try to force refresh the gateway cache and get the latest client encryption key.
                    protectedDataEncryptionKey = await this.BuildProtectedDataEncryptionKeyAsync(
                        clientEncryptionKeyProperties,
                        this.ClientEncryptionKeyId,
                        cancellationToken);
                }
                catch (RequestFailedException exOnRetry) when(exOnRetry.Status == (int)HttpStatusCode.Forbidden)
                {
                    // the gateway cache could be stale. Force refresh the gateway cache.
                    // bail out if this fails.
                    protectedDataEncryptionKey = await this.ForceRefreshGatewayCacheAndBuildProtectedDataEncryptionKeyAsync(
                        existingCekEtag : clientEncryptionKeyProperties.ETag,
                        refreshRetriedOnException : exOnRetry,
                        cancellationToken : cancellationToken);
                }
            }

            AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = new AeadAes256CbcHmac256EncryptionAlgorithm(
                protectedDataEncryptionKey,
                this.EncryptionType);

            return(aeadAes256CbcHmac256EncryptionAlgorithm);
        }
        public void ThrowWhenDecryptionAnInvalidAuthenticationTag()
        {
            byte[]            invalidAuthTag = new byte[] { 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 };
            DataEncryptionKey encryptionKey  = new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey);
            AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Deterministic);

            Assert.Throws <CryptographicException>(() => encryptionAlgorithm.Decrypt(invalidAuthTag));
        }
Example #8
0
 /// <summary>
 /// Initializes a new instance of MdeEncryptionAlgorithm.
 /// Uses <see cref="AeadAes256CbcHmac256EncryptionAlgorithm"/> which implements authenticated encryption algorithm with associated data as described
 /// <see href="http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05">here</see> .
 /// More specifically this implements AEAD_AES_256_CBC_HMAC_SHA256 algorithm.
 /// </summary>
 /// <param name="dataEncryptionKey"> Data Encryption Key </param>
 /// <param name="encryptionType"> Encryption type </param>
 public MdeEncryptionAlgorithm(
     Data.Encryption.Cryptography.DataEncryptionKey dataEncryptionKey,
     Data.Encryption.Cryptography.EncryptionType encryptionType)
 {
     this.mdeAeadAes256CbcHmac256EncryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(
         dataEncryptionKey,
         encryptionType);
 }
        public void ReturnNullWhenDecryptingNull()
        {
            DataEncryptionKey encryptionKey = new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey);
            AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Deterministic);

            byte[] plaintext = encryptionAlgorithm.Decrypt(null);

            Assert.Null(plaintext);
        }
Example #10
0
        /// <summary>
        /// Initializes a new instance of MdeEncryptionAlgorithm.
        /// Uses <see cref="AeadAes256CbcHmac256EncryptionAlgorithm"/> which implements authenticated encryption algorithm with associated data as described
        /// <see href="http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05">here</see> .
        /// More specifically this implements AEAD_AES_256_CBC_HMAC_SHA256 algorithm.
        /// </summary>
        /// <param name="dekProperties"> Data Encryption Key properties</param>
        /// <param name="encryptionType"> Encryption type </param>
        /// <param name="encryptionKeyStoreProvider"> EncryptionKeyStoreProvider for wrapping and unwrapping </param>
        public MdeEncryptionAlgorithm(
            DataEncryptionKeyProperties dekProperties,
            Data.Encryption.Cryptography.EncryptionType encryptionType,
            EncryptionKeyStoreProvider encryptionKeyStoreProvider,
            TimeSpan?cacheTimeToLive)
        {
            if (dekProperties == null)
            {
                throw new ArgumentNullException(nameof(dekProperties));
            }

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

            KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate(
                dekProperties.EncryptionKeyWrapMetadata.Name,
                dekProperties.EncryptionKeyWrapMetadata.Value,
                encryptionKeyStoreProvider);

            ProtectedDataEncryptionKey protectedDataEncryptionKey;

            if (cacheTimeToLive.HasValue)
            {
                // no caching
                if (cacheTimeToLive.Value == TimeSpan.Zero)
                {
                    protectedDataEncryptionKey = new ProtectedDataEncryptionKey(
                        dekProperties.Id,
                        keyEncryptionKey,
                        dekProperties.WrappedDataEncryptionKey);
                }
                else
                {
                    protectedDataEncryptionKey = ProtectedDataEncryptionKey.GetOrCreate(
                        dekProperties.Id,
                        keyEncryptionKey,
                        dekProperties.WrappedDataEncryptionKey);

                    protectedDataEncryptionKey.TimeToLive = cacheTimeToLive.Value;
                }
            }
            else
            {
                protectedDataEncryptionKey = ProtectedDataEncryptionKey.GetOrCreate(
                    dekProperties.Id,
                    keyEncryptionKey,
                    dekProperties.WrappedDataEncryptionKey);
            }

            this.mdeAeadAes256CbcHmac256EncryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(
                protectedDataEncryptionKey,
                encryptionType);
        }
Example #11
0
        internal static IEnumerable <byte[]> Encrypt(this IEnumerable source, EncryptionSettings settings)
        {
            DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(settings.DataEncryptionKey, settings.EncryptionType);
            ISerializer   serializer          = settings.GetSerializer();

            foreach (var item in source)
            {
                byte[] serializedData = serializer.Serialize(item);
                yield return(encryptionAlgorithm.Encrypt(serializedData));
            }
        }
Example #12
0
        public async Task <AeadAes256CbcHmac256EncryptionAlgorithm> BuildEncryptionAlgorithmForSettingAsync(CancellationToken cancellationToken)
        {
            ClientEncryptionKeyProperties clientEncryptionKeyProperties = await this.encryptionContainer.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync(
                clientEncryptionKeyId : this.ClientEncryptionKeyId,
                encryptionContainer : this.encryptionContainer,
                databaseRid : this.databaseRid,
                cancellationToken : cancellationToken);

            ProtectedDataEncryptionKey protectedDataEncryptionKey;

            try
            {
                // we pull out the Encrypted Data Encryption Key and build the Protected Data Encryption key
                // Here a request is sent out to unwrap using the Master Key configured via the Key Encryption Key.
                protectedDataEncryptionKey = this.BuildProtectedDataEncryptionKey(
                    clientEncryptionKeyProperties,
                    this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyStoreProvider,
                    this.ClientEncryptionKeyId);
            }
            catch (RequestFailedException ex)
            {
                // The access to master key was probably revoked. Try to fetch the latest ClientEncryptionKeyProperties from the backend.
                // This will succeed provided the user has rewraped the Client Encryption Key with right set of meta data.
                // This is based on the AKV provider implementaion so we expect a RequestFailedException in case other providers are used in unwrap implementation.
                if (ex.Status == (int)HttpStatusCode.Forbidden)
                {
                    clientEncryptionKeyProperties = await this.encryptionContainer.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync(
                        clientEncryptionKeyId : this.ClientEncryptionKeyId,
                        encryptionContainer : this.encryptionContainer,
                        databaseRid : this.databaseRid,
                        cancellationToken : cancellationToken,
                        shouldForceRefresh : true);

                    // just bail out if this fails.
                    protectedDataEncryptionKey = this.BuildProtectedDataEncryptionKey(
                        clientEncryptionKeyProperties,
                        this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyStoreProvider,
                        this.ClientEncryptionKeyId);
                }
                else
                {
                    throw;
                }
            }

            AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = new AeadAes256CbcHmac256EncryptionAlgorithm(
                protectedDataEncryptionKey,
                this.EncryptionType);

            return(aeadAes256CbcHmac256EncryptionAlgorithm);
        }
Example #13
0
        /// <remarks>
        /// If there isn't any PathsToEncrypt, input stream will be returned without any modification.
        /// Else input stream will be disposed, and a new stream is returned.
        /// In case of an exception, input stream won't be disposed, but position will be end of stream.
        /// </remarks>
        public async Task <Stream> EncryptAsync(
            Stream input,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }

            Debug.Assert(diagnosticsContext != null);

            await this.InitEncryptionSettingsIfNotInitializedAsync(cancellationToken);

            if (this.ClientEncryptionPolicy == null)
            {
                return(input);
            }

            JObject itemJObj = EncryptionProcessor.BaseSerializer.FromStream <JObject>(input);

            foreach (ClientEncryptionIncludedPath pathToEncrypt in this.ClientEncryptionPolicy.IncludedPaths)
            {
                string propertyName = pathToEncrypt.Path.Substring(1);

                // possibly a wrong path configured in the Client Encryption Policy, ignore.
                if (!itemJObj.TryGetValue(propertyName, out JToken propertyValue))
                {
                    continue;
                }

                EncryptionSettingForProperty settingforProperty = await this.EncryptionSettings.GetEncryptionSettingForPropertyAsync(propertyName, cancellationToken);

                if (settingforProperty == null)
                {
                    throw new ArgumentException($"Invalid Encryption Setting for the Property:{propertyName}. ");
                }

                AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingforProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken);

                this.EncryptProperty(
                    itemJObj,
                    propertyValue,
                    aeadAes256CbcHmac256EncryptionAlgorithm);
            }

            input.Dispose();
            return(EncryptionProcessor.BaseSerializer.ToStream(itemJObj));
        }
Example #14
0
 internal static EncryptionSettings Create(
     EncryptionSettings settingsForKey,
     EncryptionType encryptionType)
 {
     return(new EncryptionSettings()
     {
         ClientEncryptionKeyId = settingsForKey.ClientEncryptionKeyId,
         DataEncryptionKey = settingsForKey.DataEncryptionKey,
         EncryptionType = encryptionType,
         EncryptionSettingTimeToLive = settingsForKey.EncryptionSettingTimeToLive,
         AeadAes256CbcHmac256EncryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(
             settingsForKey.DataEncryptionKey,
             encryptionType),
     });
 }
        public void EncryptToSameCiphertextWhenDeterministicEncryptionTypeSelected(DataEncryptionKey encryptionKey)
        {
            EncryptionType encryptionType = EncryptionType.Deterministic;

            byte[] serializedPlaintext = new byte[] { 1, 2, 3, 4, 5 };
            AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, encryptionType);

            byte[] ciphertext1 = encryptionAlgorithm.Encrypt(serializedPlaintext);
            byte[] ciphertext2 = encryptionAlgorithm.Encrypt(serializedPlaintext);
            byte[] ciphertext3 = encryptionAlgorithm.Encrypt(serializedPlaintext);

            Assert.Equal(ciphertext1, ciphertext2);
            Assert.Equal(ciphertext2, ciphertext3);
            Assert.Equal(ciphertext1, ciphertext3);
        }
        public void EncryptToDifferentCiphertextWhenRandomizedEncryptionTypeSelected(DataEncryptionKey encryptionKey)
        {
            EncryptionType encryptionType = EncryptionType.Randomized;

            byte[] serializedPlaintext = new byte[] { 1, 2, 3, 4, 5 };
            AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, encryptionType);

            byte[] ciphertext1 = encryptionAlgorithm.Encrypt(serializedPlaintext);
            byte[] ciphertext2 = encryptionAlgorithm.Encrypt(serializedPlaintext);
            byte[] ciphertext3 = encryptionAlgorithm.Encrypt(serializedPlaintext);

            Assert.NotEqual(ciphertext1, ciphertext2);
            Assert.NotEqual(ciphertext2, ciphertext3);
            Assert.NotEqual(ciphertext1, ciphertext3);
        }
Example #17
0
        internal static IList Decrypt(this IEnumerable source, EncryptionSettings settings)
        {
            DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(settings.DataEncryptionKey, settings.EncryptionType);
            ISerializer   serializer          = settings.GetSerializer();

            Type  type = serializer.GetType().BaseType.GetGenericArguments()[0];
            IList list = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(type));

            foreach (var item in source)
            {
                byte[] plaintextData = encryptionAlgorithm.Decrypt((byte[])item);
                list.Add(serializer.Deserialize(plaintextData));
            }

            return(list);
        }
Example #18
0
        /// <remarks>
        /// If there isn't any PathsToEncrypt, input stream will be returned without any modification.
        /// Else input stream will be disposed, and a new stream is returned.
        /// In case of an exception, input stream won't be disposed, but position will be end of stream.
        /// </remarks>
        public static async Task <Stream> EncryptAsync(
            Stream input,
            EncryptionSettings encryptionSettings,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }

            Debug.Assert(diagnosticsContext != null);

            JObject itemJObj = EncryptionProcessor.BaseSerializer.FromStream <JObject>(input);

            foreach (string propertyName in encryptionSettings.PropertiesToEncrypt)
            {
                // possibly a wrong path configured in the Client Encryption Policy, ignore.
                if (!itemJObj.TryGetValue(propertyName, out JToken propertyValue))
                {
                    continue;
                }

                EncryptionSettingForProperty settingforProperty = encryptionSettings.GetEncryptionSettingForProperty(propertyName);

                if (settingforProperty == null)
                {
                    throw new ArgumentException($"Invalid Encryption Setting for the Property:{propertyName}. ");
                }

                AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingforProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken);

                EncryptProperty(
                    itemJObj,
                    propertyValue,
                    aeadAes256CbcHmac256EncryptionAlgorithm);
            }

            input.Dispose();
            return(EncryptionProcessor.BaseSerializer.ToStream(itemJObj));
        }
        public void CacheEncryptionAlgorithmsCorrectlyWhenCallingGetOrCreate()
        {
            DataEncryptionKey key1 = new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey);
            DataEncryptionKey key2 = new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey);
            DataEncryptionKey key3 = new ProtectedDataEncryptionKey("Not_EK", keyEncryptionKey, encryptedDataEncryptionKey);

            AeadAes256CbcHmac256EncryptionAlgorithm algorithm1 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key1, EncryptionType.Deterministic);
            AeadAes256CbcHmac256EncryptionAlgorithm algorithm2 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key2, EncryptionType.Deterministic);

            Assert.Same(algorithm1, algorithm2);

            AeadAes256CbcHmac256EncryptionAlgorithm algorithm3 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key1, EncryptionType.Deterministic);
            AeadAes256CbcHmac256EncryptionAlgorithm algorithm4 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key2, EncryptionType.Randomized);

            Assert.NotSame(algorithm3, algorithm4);

            AeadAes256CbcHmac256EncryptionAlgorithm algorithm5 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key1, EncryptionType.Randomized);
            AeadAes256CbcHmac256EncryptionAlgorithm algorithm6 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key3, EncryptionType.Randomized);

            Assert.NotSame(algorithm5, algorithm6);
        }
        public void EncryptAndDecryptToTheSameValue <T>(T originalPlaintext, Serializer <T> serializer)
        {
            DataEncryptionKey[] keys =
            {
                new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey),
                new PlaintextDataEncryptionKey("EK", plaintextEncryptionKeyBytes)
            };

            foreach (DataEncryptionKey encryptionKey in keys)
            {
                EncryptionType encryptionType = (EncryptionType)random.Next(1, 2);
                AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, encryptionType);

                byte[] serializedPlaintext = serializer.Serialize(originalPlaintext);
                byte[] ciphhertext         = encryptionAlgorithm.Encrypt(serializedPlaintext);
                byte[] decryptedPlaintext  = encryptionAlgorithm.Decrypt(ciphhertext);
                T      actualPlaintext     = serializer.Deserialize(decryptedPlaintext);

                Assert.Equal(originalPlaintext, actualPlaintext);
            }
        }
Example #21
0
        private void EncryptProperty(
            JObject itemJObj,
            JToken propertyValue,
            AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm)
        {
            /* Top Level can be an Object*/
            if (propertyValue.Type == JTokenType.Object)
            {
                foreach (JProperty jProperty in propertyValue.Children <JProperty>())
                {
                    if (jProperty.Value.Type == JTokenType.Object || jProperty.Value.Type == JTokenType.Array)
                    {
                        this.EncryptProperty(
                            itemJObj,
                            jProperty.Value,
                            aeadAes256CbcHmac256EncryptionAlgorithm);
                    }
                    else
                    {
                        jProperty.Value = this.SerializeAndEncryptValue(jProperty.Value, aeadAes256CbcHmac256EncryptionAlgorithm);
                    }
                }
            }
            else if (propertyValue.Type == JTokenType.Array)
            {
                if (propertyValue.Children().Any())
                {
                    // objects as array elements.
                    if (propertyValue.Children().First().Type == JTokenType.Object)
                    {
                        foreach (JObject arrayjObject in propertyValue.Children <JObject>())
                        {
                            foreach (JProperty jProperty in arrayjObject.Properties())
                            {
                                if (jProperty.Value.Type == JTokenType.Object || jProperty.Value.Type == JTokenType.Array)
                                {
                                    this.EncryptProperty(
                                        itemJObj,
                                        jProperty.Value,
                                        aeadAes256CbcHmac256EncryptionAlgorithm);
                                }

                                // primitive type
                                else
                                {
                                    jProperty.Value = this.SerializeAndEncryptValue(jProperty.Value, aeadAes256CbcHmac256EncryptionAlgorithm);
                                }
                            }
                        }
                    }

                    // array as elements.
                    else if (propertyValue.Children().First().Type == JTokenType.Array)
                    {
                        foreach (JArray jArray in propertyValue.Value <JArray>())
                        {
                            for (int i = 0; i < jArray.Count(); i++)
                            {
                                // iterates over individual elements
                                if (jArray[i].Type == JTokenType.Object || jArray[i].Type == JTokenType.Array)
                                {
                                    this.EncryptProperty(
                                        itemJObj,
                                        jArray[i],
                                        aeadAes256CbcHmac256EncryptionAlgorithm);
                                }

                                // primitive type
                                else
                                {
                                    jArray[i] = this.SerializeAndEncryptValue(jArray[i], aeadAes256CbcHmac256EncryptionAlgorithm);
                                }
                            }
                        }
                    }

                    // array of primitive types.
                    else
                    {
                        for (int i = 0; i < propertyValue.Count(); i++)
                        {
                            propertyValue[i] = this.SerializeAndEncryptValue(propertyValue[i], aeadAes256CbcHmac256EncryptionAlgorithm);
                        }
                    }
                }
            }
            else
            {
                itemJObj.Property(propertyValue.Path).Value = this.SerializeAndEncryptValue(
                    itemJObj.Property(propertyValue.Path).Value,
                    aeadAes256CbcHmac256EncryptionAlgorithm);
            }
        }
Example #22
0
        private void DecryptProperty(
            JObject itemJObj,
            AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm,
            string propertyName,
            JToken propertyValue)
        {
            if (propertyValue.Type == JTokenType.Object)
            {
                foreach (JProperty jProperty in propertyValue.Children <JProperty>())
                {
                    if (jProperty.Value.Type == JTokenType.Object || jProperty.Value.Type == JTokenType.Array)
                    {
                        this.DecryptProperty(
                            itemJObj,
                            aeadAes256CbcHmac256EncryptionAlgorithm,
                            jProperty.Name,
                            jProperty.Value);
                    }
                    else
                    {
                        jProperty.Value = this.DecryptAndDeserializeValue(
                            jProperty.Value,
                            aeadAes256CbcHmac256EncryptionAlgorithm);
                    }
                }
            }
            else if (propertyValue.Type == JTokenType.Array)
            {
                if (propertyValue.Children().Any())
                {
                    if (propertyValue.Children().First().Type == JTokenType.Object)
                    {
                        foreach (JObject arrayjObject in propertyValue.Children <JObject>())
                        {
                            foreach (JProperty jProperty in arrayjObject.Properties())
                            {
                                if (jProperty.Value.Type == JTokenType.Object || jProperty.Value.Type == JTokenType.Array)
                                {
                                    this.DecryptProperty(
                                        itemJObj,
                                        aeadAes256CbcHmac256EncryptionAlgorithm,
                                        jProperty.Name,
                                        jProperty.Value);
                                }
                                else
                                {
                                    jProperty.Value = this.DecryptAndDeserializeValue(
                                        jProperty.Value,
                                        aeadAes256CbcHmac256EncryptionAlgorithm);
                                }
                            }
                        }
                    }
                    else if (propertyValue.Children().First().Type == JTokenType.Array)
                    {
                        foreach (JArray jArray in propertyValue.Value <JArray>())
                        {
                            for (int i = 0; i < jArray.Count(); i++)
                            {
                                // iterates over individual elements
                                if (jArray[i].Type == JTokenType.Object || jArray[i].Type == JTokenType.Array)
                                {
                                    this.DecryptProperty(
                                        itemJObj,
                                        aeadAes256CbcHmac256EncryptionAlgorithm,
                                        jArray[i].Path,
                                        jArray[i]);
                                }
                                else
                                {
                                    jArray[i] = this.DecryptAndDeserializeValue(
                                        jArray[i],
                                        aeadAes256CbcHmac256EncryptionAlgorithm);
                                }
                            }
                        }
                    }

                    // primitive type
                    else
                    {
                        for (int i = 0; i < propertyValue.Count(); i++)
                        {
                            propertyValue[i] = this.DecryptAndDeserializeValue(
                                propertyValue[i],
                                aeadAes256CbcHmac256EncryptionAlgorithm);
                        }
                    }
                }
            }
            else
            {
                itemJObj.Property(propertyName).Value = this.DecryptAndDeserializeValue(
                    itemJObj.Property(propertyName).Value,
                    aeadAes256CbcHmac256EncryptionAlgorithm);
            }
        }
Example #23
0
        /// <summary>
        /// Gets a QueryDefinition with Encrypted Parameters.
        /// </summary>
        /// <param name="queryDefinition"> Query Definition to be replaced with Encrypted Values.</param>
        /// <param name="name"> Query Paramerter Name. </param>
        /// <param name="value"> Query Paramerter Value.</param>
        /// <param name="path"> Encrypted Property Path. </param>
        /// <param name="cancellationToken"> cancellation token </param>
        /// <returns> QueryDefinition with encrypted parameters. </returns>
        /// <example>
        /// This example shows how to pass in a QueryDefinition with Encryption support to AddParameterAsync
        /// to encrypt the required Property for running Query on encrypted data.
        ///
        /// <code language="c#">
        /// <![CDATA[
        /// containerWithEncryption = await this.cosmosDatabase.GetContainer("id").InitializeEncryptionAsync();
        /// QueryDefinition withEncryptedParameter = containerWithEncryption.CreateQueryDefinition(
        ///     "SELECT * FROM c where c.PropertyName = @PropertyValue");
        /// await withEncryptedParameter.AddParameterAsync(
        ///     "@PropertyName",
        ///     PropertyValue,
        ///     "/PropertyName");
        /// ]]>
        /// </code>
        /// </example>
        public static async Task <QueryDefinition> AddParameterAsync(
            this QueryDefinition queryDefinition,
            string name,
            object value,
            string path,
            CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

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

            if (string.IsNullOrWhiteSpace(path) || path[0] != '/' || path.LastIndexOf('/') != 0)
            {
                throw new InvalidOperationException($"Invalid path {path ?? string.Empty}, {nameof(path)}. ");
            }

            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

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

            QueryDefinition queryDefinitionwithEncryptedValues = queryDefinition;

            if (queryDefinition is EncryptionQueryDefinition encryptionQueryDefinition)
            {
                EncryptionContainer encryptionContainer = (EncryptionContainer)encryptionQueryDefinition.Container;
                Stream valueStream = encryptionContainer.CosmosSerializer.ToStream(value);

                // not really required, but will have things setup for subsequent queries or operations on this Container if the Container was never init
                // or if this was the first operation carried out on this container.
                await encryptionContainer.EncryptionProcessor.InitEncryptionSettingsIfNotInitializedAsync(cancellationToken);

                // get the path's encryption setting.
                EncryptionSettingForProperty settingsForProperty = await encryptionContainer.EncryptionProcessor.EncryptionSettings.GetEncryptionSettingForPropertyAsync(
                    path.Substring(1),
                    cancellationToken);

                if (settingsForProperty == null)
                {
                    // property not encrypted.
                    queryDefinitionwithEncryptedValues.WithParameter(name, value);
                    return(queryDefinitionwithEncryptedValues);
                }

                if (settingsForProperty.EncryptionType == EncryptionType.Randomized)
                {
                    throw new ArgumentException($"Unsupported argument with Path: {path} for query. For executing queries on encrypted path requires the use of deterministic encryption type. Please refer to https://aka.ms/CosmosClientEncryption for more details. ");
                }

                AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingsForProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken);

                JToken propertyValueToEncrypt = EncryptionProcessor.BaseSerializer.FromStream <JToken>(valueStream);
                (EncryptionProcessor.TypeMarker typeMarker, byte[] serializedData) = EncryptionProcessor.Serialize(propertyValueToEncrypt);

                byte[] cipherText = aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt(serializedData);

                if (cipherText == null)
                {
                    throw new InvalidOperationException($"{nameof(AddParameterAsync)} returned null cipherText from {nameof(aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt)}. Please refer to https://aka.ms/CosmosClientEncryption for more details. ");
                }

                byte[] cipherTextWithTypeMarker = new byte[cipherText.Length + 1];
                cipherTextWithTypeMarker[0] = (byte)typeMarker;
                Buffer.BlockCopy(cipherText, 0, cipherTextWithTypeMarker, 1, cipherText.Length);
                queryDefinitionwithEncryptedValues.WithParameter(name, cipherTextWithTypeMarker);

                return(queryDefinitionwithEncryptedValues);
            }
            else
            {
                throw new ArgumentException("Executing queries on encrypted path requires the use of an encryption - enabled client. Please refer to https://aka.ms/CosmosClientEncryption for more details. ");
            }
        }