public void CacheEncryptionKeyCorrectlyWhenCallingGetOrCreate()
        {
            KeyEncryptionKey masterKey1 = new KeyEncryptionKey("MK", keyEncryptionKeyPath, azureKeyProvider);
            KeyEncryptionKey masterKey2 = new KeyEncryptionKey("MK", keyEncryptionKeyPath, azureKeyProvider);
            KeyEncryptionKey masterKey3 = new KeyEncryptionKey("Not_MK", keyEncryptionKeyPath, azureKeyProvider);

            byte[] EncryptedKey1 = { 1, 206, 0, 0, 1, 104, 0, 116, 0, 116, 0, 112, 0, 115, 0, 58, 0, 47, 0, 47, 0, 106, 0, 101, 0, 116, 0, 114, 0, 105, 0, 109, 0, 109, 0, 101, 0, 45, 0, 107, 0, 101, 0, 121, 0, 45, 0, 118, 0, 97, 0, 117, 0, 108, 0, 116, 0, 46, 0, 118, 0, 97, 0, 117, 0, 108, 0, 116, 0, 46, 0, 97, 0, 122, 0, 117, 0, 114, 0, 101, 0, 46, 0, 110, 0, 101, 0, 116, 0, 47, 0, 107, 0, 101, 0, 121, 0, 115, 0, 47, 0, 97, 0, 108, 0, 119, 0, 97, 0, 121, 0, 115, 0, 45, 0, 101, 0, 110, 0, 99, 0, 114, 0, 121, 0, 112, 0, 116, 0, 101, 0, 100, 0, 45, 0, 97, 0, 117, 0, 116, 0, 111, 0, 49, 0, 47, 0, 97, 0, 55, 0, 100, 0, 53, 0, 99, 0, 57, 0, 56, 0, 57, 0, 100, 0, 53, 0, 97, 0, 48, 0, 52, 0, 50, 0, 51, 0, 102, 0, 56, 0, 100, 0, 51, 0, 53, 0, 54, 0, 102, 0, 49, 0, 57, 0, 53, 0, 53, 0, 51, 0, 54, 0, 101, 0, 53, 0, 57, 0, 48, 0, 146, 197, 248, 185, 212, 19, 214, 85, 165, 169, 226, 123, 111, 175, 36, 125, 232, 11, 157, 149, 159, 59, 85, 94, 205, 149, 132, 235, 77, 85, 113, 234, 252, 191, 31, 138, 176, 171, 34, 177, 99, 108, 122, 127, 250, 60, 198, 101, 237, 238, 73, 109, 146, 56, 227, 101, 159, 141, 193, 102, 165, 82, 221, 233, 169, 55, 13, 102, 135, 162, 19, 133, 126, 147, 117, 254, 79, 128, 38, 251, 104, 60, 175, 40, 37, 73, 207, 66, 93, 25, 252, 150, 234, 122, 54, 166, 133, 208, 122, 221, 80, 139, 226, 186, 112, 158, 75, 154, 11, 61, 116, 18, 241, 187, 130, 251, 38, 222, 19, 179, 227, 115, 88, 194, 56, 28, 231, 94, 34, 153, 136, 26, 241, 109, 193, 150, 165, 91, 209, 210, 157, 196, 45, 171, 180, 10, 51, 130, 115, 100, 132, 54, 167, 192, 1, 41, 26, 99, 161, 206, 83, 172, 231, 44, 249, 232, 29, 25, 193, 12, 28, 133, 193, 7, 86, 78, 41, 151, 56, 13, 159, 8, 167, 226, 242, 31, 14, 51, 196, 36, 94, 109, 12, 181, 103, 126, 84, 208, 18, 134, 183, 74, 74, 209, 55, 40, 206, 187, 162, 159, 94, 208, 114, 188, 254, 25, 31, 79, 88, 126, 163, 167, 38, 245, 45, 217, 133, 149, 21, 141, 124, 34, 176, 39, 61, 177, 2, 124, 160, 138, 170, 65, 7, 61, 203, 40, 32, 57, 228, 172, 10, 193, 162, 30, 51, 121, 1, 185, 3, 43, 189, 28, 36, 109, 14, 153, 209, 17, 165, 201, 245, 18, 86, 215, 86, 104, 206, 109, 227, 78, 207, 14, 112, 148, 130, 136, 144, 115, 212, 4, 144, 194, 150, 234, 6, 53, 123, 51, 220, 126, 21, 75, 64, 186, 145, 208, 96, 176, 46, 249, 242, 10, 177, 18, 158, 131, 92, 76, 203, 28, 123, 218, 121, 112, 75, 215, 187, 226, 247, 116, 159, 244, 229, 30, 115, 206, 227, 175, 72, 80, 229, 117, 198, 184, 28, 35, 86, 185, 226, 192, 99, 178, 40, 153, 98, 155, 219, 43, 111, 190, 58, 183, 241, 234, 139, 155, 252, 109, 207, 237, 56, 222, 212, 163, 216, 35, 55, 57, 106, 60, 145, 102, 163, 132, 65, 128, 149, 48, 187, 174, 75, 62, 157, 31, 162, 38, 239, 43, 88, 140, 203, 221, 181, 244, 200, 182, 237, 36, 224, 241, 89, 40, 232, 107, 65, 64, 15, 164, 110, 21, 121, 183, 36, 200, 20, 223, 45, 238, 209, 43, 88, 123, 108, 252, 219, 75, 80, 197, 173, 244, 130, 193, 11, 96, 143, 7, 23, 250, 60, 21, 168, 69, 108, 168, 85, 8, 96, 78, 156, 122, 45, 202, 82, 180, 135, 200, 131, 220, 248, 42, 210, 234, 132, 100, 88, 80, 93, 212, 145, 253, 45, 117, 51, 163, 214, 134, 42, 167, 0, 120, 40, 165, 171, 114, 252, 151, 74, 0, 157, 190, 250, 132, 22, 141, 14, 146, 34, 155, 39, 103, 58, 226 };
            byte[] EncryptedKey2 = { 1, 206, 0, 0, 1, 104, 0, 116, 0, 116, 0, 112, 0, 115, 0, 58, 0, 47, 0, 47, 0, 106, 0, 101, 0, 116, 0, 114, 0, 105, 0, 109, 0, 109, 0, 101, 0, 45, 0, 107, 0, 101, 0, 121, 0, 45, 0, 118, 0, 97, 0, 117, 0, 108, 0, 116, 0, 46, 0, 118, 0, 97, 0, 117, 0, 108, 0, 116, 0, 46, 0, 97, 0, 122, 0, 117, 0, 114, 0, 101, 0, 46, 0, 110, 0, 101, 0, 116, 0, 47, 0, 107, 0, 101, 0, 121, 0, 115, 0, 47, 0, 97, 0, 108, 0, 119, 0, 97, 0, 121, 0, 115, 0, 45, 0, 101, 0, 110, 0, 99, 0, 114, 0, 121, 0, 112, 0, 116, 0, 101, 0, 100, 0, 45, 0, 97, 0, 117, 0, 116, 0, 111, 0, 49, 0, 47, 0, 97, 0, 55, 0, 100, 0, 53, 0, 99, 0, 57, 0, 56, 0, 57, 0, 100, 0, 53, 0, 97, 0, 48, 0, 52, 0, 50, 0, 51, 0, 102, 0, 56, 0, 100, 0, 51, 0, 53, 0, 54, 0, 102, 0, 49, 0, 57, 0, 53, 0, 53, 0, 51, 0, 54, 0, 101, 0, 53, 0, 57, 0, 48, 0, 146, 197, 248, 185, 212, 19, 214, 85, 165, 169, 226, 123, 111, 175, 36, 125, 232, 11, 157, 149, 159, 59, 85, 94, 205, 149, 132, 235, 77, 85, 113, 234, 252, 191, 31, 138, 176, 171, 34, 177, 99, 108, 122, 127, 250, 60, 198, 101, 237, 238, 73, 109, 146, 56, 227, 101, 159, 141, 193, 102, 165, 82, 221, 233, 169, 55, 13, 102, 135, 162, 19, 133, 126, 147, 117, 254, 79, 128, 38, 251, 104, 60, 175, 40, 37, 73, 207, 66, 93, 25, 252, 150, 234, 122, 54, 166, 133, 208, 122, 221, 80, 139, 226, 186, 112, 158, 75, 154, 11, 61, 116, 18, 241, 187, 130, 251, 38, 222, 19, 179, 227, 115, 88, 194, 56, 28, 231, 94, 34, 153, 136, 26, 241, 109, 193, 150, 165, 91, 209, 210, 157, 196, 45, 171, 180, 10, 51, 130, 115, 100, 132, 54, 167, 192, 1, 41, 26, 99, 161, 206, 83, 172, 231, 44, 249, 232, 29, 25, 193, 12, 28, 133, 193, 7, 86, 78, 41, 151, 56, 13, 159, 8, 167, 226, 242, 31, 14, 51, 196, 36, 94, 109, 12, 181, 103, 126, 84, 208, 18, 134, 183, 74, 74, 209, 55, 40, 206, 187, 162, 159, 94, 208, 114, 188, 254, 25, 31, 79, 88, 126, 163, 167, 38, 245, 45, 217, 133, 149, 21, 141, 124, 34, 176, 39, 61, 177, 2, 124, 160, 138, 170, 65, 7, 61, 203, 40, 32, 57, 228, 172, 10, 193, 162, 30, 51, 121, 1, 185, 3, 43, 189, 28, 36, 109, 14, 153, 209, 17, 165, 201, 245, 18, 86, 215, 86, 104, 206, 109, 227, 78, 207, 14, 112, 148, 130, 136, 144, 115, 212, 4, 144, 194, 150, 234, 6, 53, 123, 51, 220, 126, 21, 75, 64, 186, 145, 208, 96, 176, 46, 249, 242, 10, 177, 18, 158, 131, 92, 76, 203, 28, 123, 218, 121, 112, 75, 215, 187, 226, 247, 116, 159, 244, 229, 30, 115, 206, 227, 175, 72, 80, 229, 117, 198, 184, 28, 35, 86, 185, 226, 192, 99, 178, 40, 153, 98, 155, 219, 43, 111, 190, 58, 183, 241, 234, 139, 155, 252, 109, 207, 237, 56, 222, 212, 163, 216, 35, 55, 57, 106, 60, 145, 102, 163, 132, 65, 128, 149, 48, 187, 174, 75, 62, 157, 31, 162, 38, 239, 43, 88, 140, 203, 221, 181, 244, 200, 182, 237, 36, 224, 241, 89, 40, 232, 107, 65, 64, 15, 164, 110, 21, 121, 183, 36, 200, 20, 223, 45, 238, 209, 43, 88, 123, 108, 252, 219, 75, 80, 197, 173, 244, 130, 193, 11, 96, 143, 7, 23, 250, 60, 21, 168, 69, 108, 168, 85, 8, 96, 78, 156, 122, 45, 202, 82, 180, 135, 200, 131, 220, 248, 42, 210, 234, 132, 100, 88, 80, 93, 212, 145, 253, 45, 117, 51, 163, 214, 134, 42, 167, 0, 120, 40, 165, 171, 114, 252, 151, 74, 0, 157, 190, 250, 132, 22, 141, 14, 146, 34, 155, 39, 103, 58, 226 };

            DataEncryptionKey encryptionkey1 = ProtectedDataEncryptionKey.GetOrCreate("EK", masterKey1, EncryptedKey1);
            DataEncryptionKey encryptionkey2 = ProtectedDataEncryptionKey.GetOrCreate("EK", masterKey2, EncryptedKey1);

            Assert.Same(encryptionkey1, encryptionkey2);

            DataEncryptionKey encryptionkey3 = ProtectedDataEncryptionKey.GetOrCreate("EK", masterKey1, EncryptedKey1);
            DataEncryptionKey encryptionkey4 = ProtectedDataEncryptionKey.GetOrCreate("EK", masterKey3, EncryptedKey1);

            Assert.NotSame(encryptionkey3, encryptionkey4);

            DataEncryptionKey encryptionkey5 = ProtectedDataEncryptionKey.GetOrCreate("EK", masterKey1, EncryptedKey1);
            DataEncryptionKey encryptionkey6 = ProtectedDataEncryptionKey.GetOrCreate("Not_EK", masterKey1, EncryptedKey1);

            Assert.NotSame(encryptionkey5, encryptionkey6);

            DataEncryptionKey encryptionkey7 = ProtectedDataEncryptionKey.GetOrCreate("EK", masterKey1, EncryptedKey1);
            DataEncryptionKey encryptionkey8 = ProtectedDataEncryptionKey.GetOrCreate("EK", masterKey1, EncryptedKey2);

            Assert.Same(encryptionkey7, encryptionkey8);
        }
        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));
        }
        public void PerformHashCodeCorrectly()
        {
            DataEncryptionKey encryptionKey1 = new ProtectedDataEncryptionKey("CEK", keyEncryptionKey, encryptedDataEncryptionKey);
            DataEncryptionKey encryptionKey2 = new ProtectedDataEncryptionKey("CEK", keyEncryptionKey, encryptedDataEncryptionKey);

            Assert.Equal(encryptionKey1.GetHashCode(), encryptionKey2.GetHashCode());
        }
        public void PerformEqualityCorrectly()
        {
            DataEncryptionKey encryptionKey1 = new ProtectedDataEncryptionKey("CEK", keyEncryptionKey, encryptedDataEncryptionKey);
            DataEncryptionKey encryptionKey2 = new ProtectedDataEncryptionKey("CEK", keyEncryptionKey, encryptedDataEncryptionKey);

            Assert.Equal(encryptionKey1, encryptionKey2);
        }
        private async Task <ProtectedDataEncryptionKey> BuildProtectedDataEncryptionKeyAsync(
            ClientEncryptionKeyProperties clientEncryptionKeyProperties,
            string keyId,
            CancellationToken cancellationToken)
        {
            if (await EncryptionCosmosClient.EncryptionKeyCacheSemaphore.WaitAsync(-1, cancellationToken))
            {
                try
                {
                    KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate(
                        clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Name,
                        clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Value,
                        this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyStoreProviderImpl);

                    ProtectedDataEncryptionKey protectedDataEncryptionKey = ProtectedDataEncryptionKey.GetOrCreate(
                        keyId,
                        keyEncryptionKey,
                        clientEncryptionKeyProperties.WrappedDataEncryptionKey);

                    return(protectedDataEncryptionKey);
                }
                finally
                {
                    EncryptionCosmosClient.EncryptionKeyCacheSemaphore.Release(1);
                }
            }

            throw new InvalidOperationException("Failed to build ProtectedDataEncryptionKey. ");
        }
        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));
        }
        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 #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="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);
        }
        /// <summary>
        /// Helper function which force refreshes the gateway cache to fetch the latest client encryption key to build ProtectedDataEncryptionKey object for the encryption setting.
        /// </summary>
        /// <param name="existingCekEtag">Client encryption key etag to be passed, which is used as If-None-Match Etag for the request. </param>
        /// <param name="cancellationToken"> cacellation token. </param>
        /// <returns>ProtectedDataEncryptionKey object. </returns>
        private async Task <ProtectedDataEncryptionKey> ForceRefreshGatewayCacheAndBuildProtectedDataEncryptionKeyAsync(
            string existingCekEtag,
            Exception refreshRetriedOnException,
            CancellationToken cancellationToken)
        {
            ClientEncryptionKeyProperties clientEncryptionKeyProperties;

            try
            {
                // passing ifNoneMatchEtags results in request being sent out with IfNoneMatchEtag set in RequestOptions, this results in the Gateway cache getting force refreshed.
                // shouldForceRefresh is set to true so that we dont look up our client cache.
                clientEncryptionKeyProperties = await this.encryptionContainer.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync(
                    clientEncryptionKeyId : this.ClientEncryptionKeyId,
                    encryptionContainer : this.encryptionContainer,
                    databaseRid : this.databaseRid,
                    ifNoneMatchEtag : existingCekEtag,
                    shouldForceRefresh : true,
                    cancellationToken : cancellationToken);
            }
            catch (CosmosException ex)
            {
                // if there was a retry with ifNoneMatchEtags, the server will send back NotModified if the key resource has not been modified and is up to date.
                if (ex.StatusCode == HttpStatusCode.NotModified)
                {
                    // looks like the key was never rewrapped with a valid Key Encryption Key.
                    throw new EncryptionCosmosException(
                              $"The Client Encryption Key with key id:{this.ClientEncryptionKeyId} on database:{this.encryptionContainer.Database.Id} and container:{this.encryptionContainer.Id} , needs to be rewrapped with a valid Key Encryption Key using RewrapClientEncryptionKeyAsync. " +
                              $" The Key Encryption Key used to wrap the Client Encryption Key has been revoked: {refreshRetriedOnException.Message}. {ex.Message}." +
                              $" Please refer to https://aka.ms/CosmosClientEncryption for more details. ",
                              HttpStatusCode.BadRequest,
                              int.Parse(Constants.IncorrectContainerRidSubStatus),
                              ex.ActivityId,
                              ex.RequestCharge,
                              ex.Diagnostics);
                }
                else
                {
                    throw;
                }
            }

            ProtectedDataEncryptionKey protectedDataEncryptionKey = await this.BuildProtectedDataEncryptionKeyAsync(
                clientEncryptionKeyProperties,
                this.ClientEncryptionKeyId,
                cancellationToken);

            return(protectedDataEncryptionKey);
        }
