Beispiel #1
0
        internal async Task <InMemoryRawDek> FetchUnwrappedAsync(
            DataEncryptionKeyProperties dekProperties,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            try
            {
                if (string.Equals(dekProperties.EncryptionAlgorithm, CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized))
                {
                    DataEncryptionKey dek = this.InitMdeEncryptionAlgorithm(dekProperties);

                    // TTL is not used since DEK is not cached.
                    return(new InMemoryRawDek(dek, TimeSpan.FromMilliseconds(0)));
                }

                return(await this.DekProvider.DekCache.GetOrAddRawDekAsync(
                           dekProperties,
                           this.UnwrapAsync,
                           diagnosticsContext,
                           cancellationToken));
            }
            catch (Exception exception)
            {
                throw EncryptionExceptionFactory.EncryptionKeyNotFoundException(
                          $"Failed to unwrap Data Encryption Key with id: '{dekProperties.Id}'.",
                          exception);
            }
        }
Beispiel #2
0
        internal async Task <DataEncryptionKey> FetchUnWrappedLegacySupportedMdeDekAsync(
            DataEncryptionKeyProperties dekProperties,
            string encryptionAlgorithm,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            EncryptionKeyUnwrapResult unwrapResult;

            if (this.DekProvider.EncryptionKeyStoreProvider == null)
            {
                throw new InvalidOperationException($"For use of '{CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized}' algorithm based DEK, " +
                                                    "Encryptor or CosmosDataEncryptionKeyProvider needs to be initialized with EncryptionKeyStoreProvider.");
            }

            try
            {
                using (diagnosticsContext.CreateScope("UnwrapDataEncryptionKey"))
                {
                    unwrapResult = await this.UnWrapDekMdeEncAlgoAsync(
                        dekProperties,
                        diagnosticsContext,
                        cancellationToken);
                }

                return(DataEncryptionKey.Create(
                           unwrapResult.DataEncryptionKey,
                           encryptionAlgorithm));
            }
            catch (Exception exception)
            {
                throw EncryptionExceptionFactory.EncryptionKeyNotFoundException(
                          $"Failed to unwrap Data Encryption Key with id: '{dekProperties.Id}'.",
                          exception);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Decryption steps
        /// 1. Validate version byte
        /// 2. (optional) Validate Authentication tag
        /// 3. Decrypt the message
        /// </summary>
        protected byte[] DecryptData(byte[] cipherText, bool hasAuthenticationTag)
        {
            Debug.Assert(cipherText != null);

            byte[] iv = new byte[BlockSizeInBytes];

            int minimumCipherTextLength = hasAuthenticationTag ? MinimumCipherTextLengthInBytesWithAuthenticationTag : MinimumCipherTextLengthInBytesNoAuthenticationTag;

            if (cipherText.Length < minimumCipherTextLength)
            {
                throw EncryptionExceptionFactory.InvalidCipherTextSize(cipherText.Length, minimumCipherTextLength);
            }

            // Validate the version byte
            int startIndex = 0;

            if (cipherText[startIndex] != this.algorithmVersion)
            {
                // Cipher text was computed with a different algorithm version than this.
                throw EncryptionExceptionFactory.InvalidAlgorithmVersion(cipherText[startIndex], this.algorithmVersion);
            }

            startIndex += 1;
            int authenticationTagOffset = 0;

            // Read authentication tag
            if (hasAuthenticationTag)
            {
                authenticationTagOffset = startIndex;
                startIndex += KeySizeInBytes; // authentication tag size is KeySizeInBytes
            }

            // Read cell IV
            Buffer.BlockCopy(cipherText, startIndex, iv, 0, iv.Length);
            startIndex += iv.Length;

            // Read encrypted text
            int cipherTextOffset = startIndex;
            int cipherTextCount  = cipherText.Length - startIndex;

            if (hasAuthenticationTag)
            {
                // Compute authentication tag
                byte[] authenticationTag = this.PrepareAuthenticationTag(iv, cipherText, cipherTextOffset, cipherTextCount);
                if (!SecurityUtility.CompareBytes(authenticationTag, cipherText, authenticationTagOffset, authenticationTag.Length))
                {
                    // Potentially tampered data, throw an exception
                    throw EncryptionExceptionFactory.InvalidAuthenticationTag();
                }
            }

            // Decrypt the text and return
            return(this.DecryptData(iv, cipherText, cipherTextOffset, cipherTextCount));
        }
        /// <summary>
        /// Derives all the required keys from the given root key
        /// </summary>
        internal AeadAes256CbcHmac256EncryptionKey(byte[] rootKey, string algorithmName)
            : base(rootKey)
        {
            this.algorithmName = algorithmName;

            int keySizeInBytes = KeySize / 8;

            // Key validation
            if (rootKey.Length != keySizeInBytes)
            {
                throw EncryptionExceptionFactory.InvalidKeySize(
                          this.algorithmName,
                          rootKey.Length,
                          keySizeInBytes);
            }

            // Derive keys from the root key
            //
            // Derive encryption key
            string encryptionKeySalt = string.Format(
                EncryptionKeySaltFormat,
                this.algorithmName,
                KeySize);

            byte[] buff1 = new byte[keySizeInBytes];
            SecurityUtility.GetHMACWithSHA256(Encoding.Unicode.GetBytes(encryptionKeySalt), this.RootKey, buff1);
            this.encryptionKey = new SymmetricKey(buff1);

            // Derive mac key
            string macKeySalt = string.Format(MacKeySaltFormat, this.algorithmName, KeySize);

            byte[] buff2 = new byte[keySizeInBytes];
            SecurityUtility.GetHMACWithSHA256(Encoding.Unicode.GetBytes(macKeySalt), this.RootKey, buff2);
            this.macKey = new SymmetricKey(buff2);

            // Derive iv key
            string ivKeySalt = string.Format(IvKeySaltFormat, this.algorithmName, KeySize);

            byte[] buff3 = new byte[keySizeInBytes];
            SecurityUtility.GetHMACWithSHA256(Encoding.Unicode.GetBytes(ivKeySalt), this.RootKey, buff3);
            this.ivKey = new SymmetricKey(buff3);
        }
Beispiel #5
0
        internal async Task <DataEncryptionKeyProperties> FetchDataEncryptionKeyPropertiesAsync(
            string id,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            try
            {
                DataEncryptionKeyProperties dekProperties = await this.DekProvider.DekCache.GetOrAddDekPropertiesAsync(
                    id,
                    this.ReadResourceAsync,
                    diagnosticsContext,
                    cancellationToken);

                return(dekProperties);
            }
            catch (CosmosException exception)
            {
                throw EncryptionExceptionFactory.EncryptionKeyNotFoundException(
                          $"Failed to retrieve Data Encryption Key with id: '{id}'.",
                          exception);
            }
        }
Beispiel #6
0
        /// <summary>
        /// For providing support to Encrypt/Decrypt items using Legacy DEK with MDE based algorithm.
        /// UnWrap using Legacy Key Provider and Init MDE Encryption Algorithm with Unwrapped Key.
        /// </summary>
        /// <param name="dekProperties"> DEK Properties </param>
        /// <param name="cancellationToken"> Cancellation Token </param>
        /// <returns> Data Encryption Key </returns>
        internal async Task <DataEncryptionKey> FetchUnWrappedMdeSupportedLegacyDekAsync(
            DataEncryptionKeyProperties dekProperties,
            CancellationToken cancellationToken)
        {
            if (this.DekProvider.EncryptionKeyWrapProvider == null)
            {
                throw new InvalidOperationException($"For use of '{CosmosEncryptionAlgorithm.AEAes256CbcHmacSha256Randomized}' algorithm based DEK, " +
                                                    "Encryptor or CosmosDataEncryptionKeyProvider needs to be initialized with EncryptionKeyWrapProvider.");
            }

            EncryptionKeyUnwrapResult unwrapResult;

            try
            {
                // unwrap with original wrap provider
                unwrapResult = await this.DekProvider.EncryptionKeyWrapProvider.UnwrapKeyAsync(
                    dekProperties.WrappedDataEncryptionKey,
                    dekProperties.EncryptionKeyWrapMetadata,
                    cancellationToken);
            }
            catch (Exception exception)
            {
                throw EncryptionExceptionFactory.EncryptionKeyNotFoundException(
                          $"Failed to unwrap Data Encryption Key with id: '{dekProperties.Id}'.",
                          exception);
            }

            // Init PlainDataEncryptionKey and then Init MDE Algorithm using PlaintextDataEncryptionKey.
            // PlaintextDataEncryptionKey derives DataEncryptionkey to Init a Raw Root Key received via Legacy WrapProvider Unwrap result.
            PlaintextDataEncryptionKey plaintextDataEncryptionKey = new PlaintextDataEncryptionKey(
                dekProperties.EncryptionKeyWrapMetadata.GetName(dekProperties.EncryptionKeyWrapMetadata),
                unwrapResult.DataEncryptionKey);

            return(new MdeEncryptionAlgorithm(
                       plaintextDataEncryptionKey,
                       Data.Encryption.Cryptography.EncryptionType.Randomized));
        }