Example #10
0
        internal ProtectedDataEncryptionKey BuildProtectedDataEncryptionKey(
            ClientEncryptionKeyProperties clientEncryptionKeyProperties,
            EncryptionKeyStoreProvider encryptionKeyStoreProvider,
            string keyId)
        {
            KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate(
                clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Name,
                clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Value,
                encryptionKeyStoreProvider);

            ProtectedDataEncryptionKey protectedDataEncryptionKey = ProtectedDataEncryptionKey.GetOrCreate(
                keyId,
                keyEncryptionKey,
                clientEncryptionKeyProperties.WrappedDataEncryptionKey);

            return(protectedDataEncryptionKey);
        }
        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);
        }
Example #12
0
        private (byte[], EncryptionKeyWrapMetadata) GenerateAndWrapPdekForMdeEncAlgo(EncryptionKeyWrapMetadata encryptionKeyWrapMetadata)
        {
            if (this.DekProvider.MdeKeyWrapProvider == null)
            {
                throw new InvalidOperationException($"For use of '{CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized}' algorithm, " +
                                                    "Encryptor or CosmosDataEncryptionKeyProvider needs to be initialized with EncryptionKeyStoreProvider.");
            }

            KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate(
                encryptionKeyWrapMetadata.Name,
                encryptionKeyWrapMetadata.Value,
                this.DekProvider.MdeKeyWrapProvider.EncryptionKeyStoreProvider);

            ProtectedDataEncryptionKey protectedDataEncryptionKey = new ProtectedDataEncryptionKey(
                encryptionKeyWrapMetadata.Name,
                keyEncryptionKey);

            byte[] wrappedDek = protectedDataEncryptionKey.EncryptedValue;
            EncryptionKeyWrapMetadata updatedMetadata = encryptionKeyWrapMetadata;

            return(wrappedDek, updatedMetadata);
        }
Example #13
0
        private async Task <CachedEncryptionSettings> FetchCachedEncryptionSettingsAsync(
            string propertyName,
            EncryptionProcessor encryptionProcessor,
            CancellationToken cancellationToken)
        {
            ClientEncryptionPolicy clientEncryptionPolicy = await encryptionProcessor.EncryptionCosmosClient.GetClientEncryptionPolicyAsync(
                encryptionProcessor.Container,
                cancellationToken,
                false);

            if (clientEncryptionPolicy != null)
            {
                foreach (ClientEncryptionIncludedPath propertyToEncrypt in clientEncryptionPolicy.IncludedPaths)
                {
                    if (string.Equals(propertyToEncrypt.Path.Substring(1), propertyName))
                    {
                        ClientEncryptionKeyProperties clientEncryptionKeyProperties = await encryptionProcessor.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync(
                            clientEncryptionKeyId : propertyToEncrypt.ClientEncryptionKeyId,
                            container : encryptionProcessor.Container,
                            cancellationToken : cancellationToken,
                            shouldForceRefresh : false);

                        ProtectedDataEncryptionKey protectedDataEncryptionKey = null;

                        try
                        {
                            protectedDataEncryptionKey = this.BuildProtectedDataEncryptionKey(
                                clientEncryptionKeyProperties,
                                encryptionProcessor.EncryptionKeyStoreProvider,
                                propertyToEncrypt.ClientEncryptionKeyId);
                        }
                        catch (RequestFailedException ex)
                        {
                            // the key was revoked. Try to fetch the latest EncryptionKeyProperties from the backend.
                            // This should succeed provided the user has rewraped the key with right set of meta data.
                            if (ex.Status == (int)HttpStatusCode.Forbidden)
                            {
                                clientEncryptionKeyProperties = await encryptionProcessor.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync(
                                    clientEncryptionKeyId : propertyToEncrypt.ClientEncryptionKeyId,
                                    container : encryptionProcessor.Container,
                                    cancellationToken : cancellationToken,
                                    shouldForceRefresh : true);

                                protectedDataEncryptionKey = this.BuildProtectedDataEncryptionKey(
                                    clientEncryptionKeyProperties,
                                    encryptionProcessor.EncryptionKeyStoreProvider,
                                    propertyToEncrypt.ClientEncryptionKeyId);
                            }
                            else
                            {
                                throw;
                            }
                        }

                        EncryptionSettings encryptionSettings = new EncryptionSettings
                        {
                            EncryptionSettingTimeToLive = DateTime.UtcNow + TimeSpan.FromMinutes(Constants.CachedEncryptionSettingsDefaultTTLInMinutes),
                            ClientEncryptionKeyId       = propertyToEncrypt.ClientEncryptionKeyId,
                            DataEncryptionKey           = protectedDataEncryptionKey,
                        };

                        EncryptionType encryptionType = EncryptionType.Plaintext;
                        switch (propertyToEncrypt.EncryptionType)
                        {
                        case CosmosEncryptionType.Deterministic:
                            encryptionType = EncryptionType.Deterministic;
                            break;

                        case CosmosEncryptionType.Randomized:
                            encryptionType = EncryptionType.Randomized;
                            break;

                        case CosmosEncryptionType.Plaintext:
                            encryptionType = EncryptionType.Plaintext;
                            break;

                        default:
                            throw new ArgumentException($"Invalid encryption type {propertyToEncrypt.EncryptionType}. Please refer to https://aka.ms/CosmosClientEncryption for more details. ");
                        }

                        encryptionSettings = EncryptionSettings.Create(encryptionSettings, encryptionType);
                        return(new CachedEncryptionSettings(encryptionSettings, encryptionSettings.EncryptionSettingTimeToLive));
                    }
                }
            }

            return(null);
        }
        /// <summary>
        /// Builds up and caches the Encryption Setting by getting the cached entries of Client Encryption Policy and the corresponding keys.
        /// Sets up the MDE Algorithm for encryption and decryption by initializing the KeyEncryptionKey and ProtectedDataEncryptionKey.
        /// </summary>
        /// <param name="cancellationToken"> cancellation token </param>
        /// <returns> Task </returns>
        internal async Task InitializeEncryptionSettingsAsync(CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            if (this.isEncryptionSettingsInitDone)
            {
                throw new InvalidOperationException("The Encrypton Processor has already been initialized. ");
            }

            // fetch the cached policy.
            this.ClientEncryptionPolicy = await this.EncryptionCosmosClient.GetClientEncryptionPolicyAsync(
                container : this.Container,
                cancellationToken : cancellationToken,
                shouldForceRefresh : false);

            // no policy was configured.
            if (this.ClientEncryptionPolicy == null)
            {
                this.isEncryptionSettingsInitDone = true;
                return;
            }

            Dictionary <string, EncryptionSettings> settingsByDekId = new Dictionary <string, EncryptionSettings>();

            // update the property level setting.
            foreach (ClientEncryptionIncludedPath propertyToEncrypt in this.ClientEncryptionPolicy.IncludedPaths)
            {
                if (!settingsByDekId.ContainsKey(propertyToEncrypt.ClientEncryptionKeyId))
                {
                    string clientEncryptionKeyId = propertyToEncrypt.ClientEncryptionKeyId;

                    ClientEncryptionKeyProperties clientEncryptionKeyProperties = await this.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync(
                        clientEncryptionKeyId : clientEncryptionKeyId,
                        container : this.Container,
                        cancellationToken : cancellationToken,
                        shouldForceRefresh : false);

                    ProtectedDataEncryptionKey protectedDataEncryptionKey = null;

                    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.EncryptionSettings.BuildProtectedDataEncryptionKey(
                            clientEncryptionKeyProperties,
                            this.EncryptionKeyStoreProvider,
                            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.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync(
                                clientEncryptionKeyId : clientEncryptionKeyId,
                                container : this.Container,
                                cancellationToken : cancellationToken,
                                shouldForceRefresh : true);

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

                    settingsByDekId[clientEncryptionKeyId] = new EncryptionSettings
                    {
                        // we cache the setting for performance reason.
                        EncryptionSettingTimeToLive = DateTime.UtcNow + TimeSpan.FromMinutes(Constants.CachedEncryptionSettingsDefaultTTLInMinutes),
                        ClientEncryptionKeyId       = clientEncryptionKeyId,
                        DataEncryptionKey           = protectedDataEncryptionKey,
                    };
                }

                EncryptionType encryptionType = EncryptionType.Plaintext;
                switch (propertyToEncrypt.EncryptionType)
                {
                case CosmosEncryptionType.Deterministic:
                    encryptionType = EncryptionType.Deterministic;
                    break;

                case CosmosEncryptionType.Randomized:
                    encryptionType = EncryptionType.Randomized;
                    break;

                case CosmosEncryptionType.Plaintext:
                    encryptionType = EncryptionType.Plaintext;
                    break;

                default:
                    throw new ArgumentException($"Invalid encryption type {propertyToEncrypt.EncryptionType}. Please refer to https://aka.ms/CosmosClientEncryption for more details. ");
                }

                string propertyName = propertyToEncrypt.Path.Substring(1);

                this.EncryptionSettings.SetEncryptionSettingForProperty(
                    propertyName,
                    EncryptionSettings.Create(
                        settingsByDekId[propertyToEncrypt.ClientEncryptionKeyId],
                        encryptionType),
                    settingsByDekId[propertyToEncrypt.ClientEncryptionKeyId].EncryptionSettingTimeToLive);
            }

            this.isEncryptionSettingsInitDone = true;
        }
Example #15
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FileEncryptionSettings{T}"/> class.
 /// </summary>
 /// <param name="dataEncryptionKey">An encryption key is used to encrypt and decrypt data.</param>
 /// <param name="encryptionType">The type of encryption.</param>
 /// <param name="serializer">A serializer is used for serializing and deserializing data objects to and from an array of bytes.</param>
 public FileEncryptionSettings(ProtectedDataEncryptionKey dataEncryptionKey, EncryptionType encryptionType, Serializer <T> serializer)
 {
     DataEncryptionKey = dataEncryptionKey;
     EncryptionType    = encryptionType;
     Serializer        = serializer;
 }
Example #16
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FileEncryptionSettings{T}"/> class.
 /// </summary>
 /// <param name="dataEncryptionKey">An encryption key is used to encrypt and decrypt data.</param>
 /// <param name="serializer">A serializer is used for serializing and deserializing data objects to and from an array of bytes.</param>
 public FileEncryptionSettings(ProtectedDataEncryptionKey dataEncryptionKey, Serializer <T> serializer)
     : this(dataEncryptionKey, GetDefaultEncryptionType(dataEncryptionKey), serializer)
 {
 }
Example #17
0
        /// <summary>
        /// Create a Client Encryption Key used to Encrypt data.
        /// </summary>
        /// <param name="database">Regular cosmos database.</param>
        /// <param name="clientEncryptionKeyId"> Client Encryption Key id.</param>
        /// <param name="dataEncryptionKeyAlgorithm"> Encryption Algorthm. </param>
        /// <param name="encryptionKeyWrapMetadata"> EncryptionKeyWrapMetadata.</param>
        /// <param name="cancellationToken"> cancellation token </param>
        /// <returns>Container to perform operations supporting client-side encryption / decryption.</returns>
        /// <example>
        /// This example shows how to create a new Client Encryption Key.
        ///
        /// <code language="c#">
        /// <![CDATA[
        /// ClientEncryptionKeyResponse response = await this.cosmosDatabase.CreateClientEncryptionKeyAsync(
        ///     "testKey",
        ///     DataEncryptionKeyAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256,
        ///     new EncryptionKeyWrapMetadata("metadataName", "MetadataValue"));
        /// ]]>
        /// </code>
        /// </example>
        public static async Task <ClientEncryptionKeyResponse> CreateClientEncryptionKeyAsync(
            this Database database,
            string clientEncryptionKeyId,
            DataEncryptionKeyAlgorithm dataEncryptionKeyAlgorithm,
            EncryptionKeyWrapMetadata encryptionKeyWrapMetadata,
            CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

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

            string encryptionAlgorithm = dataEncryptionKeyAlgorithm.ToString();

            if (!string.Equals(encryptionAlgorithm, DataEncryptionKeyAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.ToString()))
            {
                throw new ArgumentException($"Invalid Encryption Algorithm '{encryptionAlgorithm}' passed. Please refer to https://aka.ms/CosmosClientEncryption for more details. ");
            }

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

            EncryptionCosmosClient encryptionCosmosClient;

            if (database is EncryptionDatabase encryptionDatabase)
            {
                encryptionCosmosClient = encryptionDatabase.EncryptionCosmosClient;
            }
            else
            {
                throw new ArgumentException("Creating a ClientEncryptionKey resource requires the use of an encryption - enabled client. Please refer to https://aka.ms/CosmosClientEncryption for more details. ");
            }

            EncryptionKeyStoreProvider encryptionKeyStoreProvider = encryptionCosmosClient.EncryptionKeyStoreProvider;

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

            ProtectedDataEncryptionKey protectedDataEncryptionKey = new ProtectedDataEncryptionKey(
                clientEncryptionKeyId,
                keyEncryptionKey);

            byte[] wrappedDataEncryptionKey = protectedDataEncryptionKey.EncryptedValue;

            ClientEncryptionKeyProperties clientEncryptionKeyProperties = new ClientEncryptionKeyProperties(
                clientEncryptionKeyId,
                encryptionAlgorithm,
                wrappedDataEncryptionKey,
                encryptionKeyWrapMetadata);

            ClientEncryptionKeyResponse clientEncryptionKeyResponse = await database.CreateClientEncryptionKeyAsync(
                clientEncryptionKeyProperties,
                cancellationToken : cancellationToken);

            return(clientEncryptionKeyResponse);
        }
Example #18
0
        /// <summary>
        /// Creates a client encryption key.
        /// This generates a cryptographically random data encryption key, wraps it using
        /// information provided in the encryptionKeyWrapMetadata using the IKeyEncryptionKeyResolver instance configured on the client,
        /// and saves the wrapped data encryption key along with the encryptionKeyWrapMetadata at the Cosmos DB service.
        /// </summary>
        /// <param name="database">Database supporting encryption in which the client encryption key properties will be saved.</param>
        /// <param name="clientEncryptionKeyId">Identifier for the client encryption key.</param>
        /// <param name="encryptionAlgorithm">Algorithm which will be used for encryption with this key.</param>
        /// <param name="encryptionKeyWrapMetadata">Metadata used to wrap the data encryption key with a key encryption key.</param>
        /// <param name="cancellationToken">Token for request cancellation.</param>
        /// <returns>Response from the Cosmos DB service with <see cref="ClientEncryptionKeyProperties"/>.</returns>
        /// <example>
        /// This example shows how to create a client encryption key.
        ///
        /// <code language="c#">
        /// <![CDATA[
        /// Azure.Core.TokenCredential tokenCredential = new Azure.Identity.DefaultAzureCredential();
        /// Azure.Core.Cryptography.IKeyEncryptionKeyResolver keyResolver = new Azure.Security.KeyVault.Keys.Cryptography.KeyResolver(tokenCredential);
        /// CosmosClient client = (new CosmosClient(endpoint, authKey)).WithEncryption(keyResolver, KeyEncryptionKeyResolverName.AzureKeyVault);
        ///
        /// EncryptionKeyWrapMetadata wrapMetadata = new EncryptionKeyWrapMetadata(
        ///    type: KeyEncryptionKeyResolverName.AzureKeyVault,
        ///    name: "myKek",
        ///    value: "https://contoso.vault.azure.net/keys/myKek/78deebed173b48e48f55abf87ed4cf71",
        ///    algorithm: Azure.Security.KeyVault.Keys.Cryptography.EncryptionAlgorithm.RsaOaep.ToString());
        ///
        ///  ClientEncryptionKeyResponse response = await client.GetDatabase("databaseId").CreateClientEncryptionKeyAsync(
        ///    "myCek",
        ///    DataEncryptionAlgorithm.AeadAes256CbcHmacSha256,
        ///    wrapMetadata);
        /// ]]>
        /// </code>
        /// </example>
        /// <remarks>
        /// See <see href="https://aka.ms/CosmosClientEncryption">client-side encryption documentation</see> for more details.
        /// </remarks>
        public static async Task <ClientEncryptionKeyResponse> CreateClientEncryptionKeyAsync(
            this Database database,
            string clientEncryptionKeyId,
            string encryptionAlgorithm,
            EncryptionKeyWrapMetadata encryptionKeyWrapMetadata,
            CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

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

            if (!string.Equals(encryptionAlgorithm, DataEncryptionAlgorithm.AeadAes256CbcHmacSha256))
            {
                throw new ArgumentException($"Invalid encryption algorithm '{encryptionAlgorithm}' passed. Please refer to https://aka.ms/CosmosClientEncryption for more details.");
            }

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

            if (encryptionKeyWrapMetadata.Algorithm != EncryptionKeyStoreProviderImpl.RsaOaepWrapAlgorithm)
            {
                throw new ArgumentException($"Invalid key wrap algorithm '{encryptionKeyWrapMetadata.Algorithm}' passed. Please refer to https://aka.ms/CosmosClientEncryption for more details.");
            }

            EncryptionCosmosClient encryptionCosmosClient = database is EncryptionDatabase encryptionDatabase
                ? encryptionDatabase.EncryptionCosmosClient
                : throw new ArgumentException("Creating a client encryption key requires the use of an encryption-enabled client. Please refer to https://aka.ms/CosmosClientEncryption for more details.");

            if (!string.Equals(encryptionKeyWrapMetadata.Type, encryptionCosmosClient.KeyEncryptionKeyResolverName))
            {
                throw new ArgumentException($"The Type of the EncryptionKeyWrapMetadata '{encryptionKeyWrapMetadata.Type}' does not match"
                                            + $" with the keyEncryptionKeyResolverName '{encryptionCosmosClient.KeyEncryptionKeyResolverName}' configured."
                                            + " Please refer to https://aka.ms/CosmosClientEncryption for more details.");
            }

            KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate(
                encryptionKeyWrapMetadata.Name,
                encryptionKeyWrapMetadata.Value,
                encryptionCosmosClient.EncryptionKeyStoreProviderImpl);

            ProtectedDataEncryptionKey protectedDataEncryptionKey = new ProtectedDataEncryptionKey(
                clientEncryptionKeyId,
                keyEncryptionKey);

            byte[] wrappedDataEncryptionKey = protectedDataEncryptionKey.EncryptedValue;

            // cache it.
            ProtectedDataEncryptionKey.GetOrCreate(
                clientEncryptionKeyId,
                keyEncryptionKey,
                wrappedDataEncryptionKey);

            ClientEncryptionKeyProperties clientEncryptionKeyProperties = new ClientEncryptionKeyProperties(
                clientEncryptionKeyId,
                encryptionAlgorithm,
                wrappedDataEncryptionKey,
                encryptionKeyWrapMetadata);

            ClientEncryptionKeyResponse clientEncryptionKeyResponse = await database.CreateClientEncryptionKeyAsync(
                clientEncryptionKeyProperties,
                cancellationToken : cancellationToken);

            return(clientEncryptionKeyResponse);
        }